Add Clang format.

Reformats the entire codebase. Better to do it now than later.

Adds .clang-format and a convenience script format_all.sh which formats
everything automatically.
This commit is contained in:
Hans-Kristian Arntzen 2016-05-05 09:33:18 +02:00
parent 9d4b5c0c59
commit 4b8ed53974
18 changed files with 8908 additions and 8351 deletions

164
.clang-format Executable file
View File

@ -0,0 +1,164 @@
# The style used for all options not specifically set in the configuration.
BasedOnStyle: LLVM
# The extra indent or outdent of access modifiers, e.g. public:.
AccessModifierOffset: -4
# If true, aligns escaped newlines as far left as possible. Otherwise puts them into the right-most column.
AlignEscapedNewlinesLeft: true
# If true, aligns trailing comments.
AlignTrailingComments: false
# Allow putting all parameters of a function declaration onto the next line even if BinPackParameters is false.
AllowAllParametersOfDeclarationOnNextLine: false
# Allows contracting simple braced statements to a single line.
AllowShortBlocksOnASingleLine: false
# If true, short case labels will be contracted to a single line.
AllowShortCaseLabelsOnASingleLine: false
# Dependent on the value, int f() { return 0; } can be put on a single line. Possible values: None, Inline, All.
AllowShortFunctionsOnASingleLine: None
# If true, if (a) return; can be put on a single line.
AllowShortIfStatementsOnASingleLine: false
# If true, while (true) continue; can be put on a single line.
AllowShortLoopsOnASingleLine: false
# If true, always break after function definition return types.
AlwaysBreakAfterDefinitionReturnType: false
# If true, always break before multiline string literals.
AlwaysBreakBeforeMultilineStrings: false
# If true, always break after the template<...> of a template declaration.
AlwaysBreakTemplateDeclarations: true
# If false, a function call's arguments will either be all on the same line or will have one line each.
BinPackArguments: true
# If false, a function declaration's or function definition's parameters will either all be on the same line
# or will have one line each.
BinPackParameters: true
# The way to wrap binary operators. Possible values: None, NonAssignment, All.
BreakBeforeBinaryOperators: None
# The brace breaking style to use. Possible values: Attach, Linux, Stroustrup, Allman, GNU.
BreakBeforeBraces: Allman
# If true, ternary operators will be placed after line breaks.
BreakBeforeTernaryOperators: false
# Always break constructor initializers before commas and align the commas with the colon.
BreakConstructorInitializersBeforeComma: true
# The column limit. A column limit of 0 means that there is no column limit.
ColumnLimit: 120
# A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed.
CommentPragmas: '^ *'
# If the constructor initializers don't fit on a line, put each initializer on its own line.
ConstructorInitializerAllOnOneLineOrOnePerLine: false
# The number of characters to use for indentation of constructor initializer lists.
ConstructorInitializerIndentWidth: 4
# Indent width for line continuations.
ContinuationIndentWidth: 4
# If true, format braced lists as best suited for C++11 braced lists.
Cpp11BracedListStyle: false
# Disables formatting at all.
DisableFormat: false
# A vector of macros that should be interpreted as foreach loops instead of as function calls.
#ForEachMacros: ''
# Indent case labels one level from the switch statement.
# When false, use the same indentation level as for the switch statement.
# Switch statement body is always indented one level more than case labels.
IndentCaseLabels: false
# The number of columns to use for indentation.
IndentWidth: 4
# Indent if a function definition or declaration is wrapped after the type.
IndentWrappedFunctionNames: false
# If true, empty lines at the start of blocks are kept.
KeepEmptyLinesAtTheStartOfBlocks: true
# Language, this format style is targeted at. Possible values: None, Cpp, Java, JavaScript, Proto.
Language: Cpp
# The maximum number of consecutive empty lines to keep.
MaxEmptyLinesToKeep: 1
# The indentation used for namespaces. Possible values: None, Inner, All.
NamespaceIndentation: None
# The penalty for breaking a function call after "call(".
PenaltyBreakBeforeFirstCallParameter: 19
# The penalty for each line break introduced inside a comment.
PenaltyBreakComment: 300
# The penalty for breaking before the first <<.
PenaltyBreakFirstLessLess: 120
# The penalty for each line break introduced inside a string literal.
PenaltyBreakString: 1000
# The penalty for each character outside of the column limit.
PenaltyExcessCharacter: 1000000
# Penalty for putting the return type of a function onto its own line.
PenaltyReturnTypeOnItsOwnLine: 1000000000
# Pointer and reference alignment style. Possible values: Left, Right, Middle.
PointerAlignment: Right
# If true, a space may be inserted after C style casts.
SpaceAfterCStyleCast: false
# If false, spaces will be removed before assignment operators.
SpaceBeforeAssignmentOperators: true
# Defines in which cases to put a space before opening parentheses. Possible values: Never, ControlStatements, Always.
SpaceBeforeParens: ControlStatements
# If true, spaces may be inserted into '()'.
SpaceInEmptyParentheses: false
# The number of spaces before trailing line comments (// - comments).
SpacesBeforeTrailingComments: 1
# If true, spaces will be inserted after '<' and before '>' in template argument lists.
SpacesInAngles: false
# If true, spaces may be inserted into C style casts.
SpacesInCStyleCastParentheses: false
# If true, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals).
SpacesInContainerLiterals: false
# If true, spaces will be inserted after '(' and before ')'.
SpacesInParentheses: false
# If true, spaces will be inserted after '[' and befor']'.
SpacesInSquareBrackets: false
# Format compatible with this standard, e.g. use A<A<int> > instead of A<A<int>> for LS_Cpp03. Possible values: Cpp03, Cpp11, Auto.
Standard: Cpp11
# The number of columns used for tab stops.
TabWidth: 4
# The way to use tab characters in the resulting file. Possible values: Never, ForIndentation, Always.
UseTab: ForIndentation

View File

@ -136,6 +136,11 @@ When adding support for new features to SPIRV-Cross, a new shader and reference
Contributors of new files should add a copyright header at the top of every new source code file with their copyright
along with the Apache 2.0 licensing stub.
### Formatting
SPIRV-Cross uses clang-format to automatically format code.
Please use clang-format with the style sheet found in `.clang-format` to automatically format code before submitting a pull request.
## ABI concerns
### SPIR-V headers

7
format_all.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
for file in spirv_*.{cpp,hpp} include/spirv_cross/*.{hpp,h}
do
echo "Formatting file: $file ..."
clang-format -style=file -i $file
done

View File

@ -22,58 +22,58 @@
namespace spirv_cross
{
class Barrier
{
public:
Barrier()
{
count.store(0);
iteration.store(0);
}
class Barrier
{
public:
Barrier()
{
count.store(0);
iteration.store(0);
}
void set_release_divisor(unsigned divisor)
{
this->divisor = divisor;
}
void set_release_divisor(unsigned divisor)
{
this->divisor = divisor;
}
static inline void memoryBarrier()
{
std::atomic_thread_fence(std::memory_order_seq_cst);
}
static inline void memoryBarrier()
{
std::atomic_thread_fence(std::memory_order_seq_cst);
}
void reset_counter()
{
count.store(0);
iteration.store(0);
}
void reset_counter()
{
count.store(0);
iteration.store(0);
}
void wait()
{
unsigned target_iteration = iteration.load(std::memory_order_relaxed) + 1;
// Overflows cleanly.
unsigned target_count = divisor * target_iteration;
void wait()
{
unsigned target_iteration = iteration.load(std::memory_order_relaxed) + 1;
// Overflows cleanly.
unsigned target_count = divisor * target_iteration;
// Barriers don't enforce memory ordering.
// Be as relaxed about the barrier as we possibly can!
unsigned c = count.fetch_add(1u, std::memory_order_relaxed);
// Barriers don't enforce memory ordering.
// Be as relaxed about the barrier as we possibly can!
unsigned c = count.fetch_add(1u, std::memory_order_relaxed);
if (c + 1 == target_count)
{
iteration.store(target_iteration, std::memory_order_relaxed);
}
else
{
// If we have more threads than the CPU, don't hog the CPU for very long periods of time.
while (iteration.load(std::memory_order_relaxed) != target_iteration)
std::this_thread::yield();
}
}
if (c + 1 == target_count)
{
iteration.store(target_iteration, std::memory_order_relaxed);
}
else
{
// If we have more threads than the CPU, don't hog the CPU for very long periods of time.
while (iteration.load(std::memory_order_relaxed) != target_iteration)
std::this_thread::yield();
}
}
private:
unsigned divisor = 1;
std::atomic<unsigned> count;
std::atomic<unsigned> iteration;
};
private:
unsigned divisor = 1;
std::atomic<unsigned> count;
std::atomic<unsigned> iteration;
};
}
#endif

View File

@ -27,42 +27,33 @@ typedef struct spirv_cross_shader spirv_cross_shader_t;
struct spirv_cross_interface
{
spirv_cross_shader_t* (*construct)(void);
void (*destruct)(spirv_cross_shader_t *thiz);
void (*invoke)(spirv_cross_shader_t *thiz);
spirv_cross_shader_t *(*construct)(void);
void (*destruct)(spirv_cross_shader_t *thiz);
void (*invoke)(spirv_cross_shader_t *thiz);
};
void spirv_cross_set_stage_input(spirv_cross_shader_t *thiz,
unsigned location, void *data, size_t size);
void spirv_cross_set_stage_input(spirv_cross_shader_t *thiz, unsigned location, void *data, size_t size);
void spirv_cross_set_stage_output(spirv_cross_shader_t *thiz,
unsigned location, void *data, size_t size);
void spirv_cross_set_stage_output(spirv_cross_shader_t *thiz, unsigned location, void *data, size_t size);
void spirv_cross_set_push_constant(spirv_cross_shader_t *thiz,
void *data, size_t size);
void spirv_cross_set_push_constant(spirv_cross_shader_t *thiz, void *data, size_t size);
void spirv_cross_set_uniform_constant(spirv_cross_shader_t *thiz,
unsigned location,
void *data, size_t size);
void spirv_cross_set_uniform_constant(spirv_cross_shader_t *thiz, unsigned location, void *data, size_t size);
void spirv_cross_set_resource(spirv_cross_shader_t *thiz,
unsigned set, unsigned binding,
void **data, size_t size);
void spirv_cross_set_resource(spirv_cross_shader_t *thiz, unsigned set, unsigned binding, void **data, size_t size);
const struct spirv_cross_interface* spirv_cross_get_interface(void);
const struct spirv_cross_interface *spirv_cross_get_interface(void);
typedef enum spirv_cross_builtin
{
SPIRV_CROSS_BUILTIN_POSITION = 0,
SPIRV_CROSS_BUILTIN_FRAG_COORD = 1,
SPIRV_CROSS_BUILTIN_WORK_GROUP_ID = 2,
SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS = 3,
SPIRV_CROSS_NUM_BUILTINS
SPIRV_CROSS_BUILTIN_POSITION = 0,
SPIRV_CROSS_BUILTIN_FRAG_COORD = 1,
SPIRV_CROSS_BUILTIN_WORK_GROUP_ID = 2,
SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS = 3,
SPIRV_CROSS_NUM_BUILTINS
} spirv_cross_builtin;
void spirv_cross_set_builtin(spirv_cross_shader_t *thiz,
spirv_cross_builtin builtin,
void *data, size_t size);
void spirv_cross_set_builtin(spirv_cross_shader_t *thiz, spirv_cross_builtin builtin, void *data, size_t size);
#define SPIRV_CROSS_NUM_DESCRIPTOR_SETS 4
#define SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS 16
@ -72,64 +63,63 @@ void spirv_cross_set_builtin(spirv_cross_shader_t *thiz,
enum spirv_cross_format
{
SPIRV_CROSS_FORMAT_R8_UNORM = 0,
SPIRV_CROSS_FORMAT_R8G8_UNORM = 1,
SPIRV_CROSS_FORMAT_R8G8B8_UNORM = 2,
SPIRV_CROSS_FORMAT_R8G8B8A8_UNORM = 3,
SPIRV_CROSS_FORMAT_R8_UNORM = 0,
SPIRV_CROSS_FORMAT_R8G8_UNORM = 1,
SPIRV_CROSS_FORMAT_R8G8B8_UNORM = 2,
SPIRV_CROSS_FORMAT_R8G8B8A8_UNORM = 3,
SPIRV_CROSS_NUM_FORMATS
SPIRV_CROSS_NUM_FORMATS
};
enum spirv_cross_wrap
{
SPIRV_CROSS_WRAP_CLAMP_TO_EDGE = 0,
SPIRV_CROSS_WRAP_REPEAT = 1,
SPIRV_CROSS_WRAP_CLAMP_TO_EDGE = 0,
SPIRV_CROSS_WRAP_REPEAT = 1,
SPIRV_CROSS_NUM_WRAP
SPIRV_CROSS_NUM_WRAP
};
enum spirv_cross_filter
{
SPIRV_CROSS_FILTER_NEAREST = 0,
SPIRV_CROSS_FILTER_LINEAR = 1,
SPIRV_CROSS_FILTER_NEAREST = 0,
SPIRV_CROSS_FILTER_LINEAR = 1,
SPIRV_CROSS_NUM_FILTER
SPIRV_CROSS_NUM_FILTER
};
enum spirv_cross_mipfilter
{
SPIRV_CROSS_MIPFILTER_BASE = 0,
SPIRV_CROSS_MIPFILTER_NEAREST = 1,
SPIRV_CROSS_MIPFILTER_LINEAR = 2,
SPIRV_CROSS_MIPFILTER_BASE = 0,
SPIRV_CROSS_MIPFILTER_NEAREST = 1,
SPIRV_CROSS_MIPFILTER_LINEAR = 2,
SPIRV_CROSS_NUM_MIPFILTER
SPIRV_CROSS_NUM_MIPFILTER
};
struct spirv_cross_miplevel
{
const void *data;
unsigned width, height;
size_t stride;
const void *data;
unsigned width, height;
size_t stride;
};
struct spirv_cross_sampler_info
{
const struct spirv_cross_miplevel *mipmaps;
unsigned num_mipmaps;
const struct spirv_cross_miplevel *mipmaps;
unsigned num_mipmaps;
enum spirv_cross_format format;
enum spirv_cross_wrap wrap_s;
enum spirv_cross_wrap wrap_t;
enum spirv_cross_filter min_filter;
enum spirv_cross_filter mag_filter;
enum spirv_cross_mipfilter mip_filter;
enum spirv_cross_format format;
enum spirv_cross_wrap wrap_s;
enum spirv_cross_wrap wrap_t;
enum spirv_cross_filter min_filter;
enum spirv_cross_filter mag_filter;
enum spirv_cross_mipfilter mip_filter;
};
typedef struct spirv_cross_sampler_2d spirv_cross_sampler_2d_t;
spirv_cross_sampler_2d_t *spirv_cross_create_sampler_2d(const struct spirv_cross_sampler_info *info);
void spirv_cross_destroy_sampler_2d(spirv_cross_sampler_2d_t *samp);
#ifdef __cplusplus
}
#endif

View File

@ -29,17 +29,22 @@
namespace spirv_cross
{
template<typename T>
struct image2DBase
{
virtual ~image2DBase() = default;
inline virtual T load(glm::ivec2 coord) { return T(0, 0, 0, 1); }
inline virtual void store(glm::ivec2 coord, const T &v) {}
};
template <typename T>
struct image2DBase
{
virtual ~image2DBase() = default;
inline virtual T load(glm::ivec2 coord)
{
return T(0, 0, 0, 1);
}
inline virtual void store(glm::ivec2 coord, const T &v)
{
}
};
typedef image2DBase<glm::vec4> image2D;
typedef image2DBase<glm::ivec4> iimage2D;
typedef image2DBase<glm::uvec4> uimage2D;
typedef image2DBase<glm::vec4> image2D;
typedef image2DBase<glm::ivec4> iimage2D;
typedef image2DBase<glm::uvec4> uimage2D;
}
#endif

View File

@ -39,493 +39,565 @@
namespace internal
{
// Adaptor helpers to adapt GLSL access chain syntax to C++.
// Don't bother with arrays of arrays on uniforms ...
// Would likely need horribly complex variadic template munging.
// Adaptor helpers to adapt GLSL access chain syntax to C++.
// Don't bother with arrays of arrays on uniforms ...
// Would likely need horribly complex variadic template munging.
template<typename T>
struct Interface
{
enum { ArraySize = 1, Size = sizeof(T) };
template <typename T>
struct Interface
{
enum
{
ArraySize = 1,
Size = sizeof(T)
};
Interface() : ptr(0) {}
T& get()
{
assert(ptr);
return *ptr;
}
Interface()
: ptr(0)
{
}
T &get()
{
assert(ptr);
return *ptr;
}
T *ptr;
};
T *ptr;
};
// For array types, return a pointer instead.
template<typename T, unsigned U>
struct Interface<T[U]>
{
enum { ArraySize = U, Size = U * sizeof(T) };
// For array types, return a pointer instead.
template <typename T, unsigned U>
struct Interface<T[U]>
{
enum
{
ArraySize = U,
Size = U * sizeof(T)
};
Interface() : ptr(0) {}
T* get()
{
assert(ptr);
return ptr;
}
Interface()
: ptr(0)
{
}
T *get()
{
assert(ptr);
return ptr;
}
T *ptr;
};
T *ptr;
};
// For case when array size is 1, avoid double dereference.
template<typename T>
struct PointerInterface
{
enum { ArraySize = 1, Size = sizeof(T*) };
enum { PreDereference = true };
// For case when array size is 1, avoid double dereference.
template <typename T>
struct PointerInterface
{
enum
{
ArraySize = 1,
Size = sizeof(T *)
};
enum
{
PreDereference = true
};
PointerInterface() : ptr(0) {}
PointerInterface()
: ptr(0)
{
}
T& get()
{
assert(ptr);
return *ptr;
}
T &get()
{
assert(ptr);
return *ptr;
}
T *ptr;
};
T *ptr;
};
// Automatically converts a pointer down to reference to match GLSL syntax.
template<typename T>
struct DereferenceAdaptor
{
DereferenceAdaptor(T **ptr) : ptr(ptr) {}
T& operator[](unsigned index) const { return *(ptr[index]); }
T **ptr;
};
// Automatically converts a pointer down to reference to match GLSL syntax.
template <typename T>
struct DereferenceAdaptor
{
DereferenceAdaptor(T **ptr)
: ptr(ptr)
{
}
T &operator[](unsigned index) const
{
return *(ptr[index]);
}
T **ptr;
};
// We can't have a linear array of T* since T* can be an abstract type in case of samplers.
// We also need a list of pointers since we can have run-time length SSBOs.
template<typename T, unsigned U>
struct PointerInterface<T[U]>
{
enum { ArraySize = U, Size = sizeof(T*) * U };
enum { PreDereference = false };
PointerInterface() : ptr(0) {}
// We can't have a linear array of T* since T* can be an abstract type in case of samplers.
// We also need a list of pointers since we can have run-time length SSBOs.
template <typename T, unsigned U>
struct PointerInterface<T[U]>
{
enum
{
ArraySize = U,
Size = sizeof(T *) * U
};
enum
{
PreDereference = false
};
PointerInterface()
: ptr(0)
{
}
DereferenceAdaptor<T> get()
{
assert(ptr);
return DereferenceAdaptor<T>(ptr);
}
DereferenceAdaptor<T> get()
{
assert(ptr);
return DereferenceAdaptor<T>(ptr);
}
T **ptr;
};
T **ptr;
};
// Resources can be more abstract and be unsized,
// so we need to have an array of pointers for those cases.
template<typename T> struct Resource : PointerInterface<T> {};
// Resources can be more abstract and be unsized,
// so we need to have an array of pointers for those cases.
template <typename T>
struct Resource : PointerInterface<T>
{
};
// POD with no unknown sizes, so we can express these as flat arrays.
template<typename T> struct UniformConstant : Interface<T> {};
template<typename T> struct StageInput : Interface<T> {};
template<typename T> struct StageOutput : Interface<T> {};
template<typename T> struct PushConstant : Interface<T> {};
// POD with no unknown sizes, so we can express these as flat arrays.
template <typename T>
struct UniformConstant : Interface<T>
{
};
template <typename T>
struct StageInput : Interface<T>
{
};
template <typename T>
struct StageOutput : Interface<T>
{
};
template <typename T>
struct PushConstant : Interface<T>
{
};
}
struct spirv_cross_shader
{
struct PPSize
{
PPSize() : ptr(0), size(0) {}
void **ptr;
size_t size;
};
struct PPSize
{
PPSize()
: ptr(0)
, size(0)
{
}
void **ptr;
size_t size;
};
struct PPSizeResource
{
PPSizeResource() : ptr(0), size(0), pre_dereference(false) {}
void **ptr;
size_t size;
bool pre_dereference;
};
struct PPSizeResource
{
PPSizeResource()
: ptr(0)
, size(0)
, pre_dereference(false)
{
}
void **ptr;
size_t size;
bool pre_dereference;
};
PPSizeResource resources[SPIRV_CROSS_NUM_DESCRIPTOR_SETS][SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS];
PPSize stage_inputs[SPIRV_CROSS_NUM_STAGE_INPUTS];
PPSize stage_outputs[SPIRV_CROSS_NUM_STAGE_OUTPUTS];
PPSize uniform_constants[SPIRV_CROSS_NUM_UNIFORM_CONSTANTS];
PPSize push_constant;
PPSize builtins[SPIRV_CROSS_NUM_BUILTINS];
PPSizeResource resources[SPIRV_CROSS_NUM_DESCRIPTOR_SETS][SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS];
PPSize stage_inputs[SPIRV_CROSS_NUM_STAGE_INPUTS];
PPSize stage_outputs[SPIRV_CROSS_NUM_STAGE_OUTPUTS];
PPSize uniform_constants[SPIRV_CROSS_NUM_UNIFORM_CONSTANTS];
PPSize push_constant;
PPSize builtins[SPIRV_CROSS_NUM_BUILTINS];
template<typename U>
void register_builtin(spirv_cross_builtin builtin, const U& value)
{
assert(!builtins[builtin].ptr);
template <typename U>
void register_builtin(spirv_cross_builtin builtin, const U &value)
{
assert(!builtins[builtin].ptr);
builtins[builtin].ptr = (void**)&value.ptr;
builtins[builtin].size = sizeof(*value.ptr) * U::ArraySize;
}
builtins[builtin].ptr = (void **)&value.ptr;
builtins[builtin].size = sizeof(*value.ptr) * U::ArraySize;
}
void set_builtin(spirv_cross_builtin builtin, void *data, size_t size)
{
assert(builtins[builtin].ptr);
assert(size >= builtins[builtin].size);
void set_builtin(spirv_cross_builtin builtin, void *data, size_t size)
{
assert(builtins[builtin].ptr);
assert(size >= builtins[builtin].size);
*builtins[builtin].ptr = data;
}
*builtins[builtin].ptr = data;
}
template<typename U>
void register_resource(const internal::Resource<U> &value, unsigned set, unsigned binding)
{
assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
assert(!resources[set][binding].ptr);
template <typename U>
void register_resource(const internal::Resource<U> &value, unsigned set, unsigned binding)
{
assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
assert(!resources[set][binding].ptr);
resources[set][binding].ptr = (void**)&value.ptr;
resources[set][binding].size = internal::Resource<U>::Size;
resources[set][binding].pre_dereference = internal::Resource<U>::PreDereference;
}
resources[set][binding].ptr = (void **)&value.ptr;
resources[set][binding].size = internal::Resource<U>::Size;
resources[set][binding].pre_dereference = internal::Resource<U>::PreDereference;
}
template<typename U>
void register_stage_input(const internal::StageInput<U> &value, unsigned location)
{
assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
assert(!stage_inputs[location].ptr);
template <typename U>
void register_stage_input(const internal::StageInput<U> &value, unsigned location)
{
assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
assert(!stage_inputs[location].ptr);
stage_inputs[location].ptr = (void**)&value.ptr;
stage_inputs[location].size = internal::StageInput<U>::Size;
}
stage_inputs[location].ptr = (void **)&value.ptr;
stage_inputs[location].size = internal::StageInput<U>::Size;
}
template<typename U>
void register_stage_output(const internal::StageOutput<U> &value, unsigned location)
{
assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
assert(!stage_outputs[location].ptr);
template <typename U>
void register_stage_output(const internal::StageOutput<U> &value, unsigned location)
{
assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
assert(!stage_outputs[location].ptr);
stage_outputs[location].ptr = (void**)&value.ptr;
stage_outputs[location].size = internal::StageOutput<U>::Size;
}
stage_outputs[location].ptr = (void **)&value.ptr;
stage_outputs[location].size = internal::StageOutput<U>::Size;
}
template<typename U>
void register_uniform_constant(const internal::UniformConstant<U> &value, unsigned location)
{
assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
assert(!uniform_constants[location].ptr);
template <typename U>
void register_uniform_constant(const internal::UniformConstant<U> &value, unsigned location)
{
assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
assert(!uniform_constants[location].ptr);
uniform_constants[location].ptr = (void**)&value.ptr;
uniform_constants[location].size = internal::UniformConstant<U>::Size;
}
uniform_constants[location].ptr = (void **)&value.ptr;
uniform_constants[location].size = internal::UniformConstant<U>::Size;
}
template<typename U>
void register_push_constant(const internal::PushConstant<U> &value)
{
assert(!push_constant.ptr);
template <typename U>
void register_push_constant(const internal::PushConstant<U> &value)
{
assert(!push_constant.ptr);
push_constant.ptr = (void**)&value.ptr;
push_constant.size = internal::PushConstant<U>::Size;
}
push_constant.ptr = (void **)&value.ptr;
push_constant.size = internal::PushConstant<U>::Size;
}
void set_stage_input(unsigned location, void *data, size_t size)
{
assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
assert(stage_inputs[location].ptr);
assert(size >= stage_inputs[location].size);
void set_stage_input(unsigned location, void *data, size_t size)
{
assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
assert(stage_inputs[location].ptr);
assert(size >= stage_inputs[location].size);
*stage_inputs[location].ptr = data;
}
*stage_inputs[location].ptr = data;
}
void set_stage_output(unsigned location, void *data, size_t size)
{
assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
assert(stage_outputs[location].ptr);
assert(size >= stage_outputs[location].size);
void set_stage_output(unsigned location, void *data, size_t size)
{
assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
assert(stage_outputs[location].ptr);
assert(size >= stage_outputs[location].size);
*stage_outputs[location].ptr = data;
}
*stage_outputs[location].ptr = data;
}
void set_uniform_constant(unsigned location, void *data, size_t size)
{
assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
assert(uniform_constants[location].ptr);
assert(size >= uniform_constants[location].size);
void set_uniform_constant(unsigned location, void *data, size_t size)
{
assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
assert(uniform_constants[location].ptr);
assert(size >= uniform_constants[location].size);
*uniform_constants[location].ptr = data;
}
*uniform_constants[location].ptr = data;
}
void set_push_constant(void *data, size_t size)
{
assert(push_constant.ptr);
assert(size >= push_constant.size);
void set_push_constant(void *data, size_t size)
{
assert(push_constant.ptr);
assert(size >= push_constant.size);
*push_constant.ptr = data;
}
*push_constant.ptr = data;
}
void set_resource(unsigned set, unsigned binding,
void **data, size_t size)
{
assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
assert(resources[set][binding].ptr);
assert(size >= resources[set][binding].size);
void set_resource(unsigned set, unsigned binding, void **data, size_t size)
{
assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
assert(resources[set][binding].ptr);
assert(size >= resources[set][binding].size);
// We're using the regular PointerInterface, dereference ahead of time.
if (resources[set][binding].pre_dereference)
*resources[set][binding].ptr = *data;
else
*resources[set][binding].ptr = data;
}
// We're using the regular PointerInterface, dereference ahead of time.
if (resources[set][binding].pre_dereference)
*resources[set][binding].ptr = *data;
else
*resources[set][binding].ptr = data;
}
};
namespace spirv_cross
{
template<typename T>
struct BaseShader : spirv_cross_shader
{
void invoke()
{
static_cast<T*>(this)->main();
}
};
template <typename T>
struct BaseShader : spirv_cross_shader
{
void invoke()
{
static_cast<T *>(this)->main();
}
};
struct FragmentResources
{
internal::StageOutput<glm::vec4> gl_FragCoord;
void init(spirv_cross_shader &s)
{
s.register_builtin(SPIRV_CROSS_BUILTIN_FRAG_COORD, gl_FragCoord);
}
struct FragmentResources
{
internal::StageOutput<glm::vec4> gl_FragCoord;
void init(spirv_cross_shader &s)
{
s.register_builtin(SPIRV_CROSS_BUILTIN_FRAG_COORD, gl_FragCoord);
}
#define gl_FragCoord __res->gl_FragCoord.get()
};
};
template<typename T, typename Res>
struct FragmentShader : BaseShader<FragmentShader<T, Res> >
{
inline void main()
{
impl.main();
}
template <typename T, typename Res>
struct FragmentShader : BaseShader<FragmentShader<T, Res>>
{
inline void main()
{
impl.main();
}
FragmentShader()
{
resources.init(*this);
impl.__res = &resources;
}
FragmentShader()
{
resources.init(*this);
impl.__res = &resources;
}
T impl;
Res resources;
};
T impl;
Res resources;
};
struct VertexResources
{
internal::StageOutput<glm::vec4> gl_Position;
void init(spirv_cross_shader &s)
{
s.register_builtin(SPIRV_CROSS_BUILTIN_POSITION, gl_Position);
}
struct VertexResources
{
internal::StageOutput<glm::vec4> gl_Position;
void init(spirv_cross_shader &s)
{
s.register_builtin(SPIRV_CROSS_BUILTIN_POSITION, gl_Position);
}
#define gl_Position __res->gl_Position.get()
};
};
template<typename T, typename Res>
struct VertexShader : BaseShader<VertexShader<T, Res> >
{
inline void main()
{
impl.main();
}
template <typename T, typename Res>
struct VertexShader : BaseShader<VertexShader<T, Res>>
{
inline void main()
{
impl.main();
}
VertexShader()
{
resources.init(*this);
impl.__res = &resources;
}
VertexShader()
{
resources.init(*this);
impl.__res = &resources;
}
T impl;
Res resources;
};
T impl;
Res resources;
};
struct TessEvaluationResources
{
inline void init(spirv_cross_shader&) {}
};
struct TessEvaluationResources
{
inline void init(spirv_cross_shader &)
{
}
};
template<typename T, typename Res>
struct TessEvaluationShader : BaseShader<TessEvaluationShader<T, Res> >
{
inline void main()
{
impl.main();
}
template <typename T, typename Res>
struct TessEvaluationShader : BaseShader<TessEvaluationShader<T, Res>>
{
inline void main()
{
impl.main();
}
TessEvaluationShader()
{
resources.init(*this);
impl.__res = &resources;
}
TessEvaluationShader()
{
resources.init(*this);
impl.__res = &resources;
}
T impl;
Res resources;
};
T impl;
Res resources;
};
struct TessControlResources
{
inline void init(spirv_cross_shader&) {}
};
struct TessControlResources
{
inline void init(spirv_cross_shader &)
{
}
};
template<typename T, typename Res>
struct TessControlShader : BaseShader<TessControlShader<T, Res> >
{
inline void main()
{
impl.main();
}
template <typename T, typename Res>
struct TessControlShader : BaseShader<TessControlShader<T, Res>>
{
inline void main()
{
impl.main();
}
TessControlShader()
{
resources.init(*this);
impl.__res = &resources;
}
TessControlShader()
{
resources.init(*this);
impl.__res = &resources;
}
T impl;
Res resources;
};
T impl;
Res resources;
};
struct GeometryResources
{
inline void init(spirv_cross_shader&) {}
};
struct GeometryResources
{
inline void init(spirv_cross_shader &)
{
}
};
template<typename T, typename Res>
struct GeometryShader : BaseShader<GeometryShader<T, Res> >
{
inline void main()
{
impl.main();
}
template <typename T, typename Res>
struct GeometryShader : BaseShader<GeometryShader<T, Res>>
{
inline void main()
{
impl.main();
}
GeometryShader()
{
resources.init(*this);
impl.__res = &resources;
}
GeometryShader()
{
resources.init(*this);
impl.__res = &resources;
}
T impl;
Res resources;
};
T impl;
Res resources;
};
struct ComputeResources
{
internal::StageInput<glm::uvec3> gl_WorkGroupID__;
internal::StageInput<glm::uvec3> gl_NumWorkGroups__;
void init(spirv_cross_shader &s)
{
s.register_builtin(SPIRV_CROSS_BUILTIN_WORK_GROUP_ID, gl_WorkGroupID__);
s.register_builtin(SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS, gl_NumWorkGroups__);
}
struct ComputeResources
{
internal::StageInput<glm::uvec3> gl_WorkGroupID__;
internal::StageInput<glm::uvec3> gl_NumWorkGroups__;
void init(spirv_cross_shader &s)
{
s.register_builtin(SPIRV_CROSS_BUILTIN_WORK_GROUP_ID, gl_WorkGroupID__);
s.register_builtin(SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS, gl_NumWorkGroups__);
}
#define gl_WorkGroupID __res->gl_WorkGroupID__.get()
#define gl_NumWorkGroups __res->gl_NumWorkGroups.get()
Barrier barrier__;
Barrier barrier__;
#define barrier() __res->barrier__.wait()
};
};
struct ComputePrivateResources
{
uint32_t gl_LocalInvocationIndex__;
struct ComputePrivateResources
{
uint32_t gl_LocalInvocationIndex__;
#define gl_LocalInvocationIndex __priv_res.gl_LocalInvocationIndex__
glm::uvec3 gl_LocalInvocationID__;
glm::uvec3 gl_LocalInvocationID__;
#define gl_LocalInvocationID __priv_res.gl_LocalInvocationID__
glm::uvec3 gl_GlobalInvocationID__;
glm::uvec3 gl_GlobalInvocationID__;
#define gl_GlobalInvocationID __priv_res.gl_GlobalInvocationID__
};
};
template<typename T, typename Res, unsigned WorkGroupX, unsigned WorkGroupY, unsigned WorkGroupZ>
struct ComputeShader : BaseShader<ComputeShader<T, Res, WorkGroupX, WorkGroupY, WorkGroupZ> >
{
inline void main()
{
resources.barrier__.reset_counter();
template <typename T, typename Res, unsigned WorkGroupX, unsigned WorkGroupY, unsigned WorkGroupZ>
struct ComputeShader : BaseShader<ComputeShader<T, Res, WorkGroupX, WorkGroupY, WorkGroupZ>>
{
inline void main()
{
resources.barrier__.reset_counter();
for (unsigned z = 0; z < WorkGroupZ; z++)
for (unsigned y = 0; y < WorkGroupY; y++)
for (unsigned x = 0; x < WorkGroupX; x++)
impl[z][y][x].__priv_res.gl_GlobalInvocationID__ =
glm::uvec3(WorkGroupX, WorkGroupY, WorkGroupZ) * resources.gl_WorkGroupID__.get() +
glm::uvec3(x, y, z);
for (unsigned z = 0; z < WorkGroupZ; z++)
for (unsigned y = 0; y < WorkGroupY; y++)
for (unsigned x = 0; x < WorkGroupX; x++)
impl[z][y][x].__priv_res.gl_GlobalInvocationID__ =
glm::uvec3(WorkGroupX, WorkGroupY, WorkGroupZ) * resources.gl_WorkGroupID__.get() +
glm::uvec3(x, y, z);
group.run();
group.wait();
}
group.run();
group.wait();
}
ComputeShader()
: group(&impl[0][0][0])
{
resources.init(*this);
resources.barrier__.set_release_divisor(WorkGroupX * WorkGroupY * WorkGroupZ);
ComputeShader()
: group(&impl[0][0][0])
{
resources.init(*this);
resources.barrier__.set_release_divisor(WorkGroupX * WorkGroupY * WorkGroupZ);
unsigned i = 0;
for (unsigned z = 0; z < WorkGroupZ; z++)
{
for (unsigned y = 0; y < WorkGroupY; y++)
{
for (unsigned x = 0; x < WorkGroupX; x++)
{
impl[z][y][x].__priv_res.gl_LocalInvocationID__ =
glm::uvec3(x, y, z);
impl[z][y][x].__priv_res.gl_LocalInvocationIndex__ = i++;
impl[z][y][x].__res = &resources;
}
}
}
}
unsigned i = 0;
for (unsigned z = 0; z < WorkGroupZ; z++)
{
for (unsigned y = 0; y < WorkGroupY; y++)
{
for (unsigned x = 0; x < WorkGroupX; x++)
{
impl[z][y][x].__priv_res.gl_LocalInvocationID__ = glm::uvec3(x, y, z);
impl[z][y][x].__priv_res.gl_LocalInvocationIndex__ = i++;
impl[z][y][x].__res = &resources;
}
}
}
}
T impl[WorkGroupZ][WorkGroupY][WorkGroupX];
ThreadGroup<T, WorkGroupX * WorkGroupY * WorkGroupZ> group;
Res resources;
};
T impl[WorkGroupZ][WorkGroupY][WorkGroupX];
ThreadGroup<T, WorkGroupX * WorkGroupY * WorkGroupZ> group;
Res resources;
};
inline void memoryBarrierShared() { Barrier::memoryBarrier(); }
inline void memoryBarrier() { Barrier::memoryBarrier(); }
// TODO: Rest of the barriers.
inline void memoryBarrierShared()
{
Barrier::memoryBarrier();
}
inline void memoryBarrier()
{
Barrier::memoryBarrier();
}
// TODO: Rest of the barriers.
// Atomics
template<typename T>
inline T atomicAdd(T &v, T a)
{
static_assert(sizeof(std::atomic<T>) == sizeof(T), "Cannot cast properly to std::atomic<T>.");
// Atomics
template <typename T>
inline T atomicAdd(T &v, T a)
{
static_assert(sizeof(std::atomic<T>) == sizeof(T), "Cannot cast properly to std::atomic<T>.");
// We need explicit memory barriers in GLSL to enfore any ordering.
// FIXME: Can we really cast this? There is no other way I think ...
return std::atomic_fetch_add_explicit(reinterpret_cast<std::atomic<T>*>(&v),
a, std::memory_order_relaxed);
}
// We need explicit memory barriers in GLSL to enfore any ordering.
// FIXME: Can we really cast this? There is no other way I think ...
return std::atomic_fetch_add_explicit(reinterpret_cast<std::atomic<T> *>(&v), a, std::memory_order_relaxed);
}
}
void spirv_cross_set_stage_input(spirv_cross_shader_t *shader, unsigned location, void *data, size_t size)
{
shader->set_stage_input(location, data, size);
shader->set_stage_input(location, data, size);
}
void spirv_cross_set_stage_output(spirv_cross_shader_t *shader, unsigned location, void *data, size_t size)
{
shader->set_stage_output(location, data, size);
shader->set_stage_output(location, data, size);
}
void spirv_cross_set_uniform_constant(spirv_cross_shader_t *shader, unsigned location, void *data, size_t size)
{
shader->set_uniform_constant(location, data, size);
shader->set_uniform_constant(location, data, size);
}
void spirv_cross_set_resource(spirv_cross_shader_t *shader, unsigned set, unsigned binding, void **data, size_t size)
{
shader->set_resource(set, binding, data, size);
shader->set_resource(set, binding, data, size);
}
void spirv_cross_set_push_constant(spirv_cross_shader_t *shader, void *data, size_t size)
{
shader->set_push_constant(data, size);
shader->set_push_constant(data, size);
}
void spirv_cross_set_builtin(spirv_cross_shader_t *shader, spirv_cross_builtin builtin,
void *data, size_t size)
void spirv_cross_set_builtin(spirv_cross_shader_t *shader, spirv_cross_builtin builtin, void *data, size_t size)
{
shader->set_builtin(builtin, data, size);
shader->set_builtin(builtin, data, size);
}
#endif

View File

@ -21,81 +21,85 @@
namespace spirv_cross
{
struct spirv_cross_sampler_2d
{
inline virtual ~spirv_cross_sampler_2d() {}
};
struct spirv_cross_sampler_2d
{
inline virtual ~spirv_cross_sampler_2d()
{
}
};
template<typename T>
struct sampler2DBase : spirv_cross_sampler_2d
{
sampler2DBase(const spirv_cross_sampler_info *info)
{
mips.insert(mips.end(), info->mipmaps, info->mipmaps + info->num_mipmaps);
format = info->format;
wrap_s = info->wrap_s;
wrap_t = info->wrap_t;
min_filter = info->min_filter;
mag_filter = info->mag_filter;
mip_filter = info->mip_filter;
}
template <typename T>
struct sampler2DBase : spirv_cross_sampler_2d
{
sampler2DBase(const spirv_cross_sampler_info *info)
{
mips.insert(mips.end(), info->mipmaps, info->mipmaps + info->num_mipmaps);
format = info->format;
wrap_s = info->wrap_s;
wrap_t = info->wrap_t;
min_filter = info->min_filter;
mag_filter = info->mag_filter;
mip_filter = info->mip_filter;
}
inline virtual T sample(glm::vec2 uv, float bias)
{
return sampleLod(uv, bias);
}
inline virtual T sample(glm::vec2 uv, float bias)
{
return sampleLod(uv, bias);
}
inline virtual T sampleLod(glm::vec2 uv, float lod)
{
if (mag_filter == SPIRV_CROSS_FILTER_NEAREST)
{
uv.x = wrap(uv.x, wrap_s, mips[0].width);
uv.y = wrap(uv.y, wrap_t, mips[0].height);
glm::vec2 uv_full = uv * glm::vec2(mips[0].width, mips[0].height);
inline virtual T sampleLod(glm::vec2 uv, float lod)
{
if (mag_filter == SPIRV_CROSS_FILTER_NEAREST)
{
uv.x = wrap(uv.x, wrap_s, mips[0].width);
uv.y = wrap(uv.y, wrap_t, mips[0].height);
glm::vec2 uv_full = uv * glm::vec2(mips[0].width, mips[0].height);
int x = int(uv_full.x);
int y = int(uv_full.y);
return sample(x, y, 0);
}
else
{
return T(0, 0, 0, 1);
}
}
int x = int(uv_full.x);
int y = int(uv_full.y);
return sample(x, y, 0);
}
else
{
return T(0, 0, 0, 1);
}
}
inline float wrap(float v, spirv_cross_wrap wrap, unsigned size)
{
switch (wrap)
{
case SPIRV_CROSS_WRAP_REPEAT:
return v - glm::floor(v);
case SPIRV_CROSS_WRAP_CLAMP_TO_EDGE:
{
float half = 0.5f / size;
return glm::clamp(v, half, 1.0f - half);
}
inline float wrap(float v, spirv_cross_wrap wrap, unsigned size)
{
switch (wrap)
{
case SPIRV_CROSS_WRAP_REPEAT:
return v - glm::floor(v);
case SPIRV_CROSS_WRAP_CLAMP_TO_EDGE:
{
float half = 0.5f / size;
return glm::clamp(v, half, 1.0f - half);
}
default:
return 0.0f;
}
}
default:
return 0.0f;
}
}
std::vector<spirv_cross_miplevel> mips;
spirv_cross_format format;
spirv_cross_wrap wrap_s;
spirv_cross_format wrap_t;
spirv_cross_filter min_filter;
spirv_cross_filter mag_filter;
spirv_cross_mipfilter mip_filter;
};
std::vector<spirv_cross_miplevel> mips;
spirv_cross_format format;
spirv_cross_wrap wrap_s;
spirv_cross_format wrap_t;
spirv_cross_filter min_filter;
spirv_cross_filter mag_filter;
spirv_cross_mipfilter mip_filter;
};
typedef sampler2DBase<glm::vec4> sampler2D;
typedef sampler2DBase<glm::ivec4> isampler2D;
typedef sampler2DBase<glm::uvec4> usampler2D;
template<typename T>
inline T texture(const sampler2DBase<T> &samp, const glm::vec2 &uv, float bias = 0.0f) { return samp.sample(uv, bias); }
typedef sampler2DBase<glm::vec4> sampler2D;
typedef sampler2DBase<glm::ivec4> isampler2D;
typedef sampler2DBase<glm::uvec4> usampler2D;
template <typename T>
inline T texture(const sampler2DBase<T> &samp, const glm::vec2 &uv, float bias = 0.0f)
{
return samp.sample(uv, bias);
}
}
#endif

View File

@ -23,91 +23,98 @@
namespace spirv_cross
{
template<typename T, unsigned Size>
class ThreadGroup
{
public:
ThreadGroup(T *impl)
{
for (unsigned i = 0; i < Size; i++)
workers[i].start(&impl[i]);
}
template <typename T, unsigned Size>
class ThreadGroup
{
public:
ThreadGroup(T *impl)
{
for (unsigned i = 0; i < Size; i++)
workers[i].start(&impl[i]);
}
void run()
{
for (auto &worker : workers)
worker.run();
}
void run()
{
for (auto &worker : workers)
worker.run();
}
void wait()
{
for (auto &worker : workers)
worker.wait();
}
void wait()
{
for (auto &worker : workers)
worker.wait();
}
private:
struct Thread
{
enum State
{
Idle,
Running,
Dying
};
State state = Idle;
private:
struct Thread
{
enum State
{
Idle,
Running,
Dying
};
State state = Idle;
void start(T *impl)
{
worker = std::thread([impl, this] {
for (;;)
{
{
std::unique_lock<std::mutex> l{lock};
cond.wait(l, [this] { return state != Idle; });
if (state == Dying)
break;
}
void start(T *impl)
{
worker = std::thread([impl, this]
{
for (;;)
{
{
std::unique_lock<std::mutex> l{ lock };
cond.wait(l, [this]
{
return state != Idle;
});
if (state == Dying)
break;
}
impl->main();
impl->main();
std::lock_guard<std::mutex> l{lock};
state = Idle;
cond.notify_one();
}
});
}
std::lock_guard<std::mutex> l{ lock };
state = Idle;
cond.notify_one();
}
});
}
void wait()
{
std::unique_lock<std::mutex> l{lock};
cond.wait(l, [this] { return state == Idle; });
}
void wait()
{
std::unique_lock<std::mutex> l{ lock };
cond.wait(l, [this]
{
return state == Idle;
});
}
void run()
{
std::lock_guard<std::mutex> l{lock};
state = Running;
cond.notify_one();
}
void run()
{
std::lock_guard<std::mutex> l{ lock };
state = Running;
cond.notify_one();
}
~Thread()
{
if (worker.joinable())
{
{
std::lock_guard<std::mutex> l{lock};
state = Dying;
cond.notify_one();
}
worker.join();
}
}
std::thread worker;
std::condition_variable cond;
std::mutex lock;
};
Thread workers[Size];
};
~Thread()
{
if (worker.joinable())
{
{
std::lock_guard<std::mutex> l{ lock };
state = Dying;
cond.notify_one();
}
worker.join();
}
}
std::thread worker;
std::condition_variable cond;
std::mutex lock;
};
Thread workers[Size];
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -22,415 +22,413 @@ using namespace std;
void CompilerCPP::emit_buffer_block(const SPIRVariable &var)
{
auto &type = get<SPIRType>(var.basetype);
auto instance_name = to_name(var.self);
auto &type = get<SPIRType>(var.basetype);
auto instance_name = to_name(var.self);
uint32_t descriptor_set = meta[var.self].decoration.set;
uint32_t binding = meta[var.self].decoration.binding;
uint32_t descriptor_set = meta[var.self].decoration.set;
uint32_t binding = meta[var.self].decoration.binding;
emit_struct(type);
statement("internal::Resource<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
statement("");
emit_struct(type);
statement("internal::Resource<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(
join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
statement("");
}
void CompilerCPP::emit_interface_block(const SPIRVariable &var)
{
auto &type = get<SPIRType>(var.basetype);
auto &type = get<SPIRType>(var.basetype);
const char *qual = var.storage == StorageClassInput ? "StageInput" : "StageOutput";
const char *lowerqual = var.storage == StorageClassInput ? "stage_input" : "stage_output";
auto instance_name = to_name(var.self);
uint32_t location = meta[var.self].decoration.location;
const char *qual = var.storage == StorageClassInput ? "StageInput" : "StageOutput";
const char *lowerqual = var.storage == StorageClassInput ? "stage_input" : "stage_output";
auto instance_name = to_name(var.self);
uint32_t location = meta[var.self].decoration.location;
auto flags = meta[type.self].decoration.decoration_flags;
if (flags & (1ull << DecorationBlock))
emit_struct(type);
auto flags = meta[type.self].decoration.decoration_flags;
if (flags & (1ull << DecorationBlock))
emit_struct(type);
statement("internal::", qual, "<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(join("s.register_", lowerqual, "(", instance_name, "__", ", ", location, ");"));
statement("");
statement("internal::", qual, "<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(join("s.register_", lowerqual, "(", instance_name, "__", ", ", location, ");"));
statement("");
}
void CompilerCPP::emit_shared(const SPIRVariable &var)
{
auto instance_name = to_name(var.self);
statement(variable_decl(var), ";");
statement_no_indent("#define ", instance_name, " __res->", instance_name);
auto instance_name = to_name(var.self);
statement(variable_decl(var), ";");
statement_no_indent("#define ", instance_name, " __res->", instance_name);
}
void CompilerCPP::emit_uniform(const SPIRVariable &var)
{
auto &type = get<SPIRType>(var.basetype);
auto instance_name = to_name(var.self);
auto &type = get<SPIRType>(var.basetype);
auto instance_name = to_name(var.self);
uint32_t descriptor_set = meta[var.self].decoration.set;
uint32_t binding = meta[var.self].decoration.binding;
uint32_t location = meta[var.self].decoration.location;
uint32_t descriptor_set = meta[var.self].decoration.set;
uint32_t binding = meta[var.self].decoration.binding;
uint32_t location = meta[var.self].decoration.location;
if (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage || type.basetype == SPIRType::AtomicCounter)
{
statement("internal::Resource<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
}
else
{
statement("internal::UniformConstant<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(join("s.register_uniform_constant(", instance_name, "__", ", ", location, ");"));
}
if (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
type.basetype == SPIRType::AtomicCounter)
{
statement("internal::Resource<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(
join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
}
else
{
statement("internal::UniformConstant<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name,
"__;");
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
resource_registrations.push_back(
join("s.register_uniform_constant(", instance_name, "__", ", ", location, ");"));
}
statement("");
statement("");
}
void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
{
auto &type = get<SPIRType>(var.basetype);
auto &flags = meta[var.self].decoration.decoration_flags;
if ((flags & (1ull << DecorationBinding)) || (flags & (1ull << DecorationDescriptorSet)))
throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
"Remap to location with reflection API first or disable these decorations.");
auto &type = get<SPIRType>(var.basetype);
auto &flags = meta[var.self].decoration.decoration_flags;
if ((flags & (1ull << DecorationBinding)) || (flags & (1ull << DecorationDescriptorSet)))
throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
"Remap to location with reflection API first or disable these decorations.");
emit_struct(type);
auto instance_name = to_name(var.self);
emit_struct(type);
auto instance_name = to_name(var.self);
statement("internal::PushConstant<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, ";");
statement_no_indent("#define ", instance_name, " __res->", instance_name, ".get()");
resource_registrations.push_back(join("s.register_push_constant(", instance_name, "__", ");"));
statement("");
statement("internal::PushConstant<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, ";");
statement_no_indent("#define ", instance_name, " __res->", instance_name, ".get()");
resource_registrations.push_back(join("s.register_push_constant(", instance_name, "__", ");"));
statement("");
}
void CompilerCPP::emit_resources()
{
// Output all basic struct types which are not Block or BufferBlock as these are declared inplace
// when such variables are instantiated.
for (auto &id : ids)
{
if (id.get_type() == TypeType)
{
auto &type = id.get<SPIRType>();
if (type.basetype == SPIRType::Struct &&
type.array.empty() &&
!type.pointer &&
(meta[type.self].decoration.decoration_flags & ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
{
emit_struct(type);
}
}
}
// Output all basic struct types which are not Block or BufferBlock as these are declared inplace
// when such variables are instantiated.
for (auto &id : ids)
{
if (id.get_type() == TypeType)
{
auto &type = id.get<SPIRType>();
if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
(meta[type.self].decoration.decoration_flags &
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
{
emit_struct(type);
}
}
}
statement("struct Resources : ", resource_type);
begin_scope();
statement("struct Resources : ", resource_type);
begin_scope();
// Output UBOs and SSBOs
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
// Output UBOs and SSBOs
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
if (type.pointer && type.storage == StorageClassUniform &&
!is_builtin_variable(var) &&
(meta[type.self].decoration.decoration_flags & ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
{
emit_buffer_block(var);
}
}
}
if (type.pointer && type.storage == StorageClassUniform && !is_builtin_variable(var) &&
(meta[type.self].decoration.decoration_flags &
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
{
emit_buffer_block(var);
}
}
}
// Output push constant blocks
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
if (type.pointer && type.storage == StorageClassPushConstant)
emit_push_constant_block(var);
}
}
// Output push constant blocks
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
if (type.pointer && type.storage == StorageClassPushConstant)
emit_push_constant_block(var);
}
}
// Output in/out interfaces.
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
// Output in/out interfaces.
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
if (!is_builtin_variable(var) &&
!var.remapped_variable &&
type.pointer &&
(var.storage == StorageClassInput || var.storage == StorageClassOutput))
{
emit_interface_block(var);
}
}
}
if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
(var.storage == StorageClassInput || var.storage == StorageClassOutput))
{
emit_interface_block(var);
}
}
}
// Output Uniform Constants (values, samplers, images, etc).
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
// Output Uniform Constants (values, samplers, images, etc).
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
(type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
{
emit_uniform(var);
}
}
}
if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
(type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
{
emit_uniform(var);
}
}
}
// Global variables.
bool emitted = false;
for (auto global : global_variables)
{
auto &var = get<SPIRVariable>(global);
if (var.storage == StorageClassWorkgroup)
{
emit_shared(var);
emitted = true;
}
}
// Global variables.
bool emitted = false;
for (auto global : global_variables)
{
auto &var = get<SPIRVariable>(global);
if (var.storage == StorageClassWorkgroup)
{
emit_shared(var);
emitted = true;
}
}
if (emitted)
statement("");
if (emitted)
statement("");
statement("inline void init(spirv_cross_shader& s)");
begin_scope();
statement(resource_type, "::init(s);");
for (auto &reg : resource_registrations)
statement(reg);
end_scope();
resource_registrations.clear();
statement("inline void init(spirv_cross_shader& s)");
begin_scope();
statement(resource_type, "::init(s);");
for (auto &reg : resource_registrations)
statement(reg);
end_scope();
resource_registrations.clear();
end_scope_decl();
end_scope_decl();
statement("");
statement("Resources* __res;");
if (execution.model == ExecutionModelGLCompute)
statement("ComputePrivateResources __priv_res;");
statement("");
statement("");
statement("Resources* __res;");
if (execution.model == ExecutionModelGLCompute)
statement("ComputePrivateResources __priv_res;");
statement("");
// Emit regular globals which are allocated per invocation.
emitted = false;
for (auto global : global_variables)
{
auto &var = get<SPIRVariable>(global);
if (var.storage == StorageClassPrivate)
{
if (var.storage == StorageClassWorkgroup)
emit_shared(var);
else
statement(variable_decl(var), ";");
emitted = true;
}
}
// Emit regular globals which are allocated per invocation.
emitted = false;
for (auto global : global_variables)
{
auto &var = get<SPIRVariable>(global);
if (var.storage == StorageClassPrivate)
{
if (var.storage == StorageClassWorkgroup)
emit_shared(var);
else
statement(variable_decl(var), ";");
emitted = true;
}
}
if (emitted)
statement("");
if (emitted)
statement("");
}
string CompilerCPP::compile()
{
// Do not deal with ES-isms like precision, older extensions and such.
options.es = false;
options.version = 450;
backend.float_literal_suffix = true;
backend.uint32_t_literal_suffix = true;
backend.basic_int_type = "int32_t";
backend.basic_uint_type = "uint32_t";
backend.swizzle_is_function = true;
backend.shared_is_implied = true;
// Do not deal with ES-isms like precision, older extensions and such.
options.es = false;
options.version = 450;
backend.float_literal_suffix = true;
backend.uint32_t_literal_suffix = true;
backend.basic_int_type = "int32_t";
backend.basic_uint_type = "uint32_t";
backend.swizzle_is_function = true;
backend.shared_is_implied = true;
uint32_t pass_count = 0;
do
{
if (pass_count >= 3)
throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
uint32_t pass_count = 0;
do
{
if (pass_count >= 3)
throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
resource_registrations.clear();
reset();
resource_registrations.clear();
reset();
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
emit_header();
emit_resources();
emit_header();
emit_resources();
emit_function(get<SPIRFunction>(execution.entry_point), 0);
emit_function(get<SPIRFunction>(execution.entry_point), 0);
pass_count++;
} while (force_recompile);
pass_count++;
} while (force_recompile);
// Match opening scope of emit_header().
end_scope_decl();
// namespace
end_scope();
// Match opening scope of emit_header().
end_scope_decl();
// namespace
end_scope();
// Emit C entry points
emit_c_linkage();
// Emit C entry points
emit_c_linkage();
return buffer->str();
return buffer->str();
}
void CompilerCPP::emit_c_linkage()
{
statement("");
statement("");
statement("spirv_cross_shader_t* spirv_cross_construct(void)");
begin_scope();
statement("return new ", impl_type, "();");
end_scope();
statement("spirv_cross_shader_t* spirv_cross_construct(void)");
begin_scope();
statement("return new ", impl_type, "();");
end_scope();
statement("");
statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
begin_scope();
statement("delete static_cast<", impl_type, "*>(shader);");
end_scope();
statement("");
statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
begin_scope();
statement("delete static_cast<", impl_type, "*>(shader);");
end_scope();
statement("");
statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
begin_scope();
statement("static_cast<", impl_type, "*>(shader)->invoke();");
end_scope();
statement("");
statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
begin_scope();
statement("static_cast<", impl_type, "*>(shader)->invoke();");
end_scope();
statement("");
statement("static const struct spirv_cross_interface vtable =");
begin_scope();
statement("spirv_cross_construct,");
statement("spirv_cross_destruct,");
statement("spirv_cross_invoke,");
end_scope_decl();
statement("");
statement("static const struct spirv_cross_interface vtable =");
begin_scope();
statement("spirv_cross_construct,");
statement("spirv_cross_destruct,");
statement("spirv_cross_invoke,");
end_scope_decl();
statement("");
statement("const struct spirv_cross_interface* spirv_cross_get_interface(void)");
begin_scope();
statement("return &vtable;");
end_scope();
statement("");
statement("const struct spirv_cross_interface* spirv_cross_get_interface(void)");
begin_scope();
statement("return &vtable;");
end_scope();
}
void CompilerCPP::emit_function_prototype(SPIRFunction &func, uint64_t)
{
local_variables.clear();
string decl;
local_variables.clear();
string decl;
auto &type = get<SPIRType>(func.return_type);
decl += "inline ";
decl += type_to_glsl(type);
decl += " ";
auto &type = get<SPIRType>(func.return_type);
decl += "inline ";
decl += type_to_glsl(type);
decl += " ";
if (func.self == execution.entry_point)
{
decl += "main";
processing_entry_point = true;
}
else
decl += to_name(func.self);
if (func.self == execution.entry_point)
{
decl += "main";
processing_entry_point = true;
}
else
decl += to_name(func.self);
decl += "(";
for (auto &arg : func.arguments)
{
add_local_variable(arg.id);
decl += "(";
for (auto &arg : func.arguments)
{
add_local_variable(arg.id);
decl += argument_decl(arg);
if (&arg != &func.arguments.back())
decl += ", ";
decl += argument_decl(arg);
if (&arg != &func.arguments.back())
decl += ", ";
// Hold a pointer to the parameter so we can invalidate the readonly field if needed.
auto *var = maybe_get<SPIRVariable>(arg.id);
if (var)
var->parameter = &arg;
}
// Hold a pointer to the parameter so we can invalidate the readonly field if needed.
auto *var = maybe_get<SPIRVariable>(arg.id);
if (var)
var->parameter = &arg;
}
decl += ")";
statement(decl);
decl += ")";
statement(decl);
}
string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
{
auto &type = expression_type(arg.id);
bool constref = !type.pointer || arg.write_count == 0;
auto &type = expression_type(arg.id);
bool constref = !type.pointer || arg.write_count == 0;
auto &var = get<SPIRVariable>(arg.id);
return join(constref ? "const " : "",
type_to_glsl(type), "& ", to_name(var.self), type_to_array_glsl(type));
auto &var = get<SPIRVariable>(arg.id);
return join(constref ? "const " : "", type_to_glsl(type), "& ", to_name(var.self), type_to_array_glsl(type));
}
void CompilerCPP::emit_header()
{
statement("// This C++ shader is autogenerated by spirv-cross.");
statement("#include \"spirv_cross/internal_interface.hpp\"");
statement("#include \"spirv_cross/external_interface.h\"");
statement("#include <stdint.h>");
statement("");
statement("using namespace spirv_cross;");
statement("using namespace glm;");
statement("");
statement("// This C++ shader is autogenerated by spirv-cross.");
statement("#include \"spirv_cross/internal_interface.hpp\"");
statement("#include \"spirv_cross/external_interface.h\"");
statement("#include <stdint.h>");
statement("");
statement("using namespace spirv_cross;");
statement("using namespace glm;");
statement("");
statement("namespace Impl");
begin_scope();
statement("namespace Impl");
begin_scope();
switch (execution.model)
{
case ExecutionModelGeometry:
case ExecutionModelTessellationControl:
case ExecutionModelTessellationEvaluation:
case ExecutionModelGLCompute:
case ExecutionModelFragment:
case ExecutionModelVertex:
statement("struct Shader");
begin_scope();
break;
switch (execution.model)
{
case ExecutionModelGeometry:
case ExecutionModelTessellationControl:
case ExecutionModelTessellationEvaluation:
case ExecutionModelGLCompute:
case ExecutionModelFragment:
case ExecutionModelVertex:
statement("struct Shader");
begin_scope();
break;
default:
throw CompilerError("Unsupported execution model.");
}
default:
throw CompilerError("Unsupported execution model.");
}
switch (execution.model)
{
case ExecutionModelGeometry:
impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "GeometryResources";
break;
switch (execution.model)
{
case ExecutionModelGeometry:
impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "GeometryResources";
break;
case ExecutionModelVertex:
impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "VertexResources";
break;
case ExecutionModelVertex:
impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "VertexResources";
break;
case ExecutionModelFragment:
impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "FragmentResources";
break;
case ExecutionModelFragment:
impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "FragmentResources";
break;
case ExecutionModelGLCompute:
impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ",
execution.workgroup_size.x, ", ",
execution.workgroup_size.y, ", ",
execution.workgroup_size.z, ">");
resource_type = "ComputeResources";
break;
case ExecutionModelGLCompute:
impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
resource_type = "ComputeResources";
break;
case ExecutionModelTessellationControl:
impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "TessControlResources";
break;
case ExecutionModelTessellationControl:
impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "TessControlResources";
break;
case ExecutionModelTessellationEvaluation:
impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "TessEvaluationResources";
break;
case ExecutionModelTessellationEvaluation:
impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
resource_type = "TessEvaluationResources";
break;
default:
throw CompilerError("Unsupported execution model.");
}
default:
throw CompilerError("Unsupported execution model.");
}
}

View File

@ -22,32 +22,35 @@
namespace spirv_cross
{
class CompilerCPP : public CompilerGLSL
{
public:
CompilerCPP(std::vector<uint32_t> spirv_) : CompilerGLSL(move(spirv_)) {}
std::string compile() override;
class CompilerCPP : public CompilerGLSL
{
public:
CompilerCPP(std::vector<uint32_t> spirv_)
: CompilerGLSL(move(spirv_))
{
}
std::string compile() override;
private:
void emit_header() override;
void emit_c_linkage();
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
private:
void emit_header() override;
void emit_c_linkage();
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
void emit_resources();
void emit_buffer_block(const SPIRVariable &type);
void emit_push_constant_block(const SPIRVariable &var);
void emit_interface_block(const SPIRVariable &type);
void emit_block_chain(SPIRBlock &block);
void emit_uniform(const SPIRVariable &var);
void emit_shared(const SPIRVariable &var);
void emit_resources();
void emit_buffer_block(const SPIRVariable &type);
void emit_push_constant_block(const SPIRVariable &var);
void emit_interface_block(const SPIRVariable &type);
void emit_block_chain(SPIRBlock &block);
void emit_uniform(const SPIRVariable &var);
void emit_shared(const SPIRVariable &var);
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::vector<std::string> resource_registrations;
std::string impl_type;
std::string resource_type;
uint32_t shared_counter = 0;
};
std::vector<std::string> resource_registrations;
std::string impl_type;
std::string resource_type;
uint32_t shared_counter = 0;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -30,334 +30,337 @@
namespace spirv_cross
{
struct Resource
{
// Resources are identified with their SPIR-V ID.
// This is the ID of the OpVariable.
uint32_t id;
struct Resource
{
// Resources are identified with their SPIR-V ID.
// This is the ID of the OpVariable.
uint32_t id;
// The type of the declared resource.
uint32_t type_id;
// The type of the declared resource.
uint32_t type_id;
// The declared name (OpName) of the resource.
// For Buffer blocks, the name actually reflects the externally
// visible Block name.
//
// This name can be retrieved again by using either
// get_name(id) or get_name(type_id) depending if it's a buffer block or not.
//
// This name can be an empty string in which case get_fallback_name(id) can be
// used which obtains a suitable fallback identifier for an ID.
std::string name;
};
// The declared name (OpName) of the resource.
// For Buffer blocks, the name actually reflects the externally
// visible Block name.
//
// This name can be retrieved again by using either
// get_name(id) or get_name(type_id) depending if it's a buffer block or not.
//
// This name can be an empty string in which case get_fallback_name(id) can be
// used which obtains a suitable fallback identifier for an ID.
std::string name;
};
struct ShaderResources
{
std::vector<Resource> uniform_buffers;
std::vector<Resource> storage_buffers;
std::vector<Resource> stage_inputs;
std::vector<Resource> stage_outputs;
std::vector<Resource> subpass_inputs;
std::vector<Resource> storage_images;
std::vector<Resource> sampled_images;
std::vector<Resource> atomic_counters;
struct ShaderResources
{
std::vector<Resource> uniform_buffers;
std::vector<Resource> storage_buffers;
std::vector<Resource> stage_inputs;
std::vector<Resource> stage_outputs;
std::vector<Resource> subpass_inputs;
std::vector<Resource> storage_images;
std::vector<Resource> sampled_images;
std::vector<Resource> atomic_counters;
// There can only be one push constant block,
// but keep the vector in case this restriction is lifted in the future.
std::vector<Resource> push_constant_buffers;
};
// There can only be one push constant block,
// but keep the vector in case this restriction is lifted in the future.
std::vector<Resource> push_constant_buffers;
};
struct BufferRange
{
unsigned index;
size_t offset;
size_t range;
};
struct BufferRange
{
unsigned index;
size_t offset;
size_t range;
};
class Compiler
{
public:
// The constructor takes a buffer of SPIR-V words and parses it.
Compiler(std::vector<uint32_t> ir);
class Compiler
{
public:
// The constructor takes a buffer of SPIR-V words and parses it.
Compiler(std::vector<uint32_t> ir);
virtual ~Compiler() = default;
virtual ~Compiler() = default;
// After parsing, API users can modify the SPIR-V via reflection and call this
// to disassemble the SPIR-V into the desired langauage.
// Sub-classes actually implement this.
virtual std::string compile();
// After parsing, API users can modify the SPIR-V via reflection and call this
// to disassemble the SPIR-V into the desired langauage.
// Sub-classes actually implement this.
virtual std::string compile();
// Gets the identifier (OpName) of an ID. If not defined, an empty string will be returned.
const std::string& get_name(uint32_t id) const;
// Gets the identifier (OpName) of an ID. If not defined, an empty string will be returned.
const std::string &get_name(uint32_t id) const;
// Applies a decoration to an ID. Effectively injects OpDecorate.
void set_decoration(uint32_t id, spv::Decoration decoration, uint32_t argument = 0);
// Applies a decoration to an ID. Effectively injects OpDecorate.
void set_decoration(uint32_t id, spv::Decoration decoration, uint32_t argument = 0);
// Overrides the identifier OpName of an ID.
// Identifiers beginning with underscores or identifiers which contain double underscores
// are reserved by the implementation.
void set_name(uint32_t id, const std::string& name);
// Overrides the identifier OpName of an ID.
// Identifiers beginning with underscores or identifiers which contain double underscores
// are reserved by the implementation.
void set_name(uint32_t id, const std::string &name);
// Gets a bitmask for the decorations which are applied to ID.
// I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar)
uint64_t get_decoration_mask(uint32_t id) const;
// Gets a bitmask for the decorations which are applied to ID.
// I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar)
uint64_t get_decoration_mask(uint32_t id) const;
// Gets the value for decorations which take arguments.
// If decoration doesn't exist or decoration is not recognized,
// 0 will be returned.
uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const;
// Gets the value for decorations which take arguments.
// If decoration doesn't exist or decoration is not recognized,
// 0 will be returned.
uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const;
// Removes the decoration for a an ID.
void unset_decoration(uint32_t id, spv::Decoration decoration);
// Removes the decoration for a an ID.
void unset_decoration(uint32_t id, spv::Decoration decoration);
// Gets the SPIR-V associated with ID.
// Mostly used with Resource::type_id to parse the underlying type of a resource.
const SPIRType& get_type(uint32_t id) const;
// Gets the SPIR-V associated with ID.
// Mostly used with Resource::type_id to parse the underlying type of a resource.
const SPIRType &get_type(uint32_t id) const;
// Gets the underlying storage class for an OpVariable.
spv::StorageClass get_storage_class(uint32_t id) const;
// Gets the underlying storage class for an OpVariable.
spv::StorageClass get_storage_class(uint32_t id) const;
// If get_name() is an empty string, get the fallback name which will be used
// instead in the disassembled source.
virtual const std::string get_fallback_name(uint32_t id) const
{
return join("_", id);
}
// If get_name() is an empty string, get the fallback name which will be used
// instead in the disassembled source.
virtual const std::string get_fallback_name(uint32_t id) const
{
return join("_", id);
}
// Given an OpTypeStruct in ID, obtain the identifier for member number "index".
// This may be an empty string.
const std::string& get_member_name(uint32_t id, uint32_t index) const;
// Given an OpTypeStruct in ID, obtain the identifier for member number "index".
// This may be an empty string.
const std::string &get_member_name(uint32_t id, uint32_t index) const;
// Given an OpTypeStruct in ID, obtain the OpMemberDecoration for member number "index".
uint32_t get_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const;
// Given an OpTypeStruct in ID, obtain the OpMemberDecoration for member number "index".
uint32_t get_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const;
// Sets the member identifier for OpTypeStruct ID, member number "index".
void set_member_name(uint32_t id, uint32_t index, const std::string& name);
// Sets the member identifier for OpTypeStruct ID, member number "index".
void set_member_name(uint32_t id, uint32_t index, const std::string &name);
// Gets the decoration mask for a member of a struct, similar to get_decoration_mask.
uint64_t get_member_decoration_mask(uint32_t id, uint32_t index) const;
// Gets the decoration mask for a member of a struct, similar to get_decoration_mask.
uint64_t get_member_decoration_mask(uint32_t id, uint32_t index) const;
// Similar to set_decoration, but for struct members.
void set_member_decoration(uint32_t id, uint32_t index,
spv::Decoration decoration, uint32_t argument = 0);
// Similar to set_decoration, but for struct members.
void set_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0);
// Unsets a member decoration, similar to unset_decoration.
void unset_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration);
// Unsets a member decoration, similar to unset_decoration.
void unset_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration);
// Gets the fallback name for a member, similar to get_fallback_name.
virtual const std::string get_fallback_member_name(uint32_t index) const
{
return join("_", index);
}
// Gets the fallback name for a member, similar to get_fallback_name.
virtual const std::string get_fallback_member_name(uint32_t index) const
{
return join("_", index);
}
// Returns a vector of which members of a struct are potentially in use by a
// SPIR-V shader. The granularity of this analysis is per-member of a struct.
// This can be used for Buffer (UBO), BufferBlock (SSBO) and PushConstant blocks.
// ID is the Resource::id obtained from get_shader_resources().
std::vector<BufferRange> get_active_buffer_ranges(unsigned id) const;
// Returns a vector of which members of a struct are potentially in use by a
// SPIR-V shader. The granularity of this analysis is per-member of a struct.
// This can be used for Buffer (UBO), BufferBlock (SSBO) and PushConstant blocks.
// ID is the Resource::id obtained from get_shader_resources().
std::vector<BufferRange> get_active_buffer_ranges(uint32_t id) const;
// Returns the effective size of a buffer block.
size_t get_declared_struct_size(const SPIRType &struct_type) const;
// Returns the effective size of a buffer block.
size_t get_declared_struct_size(const SPIRType &struct_type) const;
// Returns the effective size of a buffer block struct member.
virtual size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
// Returns the effective size of a buffer block struct member.
virtual size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
// Legacy GLSL compatibility method.
// Takes a variable with a block interface and flattens it into a T array[N]; array instead.
// For this to work, all types in the block must not themselves be composites
// (except vectors and matrices), and all types must be the same.
// The name of the uniform will be the same as the interface block name.
void flatten_interface_block(uint32_t id);
// Legacy GLSL compatibility method.
// Takes a variable with a block interface and flattens it into a T array[N]; array instead.
// For this to work, all types in the block must not themselves be composites
// (except vectors and matrices), and all types must be the same.
// The name of the uniform will be the same as the interface block name.
void flatten_interface_block(uint32_t id);
// Query shader resources, use ids with reflection interface to modify or query binding points, etc.
ShaderResources get_shader_resources() const;
// Query shader resources, use ids with reflection interface to modify or query binding points, etc.
ShaderResources get_shader_resources() const;
protected:
const uint32_t* stream(const Instruction &instr) const
{
// If we're not going to use any arguments, just return nullptr.
// We want to avoid case where we return an out of range pointer
// that trips debug assertions on some platforms.
if (!instr.length)
return nullptr;
protected:
const uint32_t *stream(const Instruction &instr) const
{
// If we're not going to use any arguments, just return nullptr.
// We want to avoid case where we return an out of range pointer
// that trips debug assertions on some platforms.
if (!instr.length)
return nullptr;
if (instr.offset + instr.length > spirv.size())
throw CompilerError("Compiler::stream() out of range.");
return &spirv[instr.offset];
}
std::vector<uint32_t> spirv;
if (instr.offset + instr.length > spirv.size())
throw CompilerError("Compiler::stream() out of range.");
return &spirv[instr.offset];
}
std::vector<uint32_t> spirv;
std::vector<Instruction> inst;
std::vector<Variant> ids;
std::vector<Meta> meta;
std::vector<Instruction> inst;
std::vector<Variant> ids;
std::vector<Meta> meta;
SPIRFunction *current_function = nullptr;
SPIRBlock *current_block = nullptr;
std::vector<uint32_t> global_variables;
std::vector<uint32_t> aliased_variables;
SPIRFunction *current_function = nullptr;
SPIRBlock *current_block = nullptr;
std::vector<uint32_t> global_variables;
std::vector<uint32_t> aliased_variables;
// If our IDs are out of range here as part of opcodes, throw instead of
// undefined behavior.
template<typename T, typename... P>
T& set(uint32_t id, P&&... args)
{
auto &var = variant_set<T>(ids.at(id), std::forward<P>(args)...);
var.self = id;
return var;
}
// If our IDs are out of range here as part of opcodes, throw instead of
// undefined behavior.
template <typename T, typename... P>
T &set(uint32_t id, P &&... args)
{
auto &var = variant_set<T>(ids.at(id), std::forward<P>(args)...);
var.self = id;
return var;
}
template<typename T>
T& get(uint32_t id)
{
return variant_get<T>(ids.at(id));
}
template <typename T>
T &get(uint32_t id)
{
return variant_get<T>(ids.at(id));
}
template<typename T>
T* maybe_get(uint32_t id)
{
if (ids.at(id).get_type() == T::type)
return &get<T>(id);
else
return nullptr;
}
template <typename T>
T *maybe_get(uint32_t id)
{
if (ids.at(id).get_type() == T::type)
return &get<T>(id);
else
return nullptr;
}
template<typename T>
const T& get(uint32_t id) const
{
return variant_get<T>(ids.at(id));
}
template <typename T>
const T &get(uint32_t id) const
{
return variant_get<T>(ids.at(id));
}
template<typename T>
const T* maybe_get(uint32_t id) const
{
if (ids.at(id).get_type() == T::type)
return &get<T>(id);
else
return nullptr;
}
template <typename T>
const T *maybe_get(uint32_t id) const
{
if (ids.at(id).get_type() == T::type)
return &get<T>(id);
else
return nullptr;
}
struct Execution
{
uint64_t flags = 0;
spv::ExecutionModel model;
uint32_t entry_point = 0;
struct
{
uint32_t x = 0, y = 0, z = 0;
} workgroup_size;
uint32_t invocations = 0;
uint32_t output_vertices = 0;
struct Execution
{
uint64_t flags = 0;
spv::ExecutionModel model;
uint32_t entry_point = 0;
struct
{
uint32_t x = 0, y = 0, z = 0;
} workgroup_size;
uint32_t invocations = 0;
uint32_t output_vertices = 0;
Execution() = default;
} execution;
Execution() = default;
} execution;
struct Source
{
uint32_t version = 0;
bool es = false;
bool known = false;
struct Source
{
uint32_t version = 0;
bool es = false;
bool known = false;
Source() = default;
} source;
Source() = default;
} source;
std::unordered_set<uint32_t> loop_blocks;
std::unordered_set<uint32_t> continue_blocks;
std::unordered_set<uint32_t> loop_merge_targets;
std::unordered_set<uint32_t> selection_merge_targets;
std::unordered_set<uint32_t> multiselect_merge_targets;
std::unordered_set<uint32_t> loop_blocks;
std::unordered_set<uint32_t> continue_blocks;
std::unordered_set<uint32_t> loop_merge_targets;
std::unordered_set<uint32_t> selection_merge_targets;
std::unordered_set<uint32_t> multiselect_merge_targets;
std::string to_name(uint32_t id);
bool is_builtin_variable(const SPIRVariable &var) const;
bool is_immutable(uint32_t id) const;
bool is_member_builtin(const SPIRType &type, uint32_t index, spv::BuiltIn *builtin) const;
bool is_scalar(const SPIRType &type) const;
bool is_vector(const SPIRType &type) const;
bool is_matrix(const SPIRType &type) const;
const SPIRType& expression_type(uint32_t id) const;
bool expression_is_lvalue(uint32_t id) const;
bool variable_storage_is_aliased(const SPIRVariable &var);
SPIRVariable* maybe_get_backing_variable(uint32_t chain);
std::string to_name(uint32_t id);
bool is_builtin_variable(const SPIRVariable &var) const;
bool is_immutable(uint32_t id) const;
bool is_member_builtin(const SPIRType &type, uint32_t index, spv::BuiltIn *builtin) const;
bool is_scalar(const SPIRType &type) const;
bool is_vector(const SPIRType &type) const;
bool is_matrix(const SPIRType &type) const;
const SPIRType &expression_type(uint32_t id) const;
bool expression_is_lvalue(uint32_t id) const;
bool variable_storage_is_aliased(const SPIRVariable &var);
SPIRVariable *maybe_get_backing_variable(uint32_t chain);
void register_read(uint32_t expr, uint32_t chain, bool forwarded);
void register_write(uint32_t chain);
void register_read(uint32_t expr, uint32_t chain, bool forwarded);
void register_write(uint32_t chain);
inline bool is_continue(uint32_t next) const
{
return continue_blocks.find(next) != end(continue_blocks);
}
inline bool is_continue(uint32_t next) const
{
return continue_blocks.find(next) != end(continue_blocks);
}
inline bool is_break(uint32_t next) const
{
return loop_merge_targets.find(next) != end(loop_merge_targets) ||
multiselect_merge_targets.find(next) != end(multiselect_merge_targets);
}
inline bool is_break(uint32_t next) const
{
return loop_merge_targets.find(next) != end(loop_merge_targets) ||
multiselect_merge_targets.find(next) != end(multiselect_merge_targets);
}
inline bool is_conditional(uint32_t next) const
{
return selection_merge_targets.find(next) != end(selection_merge_targets) &&
multiselect_merge_targets.find(next) == end(multiselect_merge_targets);
}
inline bool is_conditional(uint32_t next) const
{
return selection_merge_targets.find(next) != end(selection_merge_targets) &&
multiselect_merge_targets.find(next) == end(multiselect_merge_targets);
}
// Dependency tracking for temporaries read from variables.
void flush_dependees(SPIRVariable &var);
void flush_all_active_variables();
void flush_all_atomic_capable_variables();
void flush_all_aliased_variables();
void register_global_read_dependencies(const SPIRBlock &func, uint32_t id);
void register_global_read_dependencies(const SPIRFunction &func, uint32_t id);
std::unordered_set<uint32_t> invalid_expressions;
// Dependency tracking for temporaries read from variables.
void flush_dependees(SPIRVariable &var);
void flush_all_active_variables();
void flush_all_atomic_capable_variables();
void flush_all_aliased_variables();
void register_global_read_dependencies(const SPIRBlock &func, uint32_t id);
void register_global_read_dependencies(const SPIRFunction &func, uint32_t id);
std::unordered_set<uint32_t> invalid_expressions;
void update_name_cache(std::unordered_set<std::string> &cache, std::string &name);
std::unordered_set<std::string> global_struct_cache;
void update_name_cache(std::unordered_set<std::string> &cache, std::string &name);
std::unordered_set<std::string> global_struct_cache;
bool function_is_pure(const SPIRFunction &func);
bool block_is_pure(const SPIRBlock &block);
bool block_is_outside_flow_control_from_block(const SPIRBlock &from, const SPIRBlock &to);
bool function_is_pure(const SPIRFunction &func);
bool block_is_pure(const SPIRBlock &block);
bool block_is_outside_flow_control_from_block(const SPIRBlock &from, const SPIRBlock &to);
bool execution_is_branchless(const SPIRBlock &from, const SPIRBlock &to) const;
bool execution_is_noop(const SPIRBlock &from, const SPIRBlock &to) const;
SPIRBlock::ContinueBlockType continue_block_type(const SPIRBlock &continue_block) const;
bool execution_is_branchless(const SPIRBlock &from, const SPIRBlock &to) const;
bool execution_is_noop(const SPIRBlock &from, const SPIRBlock &to) const;
SPIRBlock::ContinueBlockType continue_block_type(const SPIRBlock &continue_block) const;
bool force_recompile = false;
bool force_recompile = false;
uint32_t type_struct_member_offset(const SPIRType &type, uint32_t index) const;
uint32_t type_struct_member_array_stride(const SPIRType &type, uint32_t index) const;
uint32_t type_struct_member_offset(const SPIRType &type, uint32_t index) const;
uint32_t type_struct_member_array_stride(const SPIRType &type, uint32_t index) const;
bool block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const;
bool block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const;
uint32_t increase_bound_by(uint32_t incr_amount);
uint32_t increase_bound_by(uint32_t incr_amount);
private:
void parse();
void parse(const Instruction &i);
private:
void parse();
void parse(const Instruction &i);
// Used internally to implement various traversals for queries.
struct OpcodeHandler
{
virtual ~OpcodeHandler() = default;
// Used internally to implement various traversals for queries.
struct OpcodeHandler
{
virtual ~OpcodeHandler() = default;
// Return true if traversal should continue.
// If false, traversal will end immediately.
virtual bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) = 0;
};
// Return true if traversal should continue.
// If false, traversal will end immediately.
virtual bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) = 0;
};
struct BufferAccessHandler : OpcodeHandler
{
BufferAccessHandler(const Compiler &compiler_, std::vector<BufferRange> &ranges_, unsigned id_)
: compiler(compiler_), ranges(ranges_), id(id_) {}
struct BufferAccessHandler : OpcodeHandler
{
BufferAccessHandler(const Compiler &compiler_, std::vector<BufferRange> &ranges_, uint32_t id_)
: compiler(compiler_)
, ranges(ranges_)
, id(id_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
const Compiler &compiler;
std::vector<BufferRange> &ranges;
uint32_t id;
const Compiler &compiler;
std::vector<BufferRange> &ranges;
uint32_t id;
std::unordered_set<uint32_t> seen;
};
std::unordered_set<uint32_t> seen;
};
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
};
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -25,275 +25,287 @@
namespace spirv_cross
{
enum PlsFormat
{
PlsNone = 0,
enum PlsFormat
{
PlsNone = 0,
PlsR11FG11FB10F,
PlsR32F,
PlsRG16F,
PlsRGB10A2,
PlsRGBA8,
PlsRG16,
PlsR11FG11FB10F,
PlsR32F,
PlsRG16F,
PlsRGB10A2,
PlsRGBA8,
PlsRG16,
PlsRGBA8I,
PlsRG16I,
PlsRGBA8I,
PlsRG16I,
PlsRGB10A2UI,
PlsRGBA8UI,
PlsRG16UI,
PlsR32UI
};
PlsRGB10A2UI,
PlsRGBA8UI,
PlsRG16UI,
PlsR32UI
};
struct PlsRemap
{
uint32_t id;
PlsFormat format;
};
struct PlsRemap
{
uint32_t id;
PlsFormat format;
};
class CompilerGLSL : public Compiler
{
public:
struct Options
{
uint32_t version = 450;
bool es = false;
bool force_temporary = false;
class CompilerGLSL : public Compiler
{
public:
struct Options
{
uint32_t version = 450;
bool es = false;
bool force_temporary = false;
enum Precision
{
DontCare,
Lowp,
Mediump,
Highp
};
enum Precision
{
DontCare,
Lowp,
Mediump,
Highp
};
struct
{
// In vertex shaders, rewrite [0, w] depth (Vulkan/D3D style) to [-w, w] depth (GL style).
bool fixup_clipspace = true;
} vertex;
struct
{
// In vertex shaders, rewrite [0, w] depth (Vulkan/D3D style) to [-w, w] depth (GL style).
bool fixup_clipspace = true;
} vertex;
struct
{
// Add precision mediump float in ES targets when emitting GLES source.
// Add precision highp int in ES targets when emitting GLES source.
Precision default_float_precision = Mediump;
Precision default_int_precision = Highp;
} fragment;
};
struct
{
// Add precision mediump float in ES targets when emitting GLES source.
// Add precision highp int in ES targets when emitting GLES source.
Precision default_float_precision = Mediump;
Precision default_int_precision = Highp;
} fragment;
};
void remap_pixel_local_storage(std::vector<PlsRemap> inputs, std::vector<PlsRemap> outputs)
{
pls_inputs = std::move(inputs);
pls_outputs = std::move(outputs);
remap_pls_variables();
}
void remap_pixel_local_storage(std::vector<PlsRemap> inputs, std::vector<PlsRemap> outputs)
{
pls_inputs = std::move(inputs);
pls_outputs = std::move(outputs);
remap_pls_variables();
}
CompilerGLSL(std::vector<uint32_t> spirv_) : Compiler(move(spirv_))
{
if (source.known)
{
options.es = source.es;
options.version = source.version;
}
}
CompilerGLSL(std::vector<uint32_t> spirv_)
: Compiler(move(spirv_))
{
if (source.known)
{
options.es = source.es;
options.version = source.version;
}
}
const Options& get_options() const { return options; }
void set_options(Options &opts) { options = opts; }
std::string compile() override;
const Options &get_options() const
{
return options;
}
void set_options(Options &opts)
{
options = opts;
}
std::string compile() override;
protected:
void reset();
void emit_function(SPIRFunction &func, uint64_t return_flags);
protected:
void reset();
void emit_function(SPIRFunction &func, uint64_t return_flags);
// Virtualize methods which need to be overridden by subclass targets like C++ and such.
virtual void emit_function_prototype(SPIRFunction &func, uint64_t return_flags);
virtual void emit_header();
virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
virtual void emit_texture_op(const Instruction &i);
virtual std::string type_to_glsl(const SPIRType &type);
virtual std::string builtin_to_glsl(spv::BuiltIn builtin);
virtual std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member);
virtual std::string image_type_glsl(const SPIRType &type);
virtual std::string constant_expression(const SPIRConstant &c);
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
virtual void emit_fixup();
// Virtualize methods which need to be overridden by subclass targets like C++ and such.
virtual void emit_function_prototype(SPIRFunction &func, uint64_t return_flags);
virtual void emit_header();
virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
virtual void emit_texture_op(const Instruction &i);
virtual std::string type_to_glsl(const SPIRType &type);
virtual std::string builtin_to_glsl(spv::BuiltIn builtin);
virtual std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member);
virtual std::string image_type_glsl(const SPIRType &type);
virtual std::string constant_expression(const SPIRConstant &c);
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
virtual void emit_fixup();
std::unique_ptr<std::ostringstream> buffer;
std::unique_ptr<std::ostringstream> buffer;
template<typename T>
inline void statement_inner(T&& t)
{
(*buffer) << std::forward<T>(t);
statement_count++;
}
template <typename T>
inline void statement_inner(T &&t)
{
(*buffer) << std::forward<T>(t);
statement_count++;
}
template<typename T, typename... Ts>
inline void statement_inner(T&& t, Ts&&... ts)
{
(*buffer) << std::forward<T>(t);
statement_count++;
statement_inner(std::forward<Ts>(ts)...);
}
template <typename T, typename... Ts>
inline void statement_inner(T &&t, Ts &&... ts)
{
(*buffer) << std::forward<T>(t);
statement_count++;
statement_inner(std::forward<Ts>(ts)...);
}
template<typename... Ts>
inline void statement(Ts&&... ts)
{
if (redirect_statement)
redirect_statement->push_back(join(std::forward<Ts>(ts)...));
else
{
for (uint32_t i = 0; i < indent; i++)
(*buffer) << " ";
template <typename... Ts>
inline void statement(Ts &&... ts)
{
if (redirect_statement)
redirect_statement->push_back(join(std::forward<Ts>(ts)...));
else
{
for (uint32_t i = 0; i < indent; i++)
(*buffer) << " ";
statement_inner(std::forward<Ts>(ts)...);
(*buffer) << '\n';
}
}
statement_inner(std::forward<Ts>(ts)...);
(*buffer) << '\n';
}
}
template<typename... Ts>
inline void statement_no_indent(Ts&&... ts)
{
auto old_indent = indent;
indent = 0;
statement(std::forward<Ts>(ts)...);
indent = old_indent;
}
template <typename... Ts>
inline void statement_no_indent(Ts &&... ts)
{
auto old_indent = indent;
indent = 0;
statement(std::forward<Ts>(ts)...);
indent = old_indent;
}
// Used for implementing continue blocks where
// we want to obtain a list of statements we can merge
// on a single line separated by comma.
std::vector<std::string> *redirect_statement = nullptr;
const SPIRBlock *current_continue_block = nullptr;
// Used for implementing continue blocks where
// we want to obtain a list of statements we can merge
// on a single line separated by comma.
std::vector<std::string> *redirect_statement = nullptr;
const SPIRBlock *current_continue_block = nullptr;
void begin_scope();
void end_scope();
void end_scope_decl();
void end_scope_decl(const std::string &decl);
void begin_scope();
void end_scope();
void end_scope_decl();
void end_scope_decl(const std::string &decl);
Options options;
Options options;
std::string type_to_array_glsl(const SPIRType &type);
std::string variable_decl(const SPIRVariable &variable);
std::string type_to_array_glsl(const SPIRType &type);
std::string variable_decl(const SPIRVariable &variable);
void add_local_variable(uint32_t id);
std::unordered_set<std::string> local_variables;
void add_local_variable(uint32_t id);
std::unordered_set<std::string> local_variables;
bool processing_entry_point = false;
bool processing_entry_point = false;
// Can be overriden by subclass backends for trivial things which
// shouldn't need polymorphism.
struct BackendVariations
{
bool float_literal_suffix = false;
bool uint32_t_literal_suffix = true;
const char *basic_int_type = "int";
const char *basic_uint_type = "uint";
bool swizzle_is_function = false;
bool shared_is_implied = false;
} backend;
// Can be overriden by subclass backends for trivial things which
// shouldn't need polymorphism.
struct BackendVariations
{
bool float_literal_suffix = false;
bool uint32_t_literal_suffix = true;
const char *basic_int_type = "int";
const char *basic_uint_type = "uint";
bool swizzle_is_function = false;
bool shared_is_implied = false;
} backend;
void emit_struct(const SPIRType &type);
void emit_instruction(const Instruction &instr);
void emit_struct(const SPIRType &type);
void emit_instruction(const Instruction &instr);
protected:
protected:
void emit_resources();
void emit_buffer_block(const SPIRVariable &type);
void emit_push_constant_block(const SPIRVariable &var);
void emit_interface_block(const SPIRVariable &type);
void emit_block_chain(SPIRBlock &block);
std::string emit_continue_block(uint32_t continue_block);
bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method);
void emit_uniform(const SPIRVariable &var);
void propagate_loop_dominators(const SPIRBlock &block);
void emit_resources();
void emit_buffer_block(const SPIRVariable &type);
void emit_push_constant_block(const SPIRVariable &var);
void emit_interface_block(const SPIRVariable &type);
void emit_block_chain(SPIRBlock &block);
std::string emit_continue_block(uint32_t continue_block);
bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method);
void emit_uniform(const SPIRVariable &var);
void propagate_loop_dominators(const SPIRBlock &block);
void branch(uint32_t from, uint32_t to);
void branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block);
void flush_phi(uint32_t from, uint32_t to);
bool flush_phi_required(uint32_t from, uint32_t to);
void flush_variable_declaration(uint32_t id);
void flush_undeclared_variables();
void branch(uint32_t from, uint32_t to);
void branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block);
void flush_phi(uint32_t from, uint32_t to);
bool flush_phi_required(uint32_t from, uint32_t to);
void flush_variable_declaration(uint32_t id);
void flush_undeclared_variables();
bool should_forward(uint32_t id);
void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp);
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, uint32_t count);
void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
uint32_t op3, const char *op);
void emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
const char *op);
void emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
bool expression_is_forwarded(uint32_t id);
SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
bool extra_parens, bool suppress_usage_tracking = false);
std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal,
bool chain_only = false);
bool should_forward(uint32_t id);
void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp);
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, uint32_t count);
void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, uint32_t op3, const char *op);
void emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, const char *op);
void emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
bool expression_is_forwarded(uint32_t id);
SPIRExpression& emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs, bool extra_parens, bool suppress_usage_tracking = false);
std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal, bool chain_only = false);
const char *index_to_swizzle(uint32_t index);
std::string remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr);
std::string declare_temporary(uint32_t type, uint32_t id);
std::string to_expression(uint32_t id);
std::string to_member_name(const SPIRType &type, uint32_t index);
std::string type_to_glsl_constructor(const SPIRType &type);
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::string to_qualifiers_glsl(uint32_t id);
const char *to_precision_qualifiers_glsl(uint32_t id);
const char *flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags);
const char *format_to_glsl(spv::ImageFormat format);
std::string layout_for_member(const SPIRType &type, uint32_t index);
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
std::string layout_for_variable(const SPIRVariable &variable);
const char* index_to_swizzle(uint32_t index);
std::string remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr);
std::string declare_temporary(uint32_t type, uint32_t id);
std::string to_expression(uint32_t id);
std::string to_member_name(const SPIRType &type, uint32_t index);
std::string type_to_glsl_constructor(const SPIRType &type);
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::string to_qualifiers_glsl(uint32_t id);
const char* to_precision_qualifiers_glsl(uint32_t id);
const char* flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags);
const char* format_to_glsl(spv::ImageFormat format);
std::string layout_for_member(const SPIRType &type, uint32_t index);
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
std::string layout_for_variable(const SPIRVariable &variable);
bool ssbo_is_std430_packing(const SPIRType &type);
uint32_t type_to_std430_alignment(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_array_stride(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_size(const SPIRType &type, uint64_t flags);
bool ssbo_is_std430_packing(const SPIRType &type);
uint32_t type_to_std430_alignment(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_array_stride(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_size(const SPIRType &type, uint64_t flags);
std::string bitcast_glsl(uint32_t result_type, uint32_t arg);
std::string bitcast_glsl_op(uint32_t result_type, uint32_t arg);
std::string build_composite_combiner(const uint32_t *elems, uint32_t length);
bool remove_duplicate_swizzle(std::string &op);
bool remove_unity_swizzle(uint32_t base, std::string &op);
std::string bitcast_glsl(uint32_t result_type, uint32_t arg);
std::string bitcast_glsl_op(uint32_t result_type, uint32_t arg);
std::string build_composite_combiner(const uint32_t *elems, uint32_t length);
bool remove_duplicate_swizzle(std::string &op);
bool remove_unity_swizzle(uint32_t base, std::string &op);
// Can modify flags to remote readonly/writeonly if image type
// and force recompile.
bool check_atomic_image(uint32_t id);
void require_extension(const std::string &ext);
// Can modify flags to remote readonly/writeonly if image type
// and force recompile.
bool check_atomic_image(uint32_t id);
void require_extension(const std::string &ext);
void replace_fragment_output(SPIRVariable &var);
void replace_fragment_outputs();
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype);
void replace_fragment_output(SPIRVariable &var);
void replace_fragment_outputs();
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype);
uint32_t indent = 0;
uint32_t indent = 0;
std::unordered_set<uint32_t> emitted_functions;
std::unordered_set<uint32_t> emitted_functions;
// Usage tracking. If a temporary is used more than once, use the temporary instead to
// avoid AST explosion when SPIRV is generated with pure SSA and doesn't write stuff to variables.
std::unordered_map<uint32_t, uint32_t> expression_usage_counts;
std::unordered_set<uint32_t> forced_temporaries;
std::unordered_set<uint32_t> forwarded_temporaries;
void track_expression_read(uint32_t id);
// Usage tracking. If a temporary is used more than once, use the temporary instead to
// avoid AST explosion when SPIRV is generated with pure SSA and doesn't write stuff to variables.
std::unordered_map<uint32_t, uint32_t> expression_usage_counts;
std::unordered_set<uint32_t> forced_temporaries;
std::unordered_set<uint32_t> forwarded_temporaries;
void track_expression_read(uint32_t id);
std::unordered_set<std::string> forced_extensions;
std::unordered_set<std::string> forced_extensions;
uint32_t statement_count;
uint32_t statement_count;
inline bool is_legacy() const
{
return (options.es && options.version < 300) || (!options.es && options.version < 130);
}
inline bool is_legacy() const { return (options.es && options.version < 300) || (!options.es && options.version < 130); }
bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure);
void register_call_out_argument(uint32_t id);
void register_impure_function_call();
bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure);
void register_call_out_argument(uint32_t id);
void register_impure_function_call();
// GL_EXT_shader_pixel_local_storage support.
std::vector<PlsRemap> pls_inputs;
std::vector<PlsRemap> pls_outputs;
std::string pls_decl(const PlsRemap &variable);
const char* to_pls_qualifiers_glsl(const SPIRVariable &variable);
void emit_pls();
void remap_pls_variables();
};
// GL_EXT_shader_pixel_local_storage support.
std::vector<PlsRemap> pls_inputs;
std::vector<PlsRemap> pls_outputs;
std::string pls_decl(const PlsRemap &variable);
const char *to_pls_qualifiers_glsl(const SPIRVariable &variable);
void emit_pls();
void remap_pls_variables();
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -21,149 +21,149 @@
#include <vector>
#include <set>
namespace spirv_cross
{
namespace spirv_cross {
// Options for compiling to Metal Shading Language
struct MSLConfiguration
{
uint32_t vtx_attr_stage_in_binding = 0;
bool flip_vert_y = true;
bool flip_frag_y = true;
bool is_rendering_points = false;
};
// Options for compiling to Metal Shading Language
struct MSLConfiguration
{
uint32_t vtx_attr_stage_in_binding= 0;
bool flip_vert_y = true;
bool flip_frag_y =true;
bool is_rendering_points = false;
};
// Defines MSL characteristics of a vertex attribute at a particular location.
// The used_by_shader flag is set to true during compilation of SPIR-V to MSL
// if the shader makes use of this vertex attribute.
struct MSLVertexAttr
{
uint32_t location = 0;
uint32_t msl_buffer = 0;
uint32_t msl_offset = 0;
uint32_t msl_stride = 0;
bool per_instance = false;
bool used_by_shader = false;
};
// Defines MSL characteristics of a vertex attribute at a particular location.
// The used_by_shader flag is set to true during compilation of SPIR-V to MSL
// if the shader makes use of this vertex attribute.
struct MSLVertexAttr
{
uint32_t location = 0;
uint32_t msl_buffer = 0;
uint32_t msl_offset = 0;
uint32_t msl_stride = 0;
bool per_instance = false;
bool used_by_shader = false;
};
// Matches the binding index of a MSL resource for a binding within a descriptor set.
// Taken together, the stage, desc_set and binding combine to form a reference to a resource
// descriptor used in a particular shading stage. Generally, only one of the buffer, texture,
// or sampler elements will be populated. The used_by_shader flag is set to true during
// compilation of SPIR-V to MSL if the shader makes use of this vertex attribute.
struct MSLResourceBinding
{
spv::ExecutionModel stage;
uint32_t desc_set = 0;
uint32_t binding = 0;
// Matches the binding index of a MSL resource for a binding within a descriptor set.
// Taken together, the stage, desc_set and binding combine to form a reference to a resource
// descriptor used in a particular shading stage. Generally, only one of the buffer, texture,
// or sampler elements will be populated. The used_by_shader flag is set to true during
// compilation of SPIR-V to MSL if the shader makes use of this vertex attribute.
struct MSLResourceBinding
{
spv::ExecutionModel stage;
uint32_t desc_set = 0;
uint32_t binding = 0;
uint32_t msl_buffer = 0;
uint32_t msl_texture = 0;
uint32_t msl_sampler = 0;
uint32_t msl_buffer = 0;
uint32_t msl_texture = 0;
uint32_t msl_sampler = 0;
bool used_by_shader = false;
};
bool used_by_shader = false;
};
// Special constant used in a MSLResourceBinding desc_set
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstDescSet = UINT32_MAX;
// Special constant used in a MSLResourceBinding desc_set
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstDescSet = UINT32_MAX;
// Special constant used in a MSLResourceBinding binding
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstBinding = 0;
// Special constant used in a MSLResourceBinding binding
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstBinding = 0;
// Decompiles SPIR-V to Metal Shading Language
class CompilerMSL : public CompilerGLSL
{
public:
// Constructs an instance to compile the SPIR-V code into Metal Shading Language.
CompilerMSL(std::vector<uint32_t> spirv);
// Compiles the SPIR-V code into Metal Shading Language using the specified configuration parameters.
// - msl_cfg indicates some general configuration for directing the compilation.
// - p_vtx_attrs is an optional list of vertex attribute bindings used to match
// vertex content locations to MSL attributes. If vertex attributes are provided,
// the compiler will set the used_by_shader flag to true in any vertex attribute
// actually used by the MSL code.
// - p_res_bindings is a list of resource bindings to indicate the MSL buffer,
// texture or sampler index to use for a particular SPIR-V description set
// and binding. If resource bindings are provided, the compiler will set the
// used_by_shader flag to true in any resource binding actually used by the MSL code.
std::string compile(MSLConfiguration &msl_cfg, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
std::vector<MSLResourceBinding> *p_res_bindings = nullptr);
// Decompiles SPIR-V to Metal Shading Language
class CompilerMSL : public CompilerGLSL
{
public:
// Compiles the SPIR-V code into Metal Shading Language using default configuration parameters.
std::string compile() override;
// Constructs an instance to compile the SPIR-V code into Metal Shading Language.
CompilerMSL(std::vector<uint32_t> spirv);
protected:
void emit_header() override;
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
void emit_texture_op(const Instruction &i) override;
void emit_fixup() override;
std::string type_to_glsl(const SPIRType &type) override;
std::string image_type_glsl(const SPIRType &type) override;
std::string builtin_to_glsl(spv::BuiltIn builtin) override;
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member) override;
std::string constant_expression(const SPIRConstant &c) override;
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
// Compiles the SPIR-V code into Metal Shading Language using the specified configuration parameters.
// - msl_cfg indicates some general configuration for directing the compilation.
// - p_vtx_attrs is an optional list of vertex attribute bindings used to match
// vertex content locations to MSL attributes. If vertex attributes are provided,
// the compiler will set the used_by_shader flag to true in any vertex attribute
// actually used by the MSL code.
// - p_res_bindings is a list of resource bindings to indicate the MSL buffer,
// texture or sampler index to use for a particular SPIR-V description set
// and binding. If resource bindings are provided, the compiler will set the
// used_by_shader flag to true in any resource binding actually used by the MSL code.
std::string compile(MSLConfiguration& msl_cfg,
std::vector<MSLVertexAttr>* p_vtx_attrs = nullptr,
std::vector<MSLResourceBinding>* p_res_bindings = nullptr);
void extract_builtins();
void localize_global_variables();
void add_interface_structs();
void bind_vertex_attributes(std::set<uint32_t> &bindings);
uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0);
void emit_resources();
void emit_interface_block(uint32_t ib_var_id);
void emit_function_prototype(SPIRFunction &func, bool is_decl);
void emit_function_declarations();
// Compiles the SPIR-V code into Metal Shading Language using default configuration parameters.
std::string compile() override;
std::string func_type_decl(SPIRType &type);
std::string clean_func_name(std::string func_name);
std::string entry_point_args(bool append_comma);
std::string get_entry_point_name();
std::string to_sampler_expression(uint32_t id);
std::string builtin_qualifier(spv::BuiltIn builtin);
std::string builtin_type_decl(spv::BuiltIn builtin);
std::string member_attribute_qualifier(const SPIRType &type, uint32_t index);
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::string get_vtx_idx_var_name(bool per_instance);
uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype);
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
uint32_t pad_to_offset(SPIRType &struct_type, uint32_t offset, uint32_t struct_size);
SPIRType &get_pad_type(uint32_t pad_len);
size_t get_declared_type_size(const SPIRType &type) const;
size_t get_declared_type_size(const SPIRType &type, uint64_t dec_mask) const;
protected:
void emit_header() override;
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
void emit_texture_op(const Instruction &i) override;
void emit_fixup() override;
std::string type_to_glsl(const SPIRType &type) override;
std::string image_type_glsl(const SPIRType &type) override;
std::string builtin_to_glsl(spv::BuiltIn builtin) override;
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member) override;
std::string constant_expression(const SPIRConstant &c) override;
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
void extract_builtins();
void localize_global_variables();
void add_interface_structs();
void bind_vertex_attributes(std::set<uint32_t>& bindings);
uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0);
void emit_resources();
void emit_interface_block(uint32_t ib_var_id);
void emit_function_prototype(SPIRFunction &func, bool is_decl);
void emit_function_declarations();
std::string func_type_decl(SPIRType& type);
std::string clean_func_name(std::string func_name);
std::string entry_point_args(bool append_comma);
std::string get_entry_point_name();
std::string to_sampler_expression(uint32_t id);
std::string builtin_qualifier(spv::BuiltIn builtin);
std::string builtin_type_decl(spv::BuiltIn builtin);
std::string member_attribute_qualifier(const SPIRType &type, uint32_t index);
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::string get_vtx_idx_var_name(bool per_instance);
uint32_t get_metal_resource_index(SPIRVariable& var, SPIRType::BaseType basetype);
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
uint32_t pad_to_offset(SPIRType& struct_type, uint32_t offset, uint32_t struct_size);
SPIRType& get_pad_type(uint32_t pad_len);
size_t get_declared_type_size(const SPIRType& type) const;
size_t get_declared_type_size(const SPIRType& type, uint64_t dec_mask) const;
MSLConfiguration msl_config;
std::unordered_map<uint32_t, MSLVertexAttr*> vtx_attrs_by_location;
std::vector<MSLResourceBinding*> resource_bindings;
std::unordered_map<uint32_t, uint32_t> builtin_vars;
MSLResourceBinding next_metal_resource_index;
std::unordered_map<uint32_t, uint32_t> pad_type_ids_by_pad_len;
std::vector<uint32_t> stage_in_var_ids;
uint32_t stage_out_var_id = 0;
std::string qual_pos_var_name;
std::string stage_in_var_name = "in";
std::string stage_out_var_name = "out";
std::string sampler_name_suffix = "Smplr";
};
// Sorts the members of a SPIRType and associated Meta info based on the location
// and builtin decorations of the members. Members are rearranged by location,
// with all builtin members appearing a the end.
struct MemberSorterByLocation
{
void sort();
bool operator() (uint32_t mbr_idx1,uint32_t mbr_idx2);
MemberSorterByLocation(SPIRType& t, Meta& m) : type(t), meta(m) {}
SPIRType& type;
Meta& meta;
};
MSLConfiguration msl_config;
std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location;
std::vector<MSLResourceBinding *> resource_bindings;
std::unordered_map<uint32_t, uint32_t> builtin_vars;
MSLResourceBinding next_metal_resource_index;
std::unordered_map<uint32_t, uint32_t> pad_type_ids_by_pad_len;
std::vector<uint32_t> stage_in_var_ids;
uint32_t stage_out_var_id = 0;
std::string qual_pos_var_name;
std::string stage_in_var_name = "in";
std::string stage_out_var_name = "out";
std::string sampler_name_suffix = "Smplr";
};
// Sorts the members of a SPIRType and associated Meta info based on the location
// and builtin decorations of the members. Members are rearranged by location,
// with all builtin members appearing a the end.
struct MemberSorterByLocation
{
void sort();
bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
MemberSorterByLocation(SPIRType &t, Meta &m)
: type(t)
, meta(m)
{
}
SPIRType &type;
Meta &meta;
};
}
#endif