diff --git a/3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h b/3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h new file mode 100644 index 000000000..b276b560c --- /dev/null +++ b/3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h @@ -0,0 +1,171 @@ +// Copyright (c) 2018-2024 The Khronos Group Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and/or associated documentation files (the "Materials"), +// to deal in the Materials without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Materials, and to permit persons to whom the +// Materials are furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Materials. +// +// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// +// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +// IN THE MATERIALS. + +#ifndef SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ +#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + NonSemanticShaderDebugInfo100Version = 100, + NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff +}; +enum { + NonSemanticShaderDebugInfo100Revision = 6, + NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100Instructions { + NonSemanticShaderDebugInfo100DebugInfoNone = 0, + NonSemanticShaderDebugInfo100DebugCompilationUnit = 1, + NonSemanticShaderDebugInfo100DebugTypeBasic = 2, + NonSemanticShaderDebugInfo100DebugTypePointer = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifier = 4, + NonSemanticShaderDebugInfo100DebugTypeArray = 5, + NonSemanticShaderDebugInfo100DebugTypeVector = 6, + NonSemanticShaderDebugInfo100DebugTypedef = 7, + NonSemanticShaderDebugInfo100DebugTypeFunction = 8, + NonSemanticShaderDebugInfo100DebugTypeEnum = 9, + NonSemanticShaderDebugInfo100DebugTypeComposite = 10, + NonSemanticShaderDebugInfo100DebugTypeMember = 11, + NonSemanticShaderDebugInfo100DebugTypeInheritance = 12, + NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13, + NonSemanticShaderDebugInfo100DebugTypeTemplate = 14, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15, + NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17, + NonSemanticShaderDebugInfo100DebugGlobalVariable = 18, + NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19, + NonSemanticShaderDebugInfo100DebugFunction = 20, + NonSemanticShaderDebugInfo100DebugLexicalBlock = 21, + NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22, + NonSemanticShaderDebugInfo100DebugScope = 23, + NonSemanticShaderDebugInfo100DebugNoScope = 24, + NonSemanticShaderDebugInfo100DebugInlinedAt = 25, + NonSemanticShaderDebugInfo100DebugLocalVariable = 26, + NonSemanticShaderDebugInfo100DebugInlinedVariable = 27, + NonSemanticShaderDebugInfo100DebugDeclare = 28, + NonSemanticShaderDebugInfo100DebugValue = 29, + NonSemanticShaderDebugInfo100DebugOperation = 30, + NonSemanticShaderDebugInfo100DebugExpression = 31, + NonSemanticShaderDebugInfo100DebugMacroDef = 32, + NonSemanticShaderDebugInfo100DebugMacroUndef = 33, + NonSemanticShaderDebugInfo100DebugImportedEntity = 34, + NonSemanticShaderDebugInfo100DebugSource = 35, + NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101, + NonSemanticShaderDebugInfo100DebugSourceContinued = 102, + NonSemanticShaderDebugInfo100DebugLine = 103, + NonSemanticShaderDebugInfo100DebugNoLine = 104, + NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105, + NonSemanticShaderDebugInfo100DebugStoragePath = 106, + NonSemanticShaderDebugInfo100DebugEntryPoint = 107, + NonSemanticShaderDebugInfo100DebugTypeMatrix = 108, + NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff +}; + + +enum NonSemanticShaderDebugInfo100DebugInfoFlags { + NonSemanticShaderDebugInfo100None = 0x0000, + NonSemanticShaderDebugInfo100FlagIsProtected = 0x01, + NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02, + NonSemanticShaderDebugInfo100FlagIsPublic = 0x03, + NonSemanticShaderDebugInfo100FlagIsLocal = 0x04, + NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08, + NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10, + NonSemanticShaderDebugInfo100FlagArtificial = 0x20, + NonSemanticShaderDebugInfo100FlagExplicit = 0x40, + NonSemanticShaderDebugInfo100FlagPrototyped = 0x80, + NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100, + NonSemanticShaderDebugInfo100FlagStaticMember = 0x200, + NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400, + NonSemanticShaderDebugInfo100FlagLValueReference = 0x800, + NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000, + NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000, + NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000, + NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000, + NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000, + NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000, + NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100BuildIdentifierFlags { + NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01, + NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding { + NonSemanticShaderDebugInfo100Unspecified = 0, + NonSemanticShaderDebugInfo100Address = 1, + NonSemanticShaderDebugInfo100Boolean = 2, + NonSemanticShaderDebugInfo100Float = 3, + NonSemanticShaderDebugInfo100Signed = 4, + NonSemanticShaderDebugInfo100SignedChar = 5, + NonSemanticShaderDebugInfo100Unsigned = 6, + NonSemanticShaderDebugInfo100UnsignedChar = 7, + NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugCompositeType { + NonSemanticShaderDebugInfo100Class = 0, + NonSemanticShaderDebugInfo100Structure = 1, + NonSemanticShaderDebugInfo100Union = 2, + NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugTypeQualifier { + NonSemanticShaderDebugInfo100ConstType = 0, + NonSemanticShaderDebugInfo100VolatileType = 1, + NonSemanticShaderDebugInfo100RestrictType = 2, + NonSemanticShaderDebugInfo100AtomicType = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugOperation { + NonSemanticShaderDebugInfo100Deref = 0, + NonSemanticShaderDebugInfo100Plus = 1, + NonSemanticShaderDebugInfo100Minus = 2, + NonSemanticShaderDebugInfo100PlusUconst = 3, + NonSemanticShaderDebugInfo100BitPiece = 4, + NonSemanticShaderDebugInfo100Swap = 5, + NonSemanticShaderDebugInfo100Xderef = 6, + NonSemanticShaderDebugInfo100StackValue = 7, + NonSemanticShaderDebugInfo100Constu = 8, + NonSemanticShaderDebugInfo100Fragment = 9, + NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugImportedEntity { + NonSemanticShaderDebugInfo100ImportedModule = 0, + NonSemanticShaderDebugInfo100ImportedDeclaration = 1, + NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff +}; + + +#ifdef __cplusplus +} +#endif + +#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ diff --git a/3rdparty/spirv-cross/spirv_common.hpp b/3rdparty/spirv-cross/spirv_common.hpp index f133586ae..cd06f754c 100644 --- a/3rdparty/spirv-cross/spirv_common.hpp +++ b/3rdparty/spirv-cross/spirv_common.hpp @@ -377,6 +377,7 @@ enum Types TypeAccessChain, TypeUndef, TypeString, + TypeDebugLocalVariable, TypeCount }; @@ -506,6 +507,18 @@ struct SPIRString : IVariant SPIRV_CROSS_DECLARE_CLONE(SPIRString) }; +struct SPIRDebugLocalVariable : IVariant +{ + enum + { + type = TypeDebugLocalVariable + }; + + uint32_t name_id; + + SPIRV_CROSS_DECLARE_CLONE(SPIRDebugLocalVariable) +}; + // 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 @@ -1163,6 +1176,9 @@ struct SPIRVariable : IVariant // Temporaries which can remain forwarded as long as this variable is not modified. SmallVector dependees; + // ShaderDebugInfo local variables attached to this variable via DebugDeclare + SmallVector debug_local_variables; + bool deferred_declaration = false; bool phi_variable = false; diff --git a/3rdparty/spirv-cross/spirv_cross.cpp b/3rdparty/spirv-cross/spirv_cross.cpp index 2204e3911..1031d3ff6 100644 --- a/3rdparty/spirv-cross/spirv_cross.cpp +++ b/3rdparty/spirv-cross/spirv_cross.cpp @@ -3611,7 +3611,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(Op op, const uint32_t * case OpCopyObject: { - // OpCopyObject copies the underlying non-pointer type, + // OpCopyObject copies the underlying non-pointer type, // so any temp variable should be declared using the underlying type. // If the type is a pointer, get its base type and overwrite the result type mapping. auto &type = compiler.get(result_type); @@ -5078,12 +5078,12 @@ std::string Compiler::get_remapped_declared_block_name(uint32_t id, bool fallbac bool Compiler::reflection_ssbo_instance_name_is_significant() const { - if (ir.source.known) + if (!ir.sources.empty() && ir.sources[0].known) { // UAVs from HLSL source tend to be declared in a way where the type is reused // but the instance name is significant, and that's the name we should report. // For GLSL, SSBOs each have their own block type as that's how GLSL is written. - return ir.source.hlsl; + return ir.sources[0].hlsl; } unordered_set ssbo_type_ids; diff --git a/3rdparty/spirv-cross/spirv_cross.hpp b/3rdparty/spirv-cross/spirv_cross.hpp index 06f2b73f1..f72d79979 100644 --- a/3rdparty/spirv-cross/spirv_cross.hpp +++ b/3rdparty/spirv-cross/spirv_cross.hpp @@ -549,6 +549,9 @@ public: return position_invariant; } + const ParsedIR &get_ir() const { return ir; } + uint32_t evaluate_constant_u32(uint32_t id) const; + protected: const uint32_t *stream(const Instruction &instr) const { @@ -1197,7 +1200,6 @@ protected: bool flush_phi_required(BlockID from, BlockID to) const; uint32_t evaluate_spec_constant_u32(const SPIRConstantOp &spec) const; - uint32_t evaluate_constant_u32(uint32_t id) const; bool is_vertex_like_shader() const; diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp index 84d2e23c0..bb9a5f58e 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp @@ -49,6 +49,7 @@ ParsedIR::ParsedIR() pool_group->pools[TypeAccessChain].reset(new ObjectPool); pool_group->pools[TypeUndef].reset(new ObjectPool); pool_group->pools[TypeString].reset(new ObjectPool); + pool_group->pools[TypeDebugLocalVariable].reset(new ObjectPool); } // Should have been default-implemented, but need this on MSVC 2013. @@ -78,7 +79,7 @@ ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT memory_model = other.memory_model; default_entry_point = other.default_entry_point; - source = other.source; + sources = std::move(other.sources); loop_iteration_depth_hard = other.loop_iteration_depth_hard; loop_iteration_depth_soft = other.loop_iteration_depth_soft; @@ -110,7 +111,7 @@ ParsedIR &ParsedIR::operator=(const ParsedIR &other) continue_block_to_loop_header = other.continue_block_to_loop_header; entry_points = other.entry_points; default_entry_point = other.default_entry_point; - source = other.source; + sources = other.sources; loop_iteration_depth_hard = other.loop_iteration_depth_hard; loop_iteration_depth_soft = other.loop_iteration_depth_soft; addressing_model = other.addressing_model; diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp index 0e825b4fd..b1e76f205 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp @@ -118,10 +118,25 @@ public: bool known = false; bool hlsl = false; + ID file_id = 0; // string + ID define_id = 0; // only non-zero for DebugSource + std::string source; + + struct Marker + { + ID line; // in source + ID col; // in source + ID offset; // in spirv stream + ID function_id; + ID block_id; + }; + + SmallVector line_markers; // sorted by line + Source() = default; }; - Source source; + std::vector sources; AddressingModel addressing_model = AddressingModelMax; MemoryModel memory_model = MemoryModelMax; @@ -233,7 +248,6 @@ public: uint32_t get_spirv_version() const; -private: template T &get(uint32_t id) { @@ -246,6 +260,7 @@ private: return variant_get(ids[id]); } +private: mutable uint32_t loop_iteration_depth_hard = 0; mutable uint32_t loop_iteration_depth_soft = 0; std::string empty_string; diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index f9ce6cb09..90fa14be9 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -206,10 +206,10 @@ static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard void CompilerGLSL::init() { - if (ir.source.known) + if (!ir.sources.empty() && ir.sources.front().known) { - options.es = ir.source.es; - options.version = ir.source.version; + options.es = ir.sources.front().es; + options.version = ir.sources.front().version; } // Query the locale to see what the decimal point is. @@ -1755,10 +1755,32 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f { uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing); - // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size, - // so that it is possible to pack other vectors into the last element. - if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct) - packed_size -= (4 - type.vecsize) * (type.width / 8); + if (packing_is_hlsl(packing)) + { + // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size, + // so that it is possible to pack other vectors into the last element. + if (type.basetype != SPIRType::Struct) + { + if (flags.get(DecorationRowMajor) && type.columns > 1) + packed_size -= (4 - type.columns) * (type.width / 8); + else + packed_size -= (4 - type.vecsize) * (type.width / 8); + } + else + { + const auto *base_type = &type; + while (is_array(*base_type)) + { + auto &new_type = get(base_type->parent_type); + if (!is_array(new_type)) + break; + base_type = &new_type; + } + + packed_size -= type_to_packed_array_stride(*base_type, flags, packing); + packed_size += type_to_packed_size(get(base_type->parent_type), flags, packing); + } + } return packed_size; } @@ -1777,15 +1799,27 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing); uint32_t alignment = max(packed_alignment, pad_alignment); - // The next member following a struct member is aligned to the base alignment of the struct that came before. - // GL 4.5 spec, 7.6.2.2. - if (member_type.basetype == SPIRType::Struct) - pad_alignment = packed_alignment; + uint32_t element_size = type_to_packed_size(member_type, member_flags, packing); + pad_alignment = 1; + + if (packing_is_hlsl(packing)) + { + // HLSL is primarily a "cannot-straddle-vec4" language. + uint32_t begin_word = size / 16; + uint32_t end_word = (size + element_size - 1) / 16; + if (begin_word != end_word) + alignment = max(alignment, 16u); + } else - pad_alignment = 1; + { + // The next member following a struct member is aligned to the base alignment of the struct that came before. + // GL 4.5 spec, 7.6.2.2. + if (member_type.basetype == SPIRType::Struct) + pad_alignment = packed_alignment; + } size = (size + alignment - 1) & ~(alignment - 1); - size += type_to_packed_size(member_type, member_flags, packing); + size += element_size; } } else @@ -1803,9 +1837,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f if (flags.get(DecorationColMajor) && type.columns > 1) { - if (packing_is_vec4_padded(packing)) - size = type.columns * 4 * base_alignment; - else if (type.vecsize == 3) + if (packing_is_vec4_padded(packing) || type.vecsize == 3) size = type.columns * 4 * base_alignment; else size = type.columns * type.vecsize * base_alignment; @@ -1813,9 +1845,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f if (flags.get(DecorationRowMajor) && type.vecsize > 1) { - if (packing_is_vec4_padded(packing)) - size = type.vecsize * 4 * base_alignment; - else if (type.columns == 3) + if (packing_is_vec4_padded(packing) || type.columns == 3) size = type.vecsize * 4 * base_alignment; else size = type.vecsize * type.columns * base_alignment; @@ -1824,7 +1854,12 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f // For matrices in HLSL, the last element has a size which depends on its vector size, // so that it is possible to pack other vectors into the last element. if (packing_is_hlsl(packing) && type.columns > 1) - size -= (4 - type.vecsize) * (type.width / 8); + { + if (flags.get(DecorationRowMajor)) + size -= (4 - type.columns) * (type.width / 8); + else + size -= (4 - type.vecsize) * (type.width / 8); + } } } @@ -1915,7 +1950,7 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin // The next member following a struct member is aligned to the base alignment of the struct that came before. // GL 4.5 spec, 7.6.2.2. - if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer) + if (!packing_is_hlsl(packing) && memb_type.basetype == SPIRType::Struct && !memb_type.pointer) pad_alignment = packed_alignment; else pad_alignment = 1; @@ -1943,13 +1978,16 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin } // Verify array stride rules. - if (is_array(memb_type) && - type_to_packed_array_stride(memb_type, member_flags, packing) != - type_struct_member_array_stride(type, i)) + if (is_array(memb_type)) { - if (failed_validation_index) - *failed_validation_index = i; - return false; + auto packed_array_stride = type_to_packed_array_stride(memb_type, member_flags, packing); + auto member_array_stride = type_struct_member_array_stride(type, i); + if (packed_array_stride != member_array_stride) + { + if (failed_validation_index) + *failed_validation_index = i; + return false; + } } // Verify that sub-structs also follow packing rules. diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 2dc148731..f8c54f4a5 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -6170,14 +6170,31 @@ void CompilerMSL::emit_custom_functions() "device", "device", "device", "device", "thread", "threadgroup", }; + static const bool src_is_physical_with_mismatch[] = { + true, true, false, + false, false, false, + false, false, false, + false, true, true, + }; + + static const bool dst_is_physical_with_mismatch[] = { + false, false, false, + false, false, false, + false, false, true, + true, false, false, + }; + for (uint32_t variant = 0; variant < 12; variant++) { + assert(!src_is_physical_with_mismatch[variant] || !dst_is_physical_with_mismatch[variant]); bool is_multidim = spv_func == SPVFuncImplArrayCopyMultidim; - const char* dim = is_multidim ? "[N][M]" : "[N]"; + const char *dim = is_multidim ? "[N][M]" : "[N]"; + + // Simple base case. statement("template" : ">"); statement("inline void spvArrayCopy", function_name_tags[variant], "(", - dst_address_space[variant], " T (&dst)", dim, ", ", - src_address_space[variant], " T (&src)", dim, ")"); + dst_address_space[variant], " T (&dst)", dim, ", ", + src_address_space[variant], " T (&src)", dim, ")"); begin_scope(); statement("for (uint i = 0; i < N; i++)"); begin_scope(); @@ -6187,6 +6204,81 @@ void CompilerMSL::emit_custom_functions() statement("dst[i] = src[i];"); end_scope(); end_scope(); + + if (spv_function_implementations.count(SPVFuncImplArrayCopyExtendedSrc) && + src_is_physical_with_mismatch[variant]) + { + // 1st overload, src can be magic vector where dst is a scalar. + // Need reinterpret casts to be memory model correct. LLVM vectors are broken otherwise. + statement("template" : ">"); + statement("inline void spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " T (&dst)", dim, ", ", + src_address_space[variant], " vec (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("dst[i] = reinterpret_cast<", src_address_space[variant], " T &>(src[i]);"); + end_scope(); + end_scope(); + + statement(""); + + // 2nd overload, both are vectors, but need SFINAE magic to avoid ambiguous case. + statement("template" : ">"); + statement("inline enable_if_t spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " vec (&dst)", dim, ", ", + src_address_space[variant], " vec (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("dst[i] = reinterpret_cast<", src_address_space[variant], " vec &>(src[i]);"); + end_scope(); + end_scope(); + } + + if (spv_function_implementations.count(SPVFuncImplArrayCopyExtendedDst) && + dst_is_physical_with_mismatch[variant]) + { + // 1st overload, src can be magic vector where dst is a scalar. + // Need reinterpret casts to be memory model correct. LLVM vectors are broken otherwise. + statement("template" : ">"); + statement("inline void spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " vec (&dst)", dim, ", ", + src_address_space[variant], " T (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("reinterpret_cast<", dst_address_space[variant], " T &>(dst[i]) = src[i];"); + end_scope(); + end_scope(); + + statement(""); + + // 2nd overload, both are vectors, but need SFINAE magic to avoid ambiguous case. + statement("template" : ">"); + statement("inline enable_if_t spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " vec (&dst)", dim, ", ", + src_address_space[variant], " vec (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("reinterpret_cast<", dst_address_space[variant], " vec &>(dst[i]) = src[i];"); + end_scope(); + end_scope(); + } + statement(""); } break; @@ -10905,6 +10997,12 @@ bool CompilerMSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rh else SPIRV_CROSS_THROW("Unknown storage class used for copying arrays."); + // Should be very rare, but mark if we need extra magic template overloads. + if (has_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID)) + add_spv_func_and_recompile(SPVFuncImplArrayCopyExtendedDst); + if (has_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID)) + add_spv_func_and_recompile(SPVFuncImplArrayCopyExtendedSrc); + // Pass internal array of spvUnsafeArray<> into wrapper functions if (lhs_is_array_template && rhs_is_array_template && !msl_options.force_native_arrays) statement("spvArrayCopy", tag, "(", lhs, ".elements, ", to_expression(rhs_id), ".elements);"); @@ -14172,6 +14270,10 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo addr_space = "threadgroup"; } + // BlockIO is passed as thread and lowered on return from main. + if (get_execution_model() == ExecutionModelVertex && has_decoration(type.self, DecorationBlock)) + addr_space = "thread"; + if (!addr_space) addr_space = "device"; } diff --git a/3rdparty/spirv-cross/spirv_msl.hpp b/3rdparty/spirv-cross/spirv_msl.hpp index f63f5a234..033cb903b 100644 --- a/3rdparty/spirv-cross/spirv_msl.hpp +++ b/3rdparty/spirv-cross/spirv_msl.hpp @@ -796,6 +796,8 @@ protected: SPVFuncImplSSign, SPVFuncImplArrayCopy, SPVFuncImplArrayCopyMultidim, + SPVFuncImplArrayCopyExtendedSrc, + SPVFuncImplArrayCopyExtendedDst, SPVFuncImplTexelBufferCoords, SPVFuncImplImage2DAtomicCoords, // Emulate texture2D atomic operations SPVFuncImplGradientCube, diff --git a/3rdparty/spirv-cross/spirv_parser.cpp b/3rdparty/spirv-cross/spirv_parser.cpp index d30972b11..d2e7dfa5f 100644 --- a/3rdparty/spirv-cross/spirv_parser.cpp +++ b/3rdparty/spirv-cross/spirv_parser.cpp @@ -22,6 +22,7 @@ */ #include "spirv_parser.hpp" +#include "NonSemanticShaderDebugInfo100.h" #include using namespace std; @@ -137,6 +138,15 @@ void Parser::parse() } forward_pointer_fixups.clear(); + for (auto &source : ir.sources) + { + auto cmp = [](const ParsedIR::Source::Marker &a, const ParsedIR::Source::Marker &b) { + return a.line < b.line; + }; + + std::sort(source.line_markers.begin(), source.line_markers.end(), cmp); + } + if (current_function) SPIRV_CROSS_THROW("Function was not terminated."); if (current_block) @@ -194,7 +204,6 @@ void Parser::parse(const Instruction &instruction) switch (op) { - case OpSourceContinued: case OpSourceExtension: case OpNop: case OpModuleProcessed: @@ -213,38 +222,53 @@ void Parser::parse(const Instruction &instruction) case OpSource: { - ir.source.lang = static_cast(ops[0]); - switch (ir.source.lang) + ir.sources.emplace_back(); + auto &source = ir.sources.back(); + source.lang = static_cast(ops[0]); + + switch (source.lang) { case SourceLanguageESSL: - ir.source.es = true; - ir.source.version = ops[1]; - ir.source.known = true; - ir.source.hlsl = false; + source.es = true; + source.version = ops[1]; + source.known = true; + source.hlsl = false; break; case SourceLanguageGLSL: - ir.source.es = false; - ir.source.version = ops[1]; - ir.source.known = true; - ir.source.hlsl = false; + source.es = false; + source.version = ops[1]; + source.known = true; + source.hlsl = false; break; case SourceLanguageHLSL: // For purposes of cross-compiling, this is GLSL 450. - ir.source.es = false; - ir.source.version = 450; - ir.source.known = true; - ir.source.hlsl = true; + source.es = false; + source.version = 450; + source.known = true; + source.hlsl = true; break; default: - ir.source.known = false; + source.known = false; break; } + + if (length >= 3) + source.file_id = ops[2]; + + if (length >= 4) + source.source = extract_string(ir.spirv, instruction.offset + 3); + break; } + case OpSourceContinued: + if (!ir.sources.empty()) + ir.sources.back().source += extract_string(ir.spirv, instruction.offset); + break; + case OpUndef: { uint32_t result_type = ops[0]; @@ -318,17 +342,70 @@ void Parser::parse(const Instruction &instruction) ir.load_type_width.insert({ ops[1], type->width }); } } - else if (op == OpExtInst) + + if (op == OpExtInst && length > 4) { // Don't want to deal with ForwardRefs here. - auto &ext = get(ops[2]); if (ext.ext == SPIRExtension::NonSemanticShaderDebugInfo) { - // Parse global ShaderDebugInfo we care about. - // Just forward the string information. - if (ops[3] == SPIRExtension::DebugSource) + const auto instr = ops[3]; + if (instr == NonSemanticShaderDebugInfo100DebugSource) + { set(ops[1], get(ops[4]).str); + + ir.sources.emplace_back(); + auto &source = ir.sources.back(); + source.file_id = ops[4]; + source.define_id = ops[1]; + if (length >= 6) + source.source = ir.get(ops[5]).str; + } + else if (instr == NonSemanticShaderDebugInfo100DebugSourceContinued) + { + if (length < 5) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugSourceContinued"); + if (!ir.sources.empty()) + ir.sources.back().source += ir.get(ops[4]).str; + } + else if (instr == NonSemanticShaderDebugInfo100DebugLine) + { + if (length < 9) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugLine"); + auto source_id = ops[4]; + auto line_start = ir.get(ops[5]).scalar_i32(); + auto col_start = ir.get(ops[7]).scalar_i32(); + + for (auto &source : ir.sources) + { + if (source.define_id != source_id) + continue; + + source.line_markers.emplace_back(); + auto &marker = source.line_markers.back(); + marker.line = line_start; + marker.col = col_start; + marker.offset = instruction.offset - 1; + marker.function_id = current_function ? current_function->self : ID(0); + marker.block_id = current_block ? current_block->self : ID(0); + break; + } + } + else if (instr == NonSemanticShaderDebugInfo100DebugLocalVariable) + { + if (length < 11) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugLocalVariable"); + auto &lvar = set(ops[1]); + lvar.name_id = ops[4]; + } + else if (instr == NonSemanticShaderDebugInfo100DebugDeclare) + { + if (length < 7) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugDeclare"); + auto &lvar = get(ops[4]); + auto &var = get(ops[5]); + var.debug_local_variables.push_back(lvar.self); + } } } break; @@ -1378,6 +1455,24 @@ void Parser::parse(const Instruction &instruction) current_function->entry_line.line_literal = ops[1]; } } + + uint32_t file = ops[0]; + uint32_t line = ops[1]; + + for (auto &source : ir.sources) + { + if (source.file_id == file) + { + source.line_markers.emplace_back(); + auto &marker = source.line_markers.back(); + marker.line = line; + marker.offset = instruction.offset - 1; + marker.function_id = current_function ? current_function->self : ID(0); + marker.block_id = current_block ? current_block->self : ID(0); + break; + } + } + break; }