diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 578a5b0c9..06d911fdf 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -563,6 +563,7 @@ struct CLIArguments uint32_t msl_additional_fixed_sample_mask = 0xffffffff; 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 vulkan_glsl_disable_ext_samplerless_texture_functions = false; bool emit_line_directives = false; @@ -674,6 +675,7 @@ static void print_help_glsl() "\t[--no-420pack-extension]:\n\t\tDo not make use of GL_ARB_shading_language_420pack in older GL targets to support layout(binding).\n" "\t[--remap-variable-type ]:\n\t\tRemaps a variable type based on name.\n" "\t\tPrimary use case is supporting external samplers in ESSL for video rendering on Android where you could remap a texture to a YUV one.\n" + "\t[--glsl-force-flattened-io-blocks]:\n\t\tAlways flatten I/O blocks and structs.\n" ); // clang-format on } @@ -1131,6 +1133,7 @@ static string compile_iteration(const CLIArguments &args, std::vector opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance; opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo; opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms; + opts.force_flattened_io_blocks = args.glsl_force_flattened_io_blocks; opts.emit_line_directives = args.emit_line_directives; opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction; opts.force_zero_initialized_variables = args.force_zero_initialized_variables; @@ -1319,6 +1322,7 @@ static int main_inner(int argc, char *argv[]) cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; }); cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; }); + cbs.add("--glsl-force-flattened-io-blocks", [&args](CLIParser &) { args.glsl_force_flattened_io_blocks = true; }); cbs.add("--glsl-remap-ext-framebuffer-fetch", [&args](CLIParser &parser) { uint32_t input_index = parser.next_uint(); uint32_t color_attachment = parser.next_uint(); diff --git a/3rdparty/spirv-cross/spirv_cross_c.cpp b/3rdparty/spirv-cross/spirv_cross_c.cpp index c7d1361bb..d1d759f83 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.cpp +++ b/3rdparty/spirv-cross/spirv_cross_c.cpp @@ -459,6 +459,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS: options->glsl.emit_uniform_buffer_as_plain_uniforms = value != 0; break; + case SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS: + options->glsl.force_flattened_io_blocks = value != 0; + break; #endif #if SPIRV_CROSS_C_API_HLSL diff --git a/3rdparty/spirv-cross/spirv_cross_c.h b/3rdparty/spirv-cross/spirv_cross_c.h index 0ea8bf693..e8d1397a9 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.h +++ b/3rdparty/spirv-cross/spirv_cross_c.h @@ -33,7 +33,7 @@ extern "C" { /* Bumped if ABI or API breaks backwards compatibility. */ #define SPVC_C_API_VERSION_MAJOR 0 /* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 36 +#define SPVC_C_API_VERSION_MINOR 37 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -634,6 +634,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION = 64 | SPVC_COMPILER_OPTION_MSL_BIT, SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE = 65 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 72a9e93b8..b37d79acc 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -2142,6 +2142,10 @@ void CompilerGLSL::emit_flattened_io_block_member(const std::string &basename, c assert(member_type->basetype != SPIRType::Struct); + // We're overriding struct member names, so ensure we do so on the primary type. + if (parent_type->type_alias) + parent_type = &get(parent_type->type_alias); + // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row, // which is not allowed. flattened_name = sanitize_underscores(flattened_name); @@ -2185,10 +2189,14 @@ void CompilerGLSL::emit_flattened_io_block_struct(const std::string &basename, c void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual) { - auto &type = get(var.basetype); - if (!type.array.empty()) + auto &var_type = get(var.basetype); + if (!var_type.array.empty()) SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings."); + // Emit flattened types based on the type alias. Normally, we are never supposed to emit + // struct declarations for aliased types. + auto &type = var_type.type_alias ? get(var_type.type_alias) : var_type; + auto old_flags = ir.meta[type.self].decoration.decoration_flags; // Emit the members as if they are part of a block to get all qualifiers. ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock); @@ -2232,7 +2240,8 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) // ESSL earlier than 310 and GLSL earlier than 150 did not support // I/O variables which are struct types. // To support this, flatten the struct into separate varyings instead. - if ((options.es && options.version < 310) || (!options.es && options.version < 150)) + if (options.force_flattened_io_blocks || (options.es && options.version < 310) || + (!options.es && options.version < 150)) { // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320. // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150). @@ -2292,7 +2301,8 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) // I/O variables which are struct types. // To support this, flatten the struct into separate varyings instead. if (type.basetype == SPIRType::Struct && - ((options.es && options.version < 310) || (!options.es && options.version < 150))) + (options.force_flattened_io_blocks || (options.es && options.version < 310) || + (!options.es && options.version < 150))) { emit_flattened_io_block(var, qual); } @@ -14066,40 +14076,32 @@ void CompilerGLSL::reset_name_caches() void CompilerGLSL::fixup_type_alias() { // Due to how some backends work, the "master" type of type_alias must be a block-like type if it exists. - // FIXME: Multiple alias types which are both block-like will be awkward, for now, it's best to just drop the type - // alias if the slave type is a block type. ir.for_each_typed_id([&](uint32_t self, SPIRType &type) { - if (type.type_alias && type_is_block_like(type)) + if (!type.type_alias) + return; + + if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock)) { + // Top-level block types should never alias anything else. + type.type_alias = 0; + } + else if (type_is_block_like(type) && type.self == ID(self)) + { + // A block-like type is any type which contains Offset decoration, but not top-level blocks, + // i.e. blocks which are placed inside buffers. // Become the master. ir.for_each_typed_id([&](uint32_t other_id, SPIRType &other_type) { - if (other_id == type.self) + if (other_id == self) return; if (other_type.type_alias == type.type_alias) - other_type.type_alias = type.self; + other_type.type_alias = self; }); this->get(type.type_alias).type_alias = self; type.type_alias = 0; } }); - - ir.for_each_typed_id([&](uint32_t, SPIRType &type) { - if (type.type_alias && type_is_block_like(type)) - { - // This is not allowed, drop the type_alias. - type.type_alias = 0; - } - else if (type.type_alias && !type_is_block_like(this->get(type.type_alias))) - { - // If the alias master is not a block-like type, there is no reason to use type aliasing. - // This case can happen if two structs are declared with the same name, but they are unrelated. - // Aliases are only used to deal with aliased types for structs which are used in different buffer types - // which all create a variant of the same struct with different DecorationOffset values. - type.type_alias = 0; - } - }); } void CompilerGLSL::reorder_type_alias() diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index 5f6227f82..c3837434f 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -121,6 +121,10 @@ public: // which would otherwise be uninitialized will now be initialized to 0 instead. bool force_zero_initialized_variables = false; + // In GLSL, force use of I/O block flattening, similar to + // what happens on legacy GLSL targets for blocks and structs. + bool force_flattened_io_blocks = false; + enum Precision { DontCare, diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 708969456..7a33559a5 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -568,6 +568,13 @@ void CompilerHLSL::emit_builtin_outputs_in_struct() semantic = legacy ? "POSITION" : "SV_Position"; break; + case BuiltInSampleMask: + if (hlsl_options.shader_model < 41 || execution.model != ExecutionModelFragment) + SPIRV_CROSS_THROW("Sample Mask output is only supported in PS 4.1 or higher."); + type = "uint"; + semantic = "SV_Coverage"; + break; + case BuiltInFragDepth: type = "float"; if (legacy) @@ -673,6 +680,13 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() semantic = "SV_SampleIndex"; break; + case BuiltInSampleMask: + if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment) + SPIRV_CROSS_THROW("Sample Mask input is only supported in PS 5.0 or higher."); + type = "uint"; + semantic = "SV_Coverage"; + break; + case BuiltInGlobalInvocationId: type = "uint3"; semantic = "SV_DispatchThreadID"; @@ -1064,13 +1078,15 @@ void CompilerHLSL::emit_builtin_variables() type = "float"; break; + case BuiltInSampleMask: + type = "int"; + break; + default: SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin))); } StorageClass storage = active_input_builtins.get(i) ? StorageClassInput : StorageClassOutput; - // FIXME: SampleMask can be both in and out with sample builtin, - // need to distinguish that when we add support for that. if (type) { @@ -1079,6 +1095,13 @@ void CompilerHLSL::emit_builtin_variables() else statement("static ", type, " ", builtin_to_glsl(builtin, storage), ";"); } + + // SampleMask can be both in and out with sample builtin, in this case we have already + // declared the input variable and we need to add the output one now. + if (builtin == BuiltInSampleMask && storage == StorageClassInput && this->active_output_builtins.get(i)) + { + statement("static ", type, " ", this->builtin_to_glsl(builtin, StorageClassOutput), ";"); + } }); if (need_base_vertex_info) @@ -5700,3 +5723,8 @@ void CompilerHLSL::set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint3 SetBindingPair pair = { desc_set, binding }; force_uav_buffer_bindings.insert(pair); } + +bool CompilerHLSL::builtin_translates_to_nonarray(spv::BuiltIn builtin) const +{ + return (builtin == BuiltInSampleMask); +} diff --git a/3rdparty/spirv-cross/spirv_hlsl.hpp b/3rdparty/spirv-cross/spirv_hlsl.hpp index 6697cbea6..11f7f2634 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.hpp +++ b/3rdparty/spirv-cross/spirv_hlsl.hpp @@ -352,6 +352,9 @@ private: void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding); std::unordered_set force_uav_buffer_bindings; + + // 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; }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/3rdparty/spirv-cross/spirv_reflect.cpp b/3rdparty/spirv-cross/spirv_reflect.cpp index e8891651b..cf025aa5a 100644 --- a/3rdparty/spirv-cross/spirv_reflect.cpp +++ b/3rdparty/spirv-cross/spirv_reflect.cpp @@ -267,7 +267,6 @@ string CompilerReflection::compile() json_stream = std::make_shared(); json_stream->set_current_locale_radix_character(current_locale_radix_character); json_stream->begin_json_object(); - fixup_type_alias(); reorder_type_alias(); emit_entry_points(); emit_types(); @@ -327,9 +326,6 @@ void CompilerReflection::emit_type(uint32_t type_id, bool &emitted_open_tag) auto &type = get(type_id); auto name = type_to_glsl(type); - if (type.type_alias != TypeID(0)) - return; - if (!emitted_open_tag) { json_stream->emit_json_key_object("types");