diff options
Diffstat (limited to 'src/3rdparty/SPIRV-Cross/spirv_common.hpp')
| -rw-r--r-- | src/3rdparty/SPIRV-Cross/spirv_common.hpp | 430 |
1 files changed, 317 insertions, 113 deletions
diff --git a/src/3rdparty/SPIRV-Cross/spirv_common.hpp b/src/3rdparty/SPIRV-Cross/spirv_common.hpp index 0cf1f56..c1c6fc8 100644 --- a/src/3rdparty/SPIRV-Cross/spirv_common.hpp +++ b/src/3rdparty/SPIRV-Cross/spirv_common.hpp @@ -20,6 +20,7 @@ #include "spirv.hpp" #include "spirv_cross_containers.hpp" #include "spirv_cross_error_handling.hpp" +#include <functional> // A bit crude, but allows projects which embed SPIRV-Cross statically to // effectively hide all the symbols from other projects. @@ -183,14 +184,14 @@ std::string join(Ts &&... ts) return stream.str(); } -inline std::string merge(const SmallVector<std::string> &list) +inline std::string merge(const SmallVector<std::string> &list, const char *between = ", ") { StringStream<> stream; for (auto &elem : list) { stream << elem; if (&elem != &list.back()) - stream << ", "; + stream << between; } return stream.str(); } @@ -270,20 +271,6 @@ struct Instruction uint32_t length = 0; }; -// Helper for Variant interface. -struct IVariant -{ - virtual ~IVariant() = default; - virtual IVariant *clone(ObjectPoolBase *pool) = 0; - uint32_t self = 0; -}; - -#define SPIRV_CROSS_DECLARE_CLONE(T) \ - IVariant *clone(ObjectPoolBase *pool) override \ - { \ - return static_cast<ObjectPool<T> *>(pool)->allocate(*this); \ - } - enum Types { TypeNone, @@ -299,9 +286,140 @@ enum Types TypeCombinedImageSampler, TypeAccessChain, TypeUndef, + TypeString, TypeCount }; +template <Types type> +class TypedID; + +template <> +class TypedID<TypeNone> +{ +public: + TypedID() = default; + TypedID(uint32_t id_) + : id(id_) + { + } + + template <Types U> + TypedID(const TypedID<U> &other) + { + *this = other; + } + + template <Types U> + TypedID &operator=(const TypedID<U> &other) + { + id = uint32_t(other); + return *this; + } + + // Implicit conversion to u32 is desired here. + // As long as we block implicit conversion between TypedID<A> and TypedID<B> we're good. + operator uint32_t() const + { + return id; + } + + template <Types U> + operator TypedID<U>() const + { + return TypedID<U>(*this); + } + + bool operator==(const TypedID &other) const + { + return id == other.id; + } + + bool operator!=(const TypedID &other) const + { + return id != other.id; + } + + template <Types type> + bool operator==(const TypedID<type> &other) const + { + return id == uint32_t(other); + } + + template <Types type> + bool operator!=(const TypedID<type> &other) const + { + return id != uint32_t(other); + } + +private: + uint32_t id = 0; +}; + +template <Types type> +class TypedID +{ +public: + TypedID() = default; + TypedID(uint32_t id_) + : id(id_) + { + } + + explicit TypedID(const TypedID<TypeNone> &other) + : id(uint32_t(other)) + { + } + + operator uint32_t() const + { + return id; + } + + bool operator==(const TypedID &other) const + { + return id == other.id; + } + + bool operator!=(const TypedID &other) const + { + return id != other.id; + } + + bool operator==(const TypedID<TypeNone> &other) const + { + return id == uint32_t(other); + } + + bool operator!=(const TypedID<TypeNone> &other) const + { + return id != uint32_t(other); + } + +private: + uint32_t id = 0; +}; + +using VariableID = TypedID<TypeVariable>; +using TypeID = TypedID<TypeType>; +using ConstantID = TypedID<TypeConstant>; +using FunctionID = TypedID<TypeFunction>; +using BlockID = TypedID<TypeBlock>; +using ID = TypedID<TypeNone>; + +// Helper for Variant interface. +struct IVariant +{ + virtual ~IVariant() = default; + virtual IVariant *clone(ObjectPoolBase *pool) = 0; + ID self = 0; +}; + +#define SPIRV_CROSS_DECLARE_CLONE(T) \ + IVariant *clone(ObjectPoolBase *pool) override \ + { \ + return static_cast<ObjectPool<T> *>(pool)->allocate(*this); \ + } + struct SPIRUndef : IVariant { enum @@ -309,15 +427,32 @@ struct SPIRUndef : IVariant type = TypeUndef }; - explicit SPIRUndef(uint32_t basetype_) + explicit SPIRUndef(TypeID basetype_) : basetype(basetype_) { } - uint32_t basetype; + TypeID basetype; SPIRV_CROSS_DECLARE_CLONE(SPIRUndef) }; +struct SPIRString : IVariant +{ + enum + { + type = TypeString + }; + + explicit SPIRString(std::string str_) + : str(std::move(str_)) + { + } + + std::string str; + + SPIRV_CROSS_DECLARE_CLONE(SPIRString) +}; + // This type is only used by backends which need to access the combined image and sampler IDs separately after // the OpSampledImage opcode. struct SPIRCombinedImageSampler : IVariant @@ -326,15 +461,15 @@ struct SPIRCombinedImageSampler : IVariant { type = TypeCombinedImageSampler }; - SPIRCombinedImageSampler(uint32_t type_, uint32_t image_, uint32_t sampler_) + SPIRCombinedImageSampler(TypeID type_, VariableID image_, VariableID sampler_) : combined_type(type_) , image(image_) , sampler(sampler_) { } - uint32_t combined_type; - uint32_t image; - uint32_t sampler; + TypeID combined_type; + VariableID image; + VariableID sampler; SPIRV_CROSS_DECLARE_CLONE(SPIRCombinedImageSampler) }; @@ -346,16 +481,18 @@ struct SPIRConstantOp : IVariant type = TypeConstantOp }; - SPIRConstantOp(uint32_t result_type, spv::Op op, const uint32_t *args, uint32_t length) + SPIRConstantOp(TypeID result_type, spv::Op op, const uint32_t *args, uint32_t length) : opcode(op) - , arguments(args, args + length) , basetype(result_type) { + arguments.reserve(length); + for (uint32_t i = 0; i < length; i++) + arguments.push_back(args[i]); } spv::Op opcode; SmallVector<uint32_t> arguments; - uint32_t basetype; + TypeID basetype; SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp) }; @@ -418,11 +555,11 @@ struct SPIRType : IVariant spv::StorageClass storage = spv::StorageClassGeneric; - SmallVector<uint32_t> member_types; + SmallVector<TypeID> member_types; struct ImageType { - uint32_t type; + TypeID type; spv::Dim dim; bool depth; bool arrayed; @@ -435,11 +572,11 @@ struct SPIRType : IVariant // Structs can be declared multiple times if they are used as part of interface blocks. // We want to detect this so that we only emit the struct definition once. // Since we cannot rely on OpName to be equal, we need to figure out aliases. - uint32_t type_alias = 0; + TypeID type_alias = 0; // Denotes the type which this type is based on. // Allows the backend to traverse how a complex type is built up during access chains. - uint32_t parent_type = 0; + TypeID parent_type = 0; // Used in backends to avoid emitting members with conflicting names. std::unordered_set<std::string> member_name_cache; @@ -458,6 +595,7 @@ struct SPIRExtension : IVariant { Unsupported, GLSL, + SPV_debug_info, SPV_AMD_shader_ballot, SPV_AMD_shader_explicit_vertex_parameter, SPV_AMD_shader_trinary_minmax, @@ -477,7 +615,7 @@ struct SPIRExtension : IVariant // so in order to avoid conflicts, we can't stick them in the ids array. struct SPIREntryPoint { - SPIREntryPoint(uint32_t self_, spv::ExecutionModel execution_model, const std::string &entry_name) + SPIREntryPoint(FunctionID self_, spv::ExecutionModel execution_model, const std::string &entry_name) : self(self_) , name(entry_name) , orig_name(entry_name) @@ -486,10 +624,10 @@ struct SPIREntryPoint } SPIREntryPoint() = default; - uint32_t self = 0; + FunctionID self = 0; std::string name; std::string orig_name; - SmallVector<uint32_t> interface_variables; + SmallVector<VariableID> interface_variables; Bitset flags; struct @@ -510,7 +648,7 @@ struct SPIRExpression : IVariant }; // Only created by the backend target to avoid creating tons of temporaries. - SPIRExpression(std::string expr, uint32_t expression_type_, bool immutable_) + SPIRExpression(std::string expr, TypeID expression_type_, bool immutable_) : expression(move(expr)) , expression_type(expression_type_) , immutable(immutable_) @@ -520,14 +658,14 @@ struct SPIRExpression : IVariant // If non-zero, prepend expression with to_expression(base_expression). // Used in amortizing multiple calls to to_expression() // where in certain cases that would quickly force a temporary when not needed. - uint32_t base_expression = 0; + ID base_expression = 0; std::string expression; - uint32_t expression_type = 0; + TypeID expression_type = 0; // If this expression is a forwarded load, // allow us to reference the original variable. - uint32_t loaded_from = 0; + ID loaded_from = 0; // If this expression will never change, we can avoid lots of temporaries // in high level source. @@ -543,11 +681,11 @@ struct SPIRExpression : IVariant bool access_chain = false; // A list of expressions which this expression depends on. - SmallVector<uint32_t> expression_dependencies; + SmallVector<ID> expression_dependencies; // By reading this expression, we implicitly read these expressions as well. // Used by access chain Store and Load since we read multiple expressions in this case. - SmallVector<uint32_t> implied_read_expressions; + SmallVector<ID> implied_read_expressions; SPIRV_CROSS_DECLARE_CLONE(SPIRExpression) }; @@ -559,12 +697,12 @@ struct SPIRFunctionPrototype : IVariant type = TypeFunctionPrototype }; - explicit SPIRFunctionPrototype(uint32_t return_type_) + explicit SPIRFunctionPrototype(TypeID return_type_) : return_type(return_type_) { } - uint32_t return_type; + TypeID return_type; SmallVector<uint32_t> parameter_types; SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype) @@ -639,23 +777,23 @@ struct SPIRBlock : IVariant Terminator terminator = Unknown; Merge merge = MergeNone; Hints hint = HintNone; - uint32_t next_block = 0; - uint32_t merge_block = 0; - uint32_t continue_block = 0; + BlockID next_block = 0; + BlockID merge_block = 0; + BlockID continue_block = 0; - uint32_t return_value = 0; // If 0, return nothing (void). - uint32_t condition = 0; - uint32_t true_block = 0; - uint32_t false_block = 0; - uint32_t default_block = 0; + ID return_value = 0; // If 0, return nothing (void). + ID condition = 0; + BlockID true_block = 0; + BlockID false_block = 0; + BlockID default_block = 0; SmallVector<Instruction> ops; struct Phi { - uint32_t local_variable; // flush local variable ... - uint32_t parent; // If we're in from_block and want to branch into this block ... - uint32_t function_variable; // to this function-global "phi" variable first. + ID local_variable; // flush local variable ... + BlockID parent; // If we're in from_block and want to branch into this block ... + VariableID function_variable; // to this function-global "phi" variable first. }; // Before entering this block flush out local variables to magical "phi" variables. @@ -663,16 +801,16 @@ struct SPIRBlock : IVariant // Declare these temporaries before beginning the block. // Used for handling complex continue blocks which have side effects. - SmallVector<std::pair<uint32_t, uint32_t>> declare_temporary; + SmallVector<std::pair<TypeID, ID>> declare_temporary; // Declare these temporaries, but only conditionally if this block turns out to be // a complex loop header. - SmallVector<std::pair<uint32_t, uint32_t>> potential_declare_temporary; + SmallVector<std::pair<TypeID, ID>> potential_declare_temporary; struct Case { uint32_t value; - uint32_t block; + BlockID block; }; SmallVector<Case> cases; @@ -686,23 +824,27 @@ struct SPIRBlock : IVariant // Do we need a ladder variable to defer breaking out of a loop construct after a switch block? bool need_ladder_break = false; + // If marked, we have explicitly handled Phi from this block, so skip any flushes related to that on a branch. + // Used to handle an edge case with switch and case-label fallthrough where fall-through writes to Phi. + BlockID ignore_phi_from_block = 0; + // The dominating block which this block might be within. // Used in continue; blocks to determine if we really need to write continue. - uint32_t loop_dominator = 0; + BlockID loop_dominator = 0; // All access to these variables are dominated by this block, // so before branching anywhere we need to make sure that we declare these variables. - SmallVector<uint32_t> dominated_variables; + SmallVector<VariableID> dominated_variables; // These are variables which should be declared in a for loop header, if we // fail to use a classic for-loop, // we remove these variables, and fall back to regular variables outside the loop. - SmallVector<uint32_t> loop_variables; + SmallVector<VariableID> loop_variables; // Some expressions are control-flow dependent, i.e. any instruction which relies on derivatives or // sub-group-like operations. // Make sure that we only use these expressions in the original block. - SmallVector<uint32_t> invalidate_expressions; + SmallVector<ID> invalidate_expressions; SPIRV_CROSS_DECLARE_CLONE(SPIRBlock) }; @@ -714,7 +856,7 @@ struct SPIRFunction : IVariant type = TypeFunction }; - SPIRFunction(uint32_t return_type_, uint32_t function_type_) + SPIRFunction(TypeID return_type_, TypeID function_type_) : return_type(return_type_) , function_type(function_type_) { @@ -722,8 +864,8 @@ struct SPIRFunction : IVariant struct Parameter { - uint32_t type; - uint32_t id; + TypeID type; + ID id; uint32_t read_count; uint32_t write_count; @@ -745,33 +887,40 @@ struct SPIRFunction : IVariant // or a global ID. struct CombinedImageSamplerParameter { - uint32_t id; - uint32_t image_id; - uint32_t sampler_id; + VariableID id; + VariableID image_id; + VariableID sampler_id; bool global_image; bool global_sampler; bool depth; }; - uint32_t return_type; - uint32_t function_type; + TypeID return_type; + TypeID function_type; SmallVector<Parameter> arguments; // Can be used by backends to add magic arguments. // Currently used by combined image/sampler implementation. SmallVector<Parameter> shadow_arguments; - SmallVector<uint32_t> local_variables; - uint32_t entry_block = 0; - SmallVector<uint32_t> blocks; + SmallVector<VariableID> local_variables; + BlockID entry_block = 0; + SmallVector<BlockID> blocks; SmallVector<CombinedImageSamplerParameter> combined_parameters; - void add_local_variable(uint32_t id) + struct EntryLine + { + uint32_t file_id = 0; + uint32_t line_literal = 0; + }; + EntryLine entry_line; + + void add_local_variable(VariableID id) { local_variables.push_back(id); } - void add_parameter(uint32_t parameter_type, uint32_t id, bool alias_global_variable = false) + void add_parameter(TypeID parameter_type, ID id, bool alias_global_variable = false) { // Arguments are read-only until proven otherwise. arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable }); @@ -792,7 +941,7 @@ struct SPIRFunction : IVariant // On function entry, make sure to copy a constant array into thread addr space to work around // the case where we are passing a constant array by value to a function on backends which do not // consider arrays value types. - SmallVector<uint32_t> constant_arrays_needed_on_stack; + SmallVector<ID> constant_arrays_needed_on_stack; bool active = false; bool flush_undeclared = true; @@ -808,7 +957,7 @@ struct SPIRAccessChain : IVariant type = TypeAccessChain }; - SPIRAccessChain(uint32_t basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_, + SPIRAccessChain(TypeID basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_, int32_t static_index_) : basetype(basetype_) , storage(storage_) @@ -823,20 +972,20 @@ struct SPIRAccessChain : IVariant // which has no usable buffer type ala GLSL SSBOs. // StructuredBuffer is too limited, so our only option is to deal with ByteAddressBuffer which works with raw addresses. - uint32_t basetype; + TypeID basetype; spv::StorageClass storage; std::string base; std::string dynamic_index; int32_t static_index; - uint32_t loaded_from = 0; + VariableID loaded_from = 0; uint32_t matrix_stride = 0; bool row_major_matrix = false; bool immutable = false; // By reading this expression, we implicitly read these expressions as well. // Used by access chain Store and Load since we read multiple expressions in this case. - SmallVector<uint32_t> implied_read_expressions; + SmallVector<ID> implied_read_expressions; SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain) }; @@ -849,7 +998,7 @@ struct SPIRVariable : IVariant }; SPIRVariable() = default; - SPIRVariable(uint32_t basetype_, spv::StorageClass storage_, uint32_t initializer_ = 0, uint32_t basevariable_ = 0) + SPIRVariable(TypeID basetype_, spv::StorageClass storage_, ID initializer_ = 0, VariableID basevariable_ = 0) : basetype(basetype_) , storage(storage_) , initializer(initializer_) @@ -857,11 +1006,11 @@ struct SPIRVariable : IVariant { } - uint32_t basetype = 0; + TypeID basetype = 0; spv::StorageClass storage = spv::StorageClassGeneric; uint32_t decoration = 0; - uint32_t initializer = 0; - uint32_t basevariable = 0; + ID initializer = 0; + VariableID basevariable = 0; SmallVector<uint32_t> dereference_chain; bool compat_builtin = false; @@ -871,10 +1020,10 @@ struct SPIRVariable : IVariant // When we read the variable as an expression, just forward // shadowed_id as the expression. bool statically_assigned = false; - uint32_t static_expression = 0; + ID static_expression = 0; // Temporaries which can remain forwarded as long as this variable is not modified. - SmallVector<uint32_t> dependees; + SmallVector<ID> dependees; bool forwardable = true; bool deferred_declaration = false; @@ -887,7 +1036,7 @@ struct SPIRVariable : IVariant uint32_t remapped_components = 0; // The block which dominates all access to this variable. - uint32_t dominator = 0; + BlockID dominator = 0; // If true, this variable is a loop variable, when accessing the variable // outside a loop, // we should statically forward it. @@ -907,7 +1056,8 @@ struct SPIRConstant : IVariant type = TypeConstant }; - union Constant { + union Constant + { uint32_t u32; int32_t i32; float f32; @@ -921,15 +1071,12 @@ struct SPIRConstant : IVariant { Constant r[4]; // If != 0, this element is a specialization constant, and we should keep track of it as such. - uint32_t id[4]; + ID id[4]; uint32_t vecsize = 1; - // Workaround for MSVC 2013, initializing an array breaks. ConstantVector() { memset(r, 0, sizeof(r)); - for (unsigned i = 0; i < 4; i++) - id[i] = 0; } }; @@ -937,15 +1084,8 @@ struct SPIRConstant : IVariant { ConstantVector c[4]; // If != 0, this column is a specialization constant, and we should keep track of it as such. - uint32_t id[4]; + ID id[4]; uint32_t columns = 1; - - // Workaround for MSVC 2013, initializing an array breaks. - ConstantMatrix() - { - for (unsigned i = 0; i < 4; i++) - id[i] = 0; - } }; static inline float f16_to_f32(uint16_t u16_value) @@ -955,7 +1095,8 @@ struct SPIRConstant : IVariant int e = (u16_value >> 10) & 0x1f; int m = (u16_value >> 0) & 0x3ff; - union { + union + { float f32; uint32_t u32; } u; @@ -1109,16 +1250,18 @@ struct SPIRConstant : IVariant SPIRConstant() = default; - SPIRConstant(uint32_t constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized) + SPIRConstant(TypeID constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized) : constant_type(constant_type_) , specialization(specialized) { - subconstants.insert(std::end(subconstants), elements, elements + num_elements); + subconstants.reserve(num_elements); + for (uint32_t i = 0; i < num_elements; i++) + subconstants.push_back(elements[i]); specialization = specialized; } // Construct scalar (32-bit). - SPIRConstant(uint32_t constant_type_, uint32_t v0, bool specialized) + SPIRConstant(TypeID constant_type_, uint32_t v0, bool specialized) : constant_type(constant_type_) , specialization(specialized) { @@ -1128,7 +1271,7 @@ struct SPIRConstant : IVariant } // Construct scalar (64-bit). - SPIRConstant(uint32_t constant_type_, uint64_t v0, bool specialized) + SPIRConstant(TypeID constant_type_, uint64_t v0, bool specialized) : constant_type(constant_type_) , specialization(specialized) { @@ -1138,7 +1281,7 @@ struct SPIRConstant : IVariant } // Construct vectors and matrices. - SPIRConstant(uint32_t constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements, + SPIRConstant(TypeID constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements, bool specialized) : constant_type(constant_type_) , specialization(specialized) @@ -1170,7 +1313,7 @@ struct SPIRConstant : IVariant } } - uint32_t constant_type = 0; + TypeID constant_type = 0; ConstantMatrix m; // If this constant is a specialization constant (i.e. created with OpSpecConstant*). @@ -1182,7 +1325,7 @@ struct SPIRConstant : IVariant bool is_used_as_lut = false; // For composites which are constant arrays, etc. - SmallVector<uint32_t> subconstants; + SmallVector<ConstantID> subconstants; // Non-Vulkan GLSL, HLSL and sometimes MSL emits defines for each specialization constant, // and uses them to initialize the constant. This allows the user @@ -1317,9 +1460,9 @@ public: return type; } - uint32_t get_id() const + ID get_id() const { - return holder ? holder->self : 0; + return holder ? holder->self : ID(0); } bool empty() const @@ -1368,12 +1511,57 @@ T &variant_set(Variant &var, P &&... args) struct AccessChainMeta { - uint32_t storage_packed_type = 0; + uint32_t storage_physical_type = 0; bool need_transpose = false; bool storage_is_packed = false; bool storage_is_invariant = false; }; +enum ExtendedDecorations +{ + // Marks if a buffer block is re-packed, i.e. member declaration might be subject to PhysicalTypeID remapping and padding. + SPIRVCrossDecorationBufferBlockRepacked = 0, + + // A type in a buffer block might be declared with a different physical type than the logical type. + // If this is not set, PhysicalTypeID == the SPIR-V type as declared. + SPIRVCrossDecorationPhysicalTypeID, + + // Marks if the physical type is to be declared with tight packing rules, i.e. packed_floatN on MSL and friends. + // If this is set, PhysicalTypeID might also be set. It can be set to same as logical type if all we're doing + // is converting float3 to packed_float3 for example. + // If this is marked on a struct, it means the struct itself must use only Packed types for all its members. + SPIRVCrossDecorationPhysicalTypePacked, + + // The padding in bytes before declaring this struct member. + // If used on a struct type, marks the target size of a struct. + SPIRVCrossDecorationPaddingTarget, + + SPIRVCrossDecorationInterfaceMemberIndex, + SPIRVCrossDecorationInterfaceOrigID, + SPIRVCrossDecorationResourceIndexPrimary, + // Used for decorations like resource indices for samplers when part of combined image samplers. + // A variable might need to hold two resource indices in this case. + SPIRVCrossDecorationResourceIndexSecondary, + // Used for resource indices for multiplanar images when part of combined image samplers. + SPIRVCrossDecorationResourceIndexTertiary, + SPIRVCrossDecorationResourceIndexQuaternary, + + // Marks a buffer block for using explicit offsets (GLSL/HLSL). + SPIRVCrossDecorationExplicitOffset, + + // Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase(). + // In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables. + SPIRVCrossDecorationBuiltInDispatchBase, + + // Apply to a variable that is a function parameter; marks it as being a "dynamic" + // combined image-sampler. In MSL, this is used when a function parameter might hold + // either a regular combined image-sampler or one that has an attached sampler + // Y'CbCr conversion. + SPIRVCrossDecorationDynamicImageSampler, + + SPIRVCrossDecorationCount +}; + struct Meta { struct Decoration @@ -1396,13 +1584,17 @@ struct Meta spv::FPRoundingMode fp_rounding_mode = spv::FPRoundingModeMax; bool builtin = false; - struct + struct Extended { - uint32_t packed_type = 0; - bool packed = false; - uint32_t ib_member_index = ~(0u); - uint32_t ib_orig_id = 0; - uint32_t argument_buffer_id = ~(0u); + Extended() + { + // MSVC 2013 workaround to init like this. + for (auto &v : values) + v = 0; + } + + Bitset flags; + uint32_t values[SPIRVCrossDecorationCount]; } extended; }; @@ -1510,4 +1702,16 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode) } } // namespace SPIRV_CROSS_NAMESPACE +namespace std +{ +template <SPIRV_CROSS_NAMESPACE::Types type> +struct hash<SPIRV_CROSS_NAMESPACE::TypedID<type>> +{ + size_t operator()(const SPIRV_CROSS_NAMESPACE::TypedID<type> &value) const + { + return std::hash<uint32_t>()(value); + } +}; +} // namespace std + #endif |
