From f0b68fd9d4ff6ffdcc14e44529f153ca67d5ad91 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: Fri, 28 May 2021 20:17:12 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 16 +- 3rdparty/spirv-cross/spirv_glsl.cpp | 65 +++++++- 3rdparty/spirv-cross/spirv_glsl.hpp | 7 +- 3rdparty/spirv-cross/spirv_msl.cpp | 234 +++++++++++++++++++--------- 3rdparty/spirv-cross/spirv_msl.hpp | 9 +- 5 files changed, 245 insertions(+), 86 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 953abfadc..0da964496 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -658,10 +658,12 @@ struct CLIArguments bool msl_emulate_subgroups = false; uint32_t msl_fixed_subgroup_size = 0; bool msl_force_sample_rate_shading = false; + const char *msl_combined_sampler_suffix = nullptr; bool glsl_emit_push_constant_as_ubo = false; bool glsl_emit_ubo_as_plain_uniforms = false; bool glsl_force_flattened_io_blocks = false; SmallVector> glsl_ext_framebuffer_fetch; + bool glsl_ext_framebuffer_fetch_noncoherent = false; bool vulkan_glsl_disable_ext_samplerless_texture_functions = false; bool emit_line_directives = false; bool enable_storage_image_qualifier_deduction = true; @@ -754,6 +756,7 @@ static void print_help_glsl() "\t[--glsl-emit-ubo-as-plain-uniforms]:\n\t\tInstead of emitting UBOs, emit them as plain uniform structs.\n" "\t[--glsl-remap-ext-framebuffer-fetch input-attachment color-location]:\n\t\tRemaps an input attachment to use GL_EXT_shader_framebuffer_fetch.\n" "\t\tgl_LastFragData[location] is read from. The attachment to read from must be declared as an output in the shader.\n" + "\t[--glsl-ext-framebuffer-fetch-noncoherent]:\n\t\tUses noncoherent qualifier for framebuffer fetch.\n" "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]:\n\t\tDo not allow use of GL_EXT_samperless_texture_functions, even in Vulkan GLSL.\n" "\t\tUse of texelFetch and similar might have to create dummy samplers to work around it.\n" "\t[--combined-samplers-inherit-bindings]:\n\t\tInherit binding information from the textures when building combined image samplers from separate textures and samplers.\n" @@ -882,7 +885,8 @@ static void print_help_msl() "\t\tIntended for Vulkan Portability implementations where VK_EXT_subgroup_size_control is not supported or disabled.\n" "\t\tIf 0, assume variable subgroup size as actually exposed by Metal.\n" "\t[--msl-force-sample-rate-shading]:\n\t\tForce fragment shaders to run per sample.\n" - "\t\tThis adds a [[sample_id]] parameter if none is already present.\n"); + "\t\tThis adds a [[sample_id]] parameter if none is already present.\n" + "\t[--msl-combined-sampler-suffix ]:\n\t\tUses a custom suffix for combined samplers.\n"); // clang-format on } @@ -1145,6 +1149,8 @@ static string compile_iteration(const CLIArguments &args, std::vector msl_comp->add_inline_uniform_block(v.first, v.second); for (auto &v : args.msl_shader_inputs) msl_comp->add_msl_shader_input(v); + if (args.msl_combined_sampler_suffix) + msl_comp->set_combined_sampler_suffix(args.msl_combined_sampler_suffix); } else if (args.hlsl) compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir()))); @@ -1279,7 +1285,7 @@ static string compile_iteration(const CLIArguments &args, std::vector compiler->set_common_options(opts); for (auto &fetch : args.glsl_ext_framebuffer_fetch) - compiler->remap_ext_framebuffer_fetch(fetch.first, fetch.second); + compiler->remap_ext_framebuffer_fetch(fetch.first, fetch.second, !args.glsl_ext_framebuffer_fetch_noncoherent); // Set HLSL specific options. if (args.hlsl) @@ -1469,6 +1475,9 @@ static int main_inner(int argc, char *argv[]) uint32_t color_attachment = parser.next_uint(); args.glsl_ext_framebuffer_fetch.push_back({ input_index, color_attachment }); }); + cbs.add("--glsl-ext-framebuffer-fetch-noncoherent", [&args](CLIParser &) { + args.glsl_ext_framebuffer_fetch_noncoherent = true; + }); cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions", [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; }); cbs.add("--disable-storage-image-qualifier-deduction", @@ -1572,6 +1581,9 @@ static int main_inner(int argc, char *argv[]) cbs.add("--msl-fixed-subgroup-size", [&args](CLIParser &parser) { args.msl_fixed_subgroup_size = parser.next_uint(); }); cbs.add("--msl-force-sample-rate-shading", [&args](CLIParser &) { args.msl_force_sample_rate_shading = true; }); + cbs.add("--msl-combined-sampler-suffix", [&args](CLIParser &parser) { + args.msl_combined_sampler_suffix = parser.next_string(); + }); cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); cbs.add("--rename-entry-point", [&args](CLIParser &parser) { auto old_name = parser.next_string(); diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index a8d0925fc..028c98d1b 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -359,10 +359,26 @@ void CompilerGLSL::remap_pls_variables() } } -void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location) +void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent) { subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location }); - inout_color_attachments.insert(color_location); + inout_color_attachments.push_back({ color_location, coherent }); +} + +bool CompilerGLSL::location_is_framebuffer_fetch(uint32_t location) const +{ + return std::find_if(begin(inout_color_attachments), end(inout_color_attachments), + [&](const std::pair &elem) { + return elem.first == location; + }) != end(inout_color_attachments); +} + +bool CompilerGLSL::location_is_non_coherent_framebuffer_fetch(uint32_t location) const +{ + return std::find_if(begin(inout_color_attachments), end(inout_color_attachments), + [&](const std::pair &elem) { + return elem.first == location && !elem.second; + }) != end(inout_color_attachments); } void CompilerGLSL::find_static_extensions() @@ -484,7 +500,22 @@ void CompilerGLSL::find_static_extensions() SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders."); if (options.vulkan_semantics) SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL."); - require_extension_internal("GL_EXT_shader_framebuffer_fetch"); + + bool has_coherent = false; + bool has_incoherent = false; + + for (auto &att : inout_color_attachments) + { + if (att.second) + has_coherent = true; + else + has_incoherent = true; + } + + if (has_coherent) + require_extension_internal("GL_EXT_shader_framebuffer_fetch"); + if (has_incoherent) + require_extension_internal("GL_EXT_shader_framebuffer_fetch_non_coherent"); } if (options.separate_shader_objects && !options.es && options.version < 410) @@ -1693,6 +1724,12 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation))); } + if (get_execution_model() == ExecutionModelFragment && var.storage == StorageClassOutput && + location_is_non_coherent_framebuffer_fetch(get_decoration(var.self, DecorationLocation))) + { + attr.push_back("noncoherent"); + } + // Transform feedback bool uses_enhanced_layouts = false; if (is_block && var.storage == StorageClassOutput) @@ -2234,7 +2271,9 @@ const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var) return "varying "; // Fragment outputs are renamed so they never hit this case. else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput) { - if (inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0) + uint32_t loc = get_decoration(var.self, DecorationLocation); + bool is_inout = location_is_framebuffer_fetch(loc); + if (is_inout) return "inout "; else return "out "; @@ -3405,7 +3444,7 @@ void CompilerGLSL::emit_resources() // Unused output I/O variables might still be required to implement framebuffer fetch. if (var.storage == StorageClassOutput && !is_legacy() && - inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0) + location_is_framebuffer_fetch(get_decoration(var.self, DecorationLocation)) != 0) { is_hidden = false; } @@ -4909,7 +4948,13 @@ string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col char print_buffer[32]; sprintf(print_buffer, "0x%xu", c.scalar(col, row)); - res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")"); + + const char *comment = "inf"; + if (float_value == -numeric_limits::infinity()) + comment = "-inf"; + else if (std::isnan(float_value)) + comment = "nan"; + res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)"); } else { @@ -4976,7 +5021,13 @@ std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32 char print_buffer[64]; sprintf(print_buffer, "0x%llx%s", static_cast(u64_value), backend.long_long_literal_suffix ? "ull" : "ul"); - res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")"); + + const char *comment = "inf"; + if (double_value == -numeric_limits::infinity()) + comment = "-inf"; + else if (std::isnan(double_value)) + comment = "nan"; + res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)"); } else { diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index a3501ca99..20b949351 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -178,7 +178,8 @@ public: // Redirect a subpassInput reading from input_attachment_index to instead load its value from // the color attachment at location = color_location. Requires ESSL. - void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location); + // If coherent, uses GL_EXT_shader_framebuffer_fetch, if not, uses noncoherent variant. + void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent); explicit CompilerGLSL(std::vector spirv_) : Compiler(std::move(spirv_)) @@ -858,7 +859,9 @@ protected: // GL_EXT_shader_framebuffer_fetch support. std::vector> subpass_to_framebuffer_fetch_attachment; - std::unordered_set inout_color_attachments; + std::vector> inout_color_attachments; + bool location_is_framebuffer_fetch(uint32_t location) const; + bool location_is_non_coherent_framebuffer_fetch(uint32_t location) const; bool subpass_input_is_framebuffer_fetch(uint32_t id) const; void emit_inout_fragment_outputs_copy_to_subpass_inputs(); const SPIRVariable *find_subpass_input_by_attachment_index(uint32_t index) const; diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 5570a211e..aee52f7dc 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -1991,6 +1991,92 @@ uint32_t CompilerMSL::build_msl_interpolant_type(uint32_t type_id, bool is_noper return new_type_id; } +bool CompilerMSL::add_component_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, + SPIRVariable &var, + const SPIRType &type, + InterfaceBlockMeta &meta) +{ + // Deal with Component decorations. + const InterfaceBlockMeta::LocationMeta *location_meta = nullptr; + uint32_t location = ~0u; + if (has_decoration(var.self, DecorationLocation)) + { + location = get_decoration(var.self, DecorationLocation); + auto location_meta_itr = meta.location_meta.find(location); + if (location_meta_itr != end(meta.location_meta)) + location_meta = &location_meta_itr->second; + } + + // Check if we need to pad fragment output to match a certain number of components. + if (location_meta) + { + bool pad_fragment_output = has_decoration(var.self, DecorationLocation) && + msl_options.pad_fragment_output_components && + get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput; + + auto &entry_func = get(ir.default_entry_point); + uint32_t start_component = get_decoration(var.self, DecorationComponent); + uint32_t type_components = type.vecsize; + uint32_t num_components = location_meta->num_components; + + if (pad_fragment_output) + { + uint32_t locn = get_decoration(var.self, DecorationLocation); + num_components = std::max(num_components, get_target_components_for_fragment_location(locn)); + } + + // We have already declared an IO block member as m_location_N. + // Just emit an early-declared variable and fixup as needed. + // Arrays need to be unrolled here since each location might need a different number of components. + entry_func.add_local_variable(var.self); + vars_needing_early_declaration.push_back(var.self); + + if (var.storage == StorageClassInput) + { + entry_func.fixup_hooks_in.push_back([=, &type, &var]() { + if (!type.array.empty()) + { + uint32_t array_size = to_array_size_literal(type); + for (uint32_t loc_off = 0; loc_off < array_size; loc_off++) + { + statement(to_name(var.self), "[", loc_off, "]", " = ", ib_var_ref, + ".m_location_", location + loc_off, + vector_swizzle(type_components, start_component), ";"); + } + } + else + { + statement(to_name(var.self), " = ", ib_var_ref, ".m_location_", location, + vector_swizzle(type_components, start_component), ";"); + } + }); + } + else + { + entry_func.fixup_hooks_out.push_back([=, &type, &var]() { + if (!type.array.empty()) + { + uint32_t array_size = to_array_size_literal(type); + for (uint32_t loc_off = 0; loc_off < array_size; loc_off++) + { + statement(ib_var_ref, ".m_location_", location + loc_off, + vector_swizzle(type_components, start_component), " = ", + to_name(var.self), "[", loc_off, "];"); + } + } + else + { + statement(ib_var_ref, ".m_location_", location, + vector_swizzle(type_components, start_component), " = ", to_name(var.self), ";"); + } + }); + } + return true; + } + else + return false; +} + void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta) { @@ -2019,65 +2105,14 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co auto &entry_func = get(ir.default_entry_point); - // Deal with Component decorations. - InterfaceBlockMeta::LocationMeta *location_meta = nullptr; - if (has_decoration(var.self, DecorationLocation)) - { - auto location_meta_itr = meta.location_meta.find(get_decoration(var.self, DecorationLocation)); - if (location_meta_itr != end(meta.location_meta)) - location_meta = &location_meta_itr->second; - } + if (add_component_variable_to_interface_block(storage, ib_var_ref, var, type, meta)) + return; bool pad_fragment_output = has_decoration(var.self, DecorationLocation) && msl_options.pad_fragment_output_components && get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput; - // Check if we need to pad fragment output to match a certain number of components. - if (location_meta) - { - start_component = get_decoration(var.self, DecorationComponent); - uint32_t num_components = location_meta->num_components; - if (pad_fragment_output) - { - uint32_t locn = get_decoration(var.self, DecorationLocation); - num_components = std::max(num_components, get_target_components_for_fragment_location(locn)); - } - - if (location_meta->ib_index != ~0u) - { - // We have already declared the variable. Just emit an early-declared variable and fixup as needed. - entry_func.add_local_variable(var.self); - vars_needing_early_declaration.push_back(var.self); - - if (var.storage == StorageClassInput) - { - uint32_t ib_index = location_meta->ib_index; - entry_func.fixup_hooks_in.push_back([=, &var]() { - statement(to_name(var.self), " = ", ib_var_ref, ".", to_member_name(ib_type, ib_index), - vector_swizzle(type_components, start_component), ";"); - }); - } - else - { - uint32_t ib_index = location_meta->ib_index; - entry_func.fixup_hooks_out.push_back([=, &var]() { - statement(ib_var_ref, ".", to_member_name(ib_type, ib_index), - vector_swizzle(type_components, start_component), " = ", to_name(var.self), ";"); - }); - } - return; - } - else - { - location_meta->ib_index = uint32_t(ib_type.member_types.size()); - type_id = build_extended_vector_type(type_id, num_components); - if (var.storage == StorageClassInput) - padded_input = true; - else - padded_output = true; - } - } - else if (pad_fragment_output) + if (pad_fragment_output) { uint32_t locn = get_decoration(var.self, DecorationLocation); target_components = get_target_components_for_fragment_location(locn); @@ -2169,11 +2204,8 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co uint32_t locn = get_decoration(var.self, DecorationLocation); if (storage == StorageClassInput) { - type_id = ensure_correct_input_type(var.basetype, locn, - location_meta ? location_meta->num_components : 0, - meta.strip_array); - if (!location_meta) - var.basetype = type_id; + type_id = ensure_correct_input_type(var.basetype, locn, 0, meta.strip_array); + var.basetype = type_id; type_id = get_pointee_type_id(type_id); if (meta.strip_array && is_array(get(type_id))) @@ -2193,13 +2225,10 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co mark_location_as_used_by_shader(locn, type, storage); } - if (!location_meta) + if (get_decoration_bitset(var.self).get(DecorationComponent)) { - if (get_decoration_bitset(var.self).get(DecorationComponent)) - { - uint32_t component = get_decoration(var.self, DecorationComponent); - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, component); - } + uint32_t component = get_decoration(var.self, DecorationComponent); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, component); } if (get_decoration_bitset(var.self).get(DecorationIndex)) @@ -2229,10 +2258,7 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample); } - // If we have location meta, there is no unique OrigID. We won't need it, since we flatten/unflatten - // the variable to stack anyways here. - if (!location_meta) - set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); + set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); } void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, @@ -2243,6 +2269,9 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); uint32_t elem_cnt = 0; + if (add_component_variable_to_interface_block(storage, ib_var_ref, var, var_type, meta)) + return; + if (is_matrix(var_type)) { if (is_array(var_type)) @@ -2339,6 +2368,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage if (get_decoration_bitset(var.self).get(DecorationLocation)) { uint32_t locn = get_decoration(var.self, DecorationLocation) + i; + uint32_t comp = get_decoration(var.self, DecorationComponent); if (storage == StorageClassInput) { var.basetype = ensure_correct_input_type(var.basetype, locn, 0, meta.strip_array); @@ -2349,6 +2379,8 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage ib_type.member_types[ib_mbr_idx] = mbr_type_id; } set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); + if (comp) + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp); mark_location_as_used_by_shader(locn, *usable_type, storage); } else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin)) @@ -3319,7 +3351,6 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) // Need to deal specially with DecorationComponent. // Multiple variables can alias the same Location, and try to make sure each location is declared only once. // We will swizzle data in and out to make this work. - // We only need to consider plain variables here, not composites. // This is only relevant for vertex inputs and fragment outputs. // Technically tessellation as well, but it is too complicated to support. uint32_t component = get_decoration(var_id, DecorationComponent); @@ -3329,8 +3360,22 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) SPIRV_CROSS_THROW("Component decoration is not supported in tessellation shaders."); else if (pack_components) { - auto &location_meta = meta.location_meta[location]; - location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize); + uint32_t array_size = 1; + if (!type.array.empty()) + array_size = to_array_size_literal(type); + + for (uint32_t location_offset = 0; location_offset < array_size; location_offset++) + { + auto &location_meta = meta.location_meta[location + location_offset]; + location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize); + + // For variables sharing location, decorations and base type must match. + location_meta.base_type_id = type.self; + location_meta.flat = has_decoration(var.self, DecorationFlat); + location_meta.noperspective = has_decoration(var.self, DecorationNoPerspective); + location_meta.centroid = has_decoration(var.self, DecorationCentroid); + location_meta.sample = has_decoration(var.self, DecorationSample); + } } } } @@ -3579,6 +3624,31 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) } } + // When multiple variables need to access same location, + // unroll locations one by one and we will flatten output or input as necessary. + for (auto &loc : meta.location_meta) + { + uint32_t location = loc.first; + auto &location_meta = loc.second; + + uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size()); + uint32_t type_id = build_extended_vector_type(location_meta.base_type_id, location_meta.num_components); + ib_type.member_types.push_back(type_id); + + set_member_name(ib_type.self, ib_mbr_idx, join("m_location_", location)); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, get(type_id), storage); + + if (location_meta.flat) + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat); + if (location_meta.noperspective) + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective); + if (location_meta.centroid) + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid); + if (location_meta.sample) + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample); + } + // Sort the members of the structure by their locations. MemberSorter member_sorter(ib_type, ir.meta[ib_type_id], MemberSorter::LocationThenBuiltInType); member_sorter.sort(); @@ -7075,7 +7145,17 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l uint32_t const_mbr_id = next_id++; uint32_t index = get_extended_decoration(ops[2], SPIRVCrossDecorationInterfaceMemberIndex); - if (flatten_composites || is_block) + // If we have a pointer chain expression, and we are no longer pointing to a composite + // object, we are in the clear. There is no longer a need to flatten anything. + bool further_access_chain_is_trivial = false; + if (ptr_is_chain && flatten_composites) + { + auto &ptr_type = expression_type(ptr); + if (!is_array(ptr_type) && !is_matrix(ptr_type) && ptr_type.basetype != SPIRType::Struct) + further_access_chain_is_trivial = true; + } + + if (!further_access_chain_is_trivial && (flatten_composites || is_block)) { uint32_t i = first_non_array_index; auto *type = &get_variable_element_type(*var); @@ -7191,7 +7271,11 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l // First one is the gl_in/gl_out struct itself, then an index into that array. // If we have traversed further, we use a normal access chain formulation. auto *ptr_expr = maybe_get(ptr); - if (flatten_composites && ptr_expr && ptr_expr->implied_read_expressions.size() == 2) + bool split_access_chain_formulation = flatten_composites && ptr_expr && + ptr_expr->implied_read_expressions.size() == 2 && + !further_access_chain_is_trivial; + + if (split_access_chain_formulation) { e = join(to_expression(ptr), access_chain_internal(stage_var_id, indices.data(), uint32_t(indices.size()), @@ -15112,6 +15196,8 @@ bool CompilerMSL::MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2) return mbr_meta2.builtin; else if (mbr_meta1.builtin) return mbr_meta1.builtin_type < mbr_meta2.builtin_type; + else if (mbr_meta1.location == mbr_meta2.location) + return mbr_meta1.component < mbr_meta2.component; else return mbr_meta1.location < mbr_meta2.location; } diff --git a/3rdparty/spirv-cross/spirv_msl.hpp b/3rdparty/spirv-cross/spirv_msl.hpp index 95e0c966c..61f54be1a 100644 --- a/3rdparty/spirv-cross/spirv_msl.hpp +++ b/3rdparty/spirv-cross/spirv_msl.hpp @@ -799,8 +799,12 @@ protected: { struct LocationMeta { + uint32_t base_type_id = 0; uint32_t num_components = 0; - uint32_t ib_index = ~0u; + bool flat = false; + bool noperspective = false; + bool centroid = false; + bool sample = false; }; std::unordered_map location_meta; bool strip_array = false; @@ -815,6 +819,9 @@ protected: SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta); void add_plain_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta); + bool add_component_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, + SPIRVariable &var, const SPIRType &type, + InterfaceBlockMeta &meta); void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, uint32_t index, InterfaceBlockMeta &meta);