From 8727f3c8235090f05e2b7224caf5ae6cdb49c397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sun, 21 May 2023 17:27:44 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 4 ++ 3rdparty/spirv-cross/spirv_common.hpp | 1 + .../spirv-cross/spirv_cross_parsed_ir.cpp | 7 +++ 3rdparty/spirv-cross/spirv_glsl.cpp | 56 ++++++++++++------- 3rdparty/spirv-cross/spirv_glsl.hpp | 2 + 3rdparty/spirv-cross/spirv_hlsl.cpp | 47 ++++++++++++++-- 3rdparty/spirv-cross/spirv_hlsl.hpp | 8 +++ 3rdparty/spirv-cross/spirv_msl.cpp | 11 ++-- 8 files changed, 108 insertions(+), 28 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 1f21c4c08..5e9b0168c 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -732,6 +732,7 @@ struct CLIArguments bool hlsl_nonwritable_uav_texture_as_srv = false; bool hlsl_enable_16bit_types = false; bool hlsl_flatten_matrix_vertex_input_semantics = false; + bool hlsl_preserve_structured_buffers = false; HLSLBindingFlags hlsl_binding_flags = 0; bool vulkan_semantics = false; bool flatten_multidimensional_arrays = false; @@ -839,6 +840,7 @@ static void print_help_hlsl() "\t\tOpName reflection information must be intact.\n" "\t[--hlsl-enable-16bit-types]:\n\t\tEnables native use of half/int16_t/uint16_t and ByteAddressBuffer interaction with these types. Requires SM 6.2.\n" "\t[--hlsl-flatten-matrix-vertex-input-semantics]:\n\t\tEmits matrix vertex inputs with input semantics as if they were independent vectors, e.g. TEXCOORD{2,3,4} rather than matrix form TEXCOORD2_{0,1,2}.\n" + "\t[--hlsl-preserve-structured-buffers]:\n\t\tEmit SturucturedBuffer rather than ByteAddressBuffer. Requires UserTypeGOOGLE to be emitted. Intended for DXC roundtrips.\n" ); // clang-format on } @@ -1421,6 +1423,7 @@ static string compile_iteration(const CLIArguments &args, std::vector hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv; hlsl_opts.enable_16bit_types = args.hlsl_enable_16bit_types; hlsl_opts.flatten_matrix_vertex_input_semantics = args.hlsl_flatten_matrix_vertex_input_semantics; + hlsl_opts.preserve_structured_buffers = args.hlsl_preserve_structured_buffers; hlsl->set_hlsl_options(hlsl_opts); hlsl->set_resource_binding_flags(args.hlsl_binding_flags); if (args.hlsl_base_vertex_index_explicit_binding) @@ -1622,6 +1625,7 @@ static int main_inner(int argc, char *argv[]) cbs.add("--hlsl-enable-16bit-types", [&args](CLIParser &) { args.hlsl_enable_16bit_types = true; }); cbs.add("--hlsl-flatten-matrix-vertex-input-semantics", [&args](CLIParser &) { args.hlsl_flatten_matrix_vertex_input_semantics = true; }); + cbs.add("--hlsl-preserve-structured-buffers", [&args](CLIParser &) { args.hlsl_preserve_structured_buffers = true; }); cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; }); cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; }); cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; }); diff --git a/3rdparty/spirv-cross/spirv_common.hpp b/3rdparty/spirv-cross/spirv_common.hpp index ba420e1db..0264e8185 100644 --- a/3rdparty/spirv-cross/spirv_common.hpp +++ b/3rdparty/spirv-cross/spirv_common.hpp @@ -1663,6 +1663,7 @@ struct Meta std::string alias; std::string qualified_alias; std::string hlsl_semantic; + std::string user_type; Bitset decoration_flags; spv::BuiltIn builtin_type = spv::BuiltInMax; uint32_t location = 0; diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp index 8d1acf69f..c6ddb6a45 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp @@ -370,6 +370,10 @@ void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string dec.hlsl_semantic = argument; break; + case DecorationUserTypeGOOGLE: + dec.user_type = argument; + break; + default: break; } @@ -659,6 +663,9 @@ const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) cons case DecorationHlslSemanticGOOGLE: return dec.hlsl_semantic; + case DecorationUserTypeGOOGLE: + return dec.user_type; + default: return empty_string; } diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index e03111673..947cc95ef 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -9858,6 +9858,9 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice bool pending_array_enclose = false; bool dimension_flatten = false; + // If we are translating access to a structured buffer, the first subscript '._m0' must be hidden + bool hide_first_subscript = count > 1 && is_user_type_structured(base); + const auto append_index = [&](uint32_t index, bool is_literal, bool is_ptr_chain = false) { AccessChainFlags mod_flags = flags; if (!is_literal) @@ -10044,32 +10047,40 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (index >= type->member_types.size()) SPIRV_CROSS_THROW("Member index is out of bounds!"); - BuiltIn builtin = BuiltInMax; - if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base)) + if (hide_first_subscript) { - if (access_chain_is_arrayed) - { - expr += "."; - expr += builtin_to_glsl(builtin, type->storage); - } - else - expr = builtin_to_glsl(builtin, type->storage); + // First "._m0" subscript has been hidden, subsequent fields must be emitted even for structured buffers + hide_first_subscript = false; } else { - // If the member has a qualified name, use it as the entire chain - string qual_mbr_name = get_member_qualified_name(type_id, index); - if (!qual_mbr_name.empty()) - expr = qual_mbr_name; - else if (flatten_member_reference) - expr += join("_", to_member_name(*type, index)); + BuiltIn builtin = BuiltInMax; + if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base)) + { + if (access_chain_is_arrayed) + { + expr += "."; + expr += builtin_to_glsl(builtin, type->storage); + } + else + expr = builtin_to_glsl(builtin, type->storage); + } else { - // Any pointer de-refences for values are handled in the first access chain. - // For pointer chains, the pointer-ness is resolved through an array access. - // The only time this is not true is when accessing array of SSBO/UBO. - // This case is explicitly handled. - expr += to_member_reference(base, *type, index, ptr_chain || i != 0); + // If the member has a qualified name, use it as the entire chain + string qual_mbr_name = get_member_qualified_name(type_id, index); + if (!qual_mbr_name.empty()) + expr = qual_mbr_name; + else if (flatten_member_reference) + expr += join("_", to_member_name(*type, index)); + else + { + // Any pointer de-refences for values are handled in the first access chain. + // For pointer chains, the pointer-ness is resolved through an array access. + // The only time this is not true is when accessing array of SSBO/UBO. + // This case is explicitly handled. + expr += to_member_reference(base, *type, index, ptr_chain || i != 0); + } } } @@ -15587,6 +15598,11 @@ bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) cons return false; // GLSL itself does not need to translate array builtin types to non-array builtin types } +bool CompilerGLSL::is_user_type_structured(uint32_t /*id*/) const +{ + return false; // GLSL itself does not have structured user type, but HLSL does with StructuredBuffer and RWStructuredBuffer resources. +} + bool CompilerGLSL::check_atomic_image(uint32_t id) { auto &type = expression_type(id); diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index d6e2477e0..d4af6924a 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -477,6 +477,8 @@ protected: virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const; + virtual bool is_user_type_structured(uint32_t id) const; + void emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id, SmallVector chain); diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 01b601033..d70219781 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -2603,11 +2603,30 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self); bool is_coherent = flags.get(DecorationCoherent) && !is_readonly; bool is_interlocked = interlocked_resources.count(var.self) > 0; - const char *type_name = "ByteAddressBuffer "; - if (!is_readonly) - type_name = is_interlocked ? "RasterizerOrderedByteAddressBuffer " : "RWByteAddressBuffer "; + + auto to_structuredbuffer_subtype_name = [this](const SPIRType &parent_type) -> std::string + { + if (parent_type.basetype == SPIRType::Struct && parent_type.member_types.size() == 1) + { + // Use type of first struct member as a StructuredBuffer will have only one '._m0' field in SPIR-V + const auto &member0_type = this->get(parent_type.member_types.front()); + return this->type_to_glsl(member0_type); + } + else + { + // Otherwise, this StructuredBuffer only has a basic subtype, e.g. StructuredBuffer + return this->type_to_glsl(parent_type); + } + }; + + std::string type_name; + if (is_user_type_structured(var.self)) + type_name = join(is_readonly ? "" : is_interlocked ? "RasterizerOrdered" : "RW", "StructuredBuffer<", to_structuredbuffer_subtype_name(type), ">"); + else + type_name = is_readonly ? "ByteAddressBuffer" : is_interlocked ? "RasterizerOrderedByteAddressBuffer" : "RWByteAddressBuffer"; + add_resource_name(var.self); - statement(is_coherent ? "globallycoherent " : "", type_name, to_name(var.self), type_to_array_glsl(type), + statement(is_coherent ? "globallycoherent " : "", type_name, " ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";"); } else @@ -4969,6 +4988,12 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction) auto *backing_variable = maybe_get_backing_variable(ops[2]); + if (backing_variable != nullptr && is_user_type_structured(backing_variable->self)) + { + CompilerGLSL::emit_instruction(instruction); + return; + } + string base; if (to_plain_buffer_length != 0) base = access_chain(ops[2], &ops[3], to_plain_buffer_length, get(ops[0])); @@ -6693,3 +6718,17 @@ bool CompilerHLSL::builtin_translates_to_nonarray(spv::BuiltIn builtin) const { return (builtin == BuiltInSampleMask); } + +bool CompilerHLSL::is_user_type_structured(uint32_t id) const +{ + if (hlsl_options.preserve_structured_buffers) + { + // Compare left hand side of string only as these user types can contain more meta data such as their subtypes, + // e.g. "structuredbuffer:int" + const std::string &user_type = get_decoration_string(id, DecorationUserTypeGOOGLE); + return user_type.compare(0, 16, "structuredbuffer") == 0 || + user_type.compare(0, 18, "rwstructuredbuffer") == 0 || + user_type.compare(0, 33, "rasterizerorderedstructuredbuffer") == 0; + } + return false; +} diff --git a/3rdparty/spirv-cross/spirv_hlsl.hpp b/3rdparty/spirv-cross/spirv_hlsl.hpp index 51af5bf07..a5d30b1b2 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.hpp +++ b/3rdparty/spirv-cross/spirv_hlsl.hpp @@ -145,6 +145,11 @@ public: // Rather than emitting main() for the entry point, use the name in SPIR-V. bool use_entry_point_name = false; + + // Preserve (RW)StructuredBuffer types if the input source was HLSL. + // This relies on UserTypeGOOGLE to encode the buffer type either as "structuredbuffer" or "rwstructuredbuffer" + // whereas the type can be extended with an optional subtype, e.g. "structuredbuffer:int". + bool preserve_structured_buffers = false; }; explicit CompilerHLSL(std::vector spirv_) @@ -398,6 +403,9 @@ private: // Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but SV_Coverage is a scalar in HLSL. bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override; + // Returns true if the specified ID has a UserTypeGOOGLE decoration for StructuredBuffer or RWStructuredBuffer resources. + bool is_user_type_structured(uint32_t id) const override; + std::vector composite_selection_workaround_types; std::string get_inner_entry_point_name() const; diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 3f03f1c28..5c00ee2fd 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -10902,26 +10902,29 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool // Therefore, dP/dx = dP/dy = exp2(lod)/extent. // (Subtracting 0.5 before exponentiation gives better results.) string grad_opt, extent; + VariableID base_img = img; + if (auto *combined = maybe_get(img)) + base_img = combined->image; switch (imgtype.image.dim) { case Dim1D: grad_opt = "2d"; - extent = join("float2(", to_expression(img), ".get_width(), 1.0)"); + extent = join("float2(", to_expression(base_img), ".get_width(), 1.0)"); break; case Dim2D: grad_opt = "2d"; - extent = join("float2(", to_expression(img), ".get_width(), ", to_expression(img), ".get_height())"); + extent = join("float2(", to_expression(base_img), ".get_width(), ", to_expression(base_img), ".get_height())"); break; case DimCube: if (imgtype.image.arrayed && msl_options.emulate_cube_array) { grad_opt = "2d"; - extent = join("float2(", to_expression(img), ".get_width())"); + extent = join("float2(", to_expression(base_img), ".get_width())"); } else { grad_opt = "cube"; - extent = join("float3(", to_expression(img), ".get_width())"); + extent = join("float3(", to_expression(base_img), ".get_width())"); } break; default: