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:
parent
9d4b5c0c59
commit
4b8ed53974
164
.clang-format
Executable file
164
.clang-format
Executable 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
|
@ -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
7
format_all.sh
Executable 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
1298
spirv_common.hpp
1298
spirv_common.hpp
File diff suppressed because it is too large
Load Diff
628
spirv_cpp.cpp
628
spirv_cpp.cpp
@ -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 ® : 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 ® : 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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
2933
spirv_cross.cpp
2933
spirv_cross.cpp
File diff suppressed because it is too large
Load Diff
531
spirv_cross.hpp
531
spirv_cross.hpp
@ -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
|
||||
|
7171
spirv_glsl.cpp
7171
spirv_glsl.cpp
File diff suppressed because it is too large
Load Diff
464
spirv_glsl.hpp
464
spirv_glsl.hpp
@ -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
|
||||
|
||||
|
2433
spirv_msl.cpp
2433
spirv_msl.cpp
File diff suppressed because it is too large
Load Diff
256
spirv_msl.hpp
256
spirv_msl.hpp
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user