diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 31b77baf9..51090bd04 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -277,6 +277,8 @@ static void print_resources(const Compiler &compiler, const char *tag, const Sma fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet)); if (mask.get(DecorationBinding)) fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding)); + if (static_cast(compiler).variable_is_depth_or_compare(res.id)) + fprintf(stderr, " (comparison)"); if (mask.get(DecorationInputAttachmentIndex)) fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex)); if (mask.get(DecorationNonReadable)) @@ -560,6 +562,7 @@ struct CLIArguments bool hlsl_compat = false; bool hlsl_support_nonzero_base = false; bool hlsl_force_storage_buffer_as_uav = false; + bool hlsl_nonwritable_uav_texture_as_srv = false; HLSLBindingFlags hlsl_binding_flags = 0; bool vulkan_semantics = false; bool flatten_multidimensional_arrays = false; @@ -632,6 +635,7 @@ static void print_help() "\t[--hlsl-support-nonzero-basevertex-baseinstance]\n" "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n" "\t[--hlsl-force-storage-buffer-as-uav]\n" + "\t[--hlsl-nonwritable-uav-texture-as-srv]\n" "\t[--separate-shader-objects]\n" "\t[--pls-in format input-name]\n" "\t[--pls-out format output-name]\n" @@ -988,6 +992,7 @@ static string compile_iteration(const CLIArguments &args, std::vector hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base; hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav; + hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv; hlsl->set_hlsl_options(hlsl_opts); hlsl->set_resource_binding_flags(args.hlsl_binding_flags); } @@ -1053,14 +1058,6 @@ static string compile_iteration(const CLIArguments &args, std::vector } } - if (args.dump_resources) - { - print_resources(*compiler, res); - print_push_constant_resources(*compiler, res.push_constant_buffers); - print_spec_constants(*compiler); - print_capabilities_and_extensions(*compiler); - } - if (combined_image_samplers) { compiler->build_combined_image_samplers(); @@ -1092,7 +1089,17 @@ static string compile_iteration(const CLIArguments &args, std::vector static_cast(compiler.get())->add_vertex_attribute_remap(remap); } - return compiler->compile(); + auto ret = compiler->compile(); + + if (args.dump_resources) + { + print_resources(*compiler, res); + print_push_constant_resources(*compiler, res.push_constant_buffers); + print_spec_constants(*compiler); + print_capabilities_and_extensions(*compiler); + } + + return ret; } static int main_inner(int argc, char *argv[]) @@ -1154,6 +1161,8 @@ static int main_inner(int argc, char *argv[]) }); cbs.add("--hlsl-force-storage-buffer-as-uav", [&args](CLIParser &) { args.hlsl_force_storage_buffer_as_uav = true; }); + cbs.add("--hlsl-nonwritable-uav-texture-as-srv", + [&args](CLIParser &) { args.hlsl_nonwritable_uav_texture_as_srv = 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_cross_c.cpp b/3rdparty/spirv-cross/spirv_cross_c.cpp index ead446912..528a51f54 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.cpp +++ b/3rdparty/spirv-cross/spirv_cross_c.cpp @@ -481,6 +481,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV: options->hlsl.force_storage_buffer_as_uav = value != 0; break; + + case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV: + options->hlsl.nonwritable_uav_texture_as_srv = value != 0; + break; #endif #if SPIRV_CROSS_C_API_MSL @@ -707,6 +711,23 @@ spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_vari #endif } +spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id) +{ +#if SPIRV_CROSS_C_API_GLSL + if (compiler->backend == SPVC_BACKEND_NONE) + { + compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + return static_cast(compiler->compiler.get())->variable_is_depth_or_compare(id) ? SPVC_TRUE : SPVC_FALSE; +#else + (void)id; + compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); + return SPVC_FALSE; +#endif +} + spvc_result spvc_compiler_hlsl_set_root_constants_layout(spvc_compiler compiler, const spvc_hlsl_root_constants *constant_info, size_t count) diff --git a/3rdparty/spirv-cross/spirv_cross_c.h b/3rdparty/spirv-cross/spirv_cross_c.h index 3ff245a6d..8c74792fa 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 28 +#define SPVC_C_API_VERSION_MINOR 30 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -580,6 +580,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES = 54 | SPVC_COMPILER_OPTION_COMMON_BIT, + SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV = 55 | SPVC_COMPILER_OPTION_HLSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; @@ -640,6 +642,8 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_add_header_line(spvc_compiler compiler SPVC_PUBLIC_API spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *ext); SPVC_PUBLIC_API spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id); +SPVC_PUBLIC_API spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id); + /* * HLSL specifics. * Maps to C++ API. diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index d5c428331..166364f1e 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -2543,7 +2543,7 @@ void CompilerGLSL::fixup_image_load_store_access() ir.for_each_typed_id([&](uint32_t var, const SPIRVariable &) { auto &vartype = expression_type(var); - if (vartype.basetype == SPIRType::Image) + if (vartype.basetype == SPIRType::Image && vartype.image.sampled == 2) { // Very old glslangValidator and HLSL compilers do not emit required qualifiers here. // Solve this by making the image access as restricted as possible and loosen up if we need to. @@ -13702,3 +13702,8 @@ void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs() }); } } + +bool CompilerGLSL::variable_is_depth_or_compare(VariableID id) const +{ + return image_is_comparison(get(get(id).basetype), id); +} diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index 065bdf041..f66202a09 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -228,6 +228,14 @@ public: // The name of the uniform array will be the same as the interface block name. void flatten_buffer_block(VariableID id); + // After compilation, query if a variable ID was used as a depth resource. + // This is meaningful for MSL since descriptor types depend on this knowledge. + // Cases which return true: + // - Images which are declared with depth = 1 image type. + // - Samplers which are statically used at least once with Dref opcodes. + // - Images which are statically used at least once with Dref opcodes. + bool variable_is_depth_or_compare(VariableID id) const; + protected: void reset(); void emit_function(SPIRFunction &func, const Bitset &return_flags); diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 8639f201a..29846c76f 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -210,6 +210,8 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id) bool typed_load = false; uint32_t components = 4; + bool force_image_srv = hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(id, DecorationNonWritable); + switch (type.image.dim) { case Dim1D: @@ -239,7 +241,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id) if (interlocked_resources.count(id)) return join("RasterizerOrderedBuffer<", image_format_to_type(type.image.format, imagetype.basetype), ">"); - return join("RWBuffer<", image_format_to_type(type.image.format, imagetype.basetype), ">"); + + typed_load = !force_image_srv && type.image.sampled == 2; + + const char *rw = force_image_srv ? "" : "RW"; + return join(rw, "Buffer<", + typed_load ? image_format_to_type(type.image.format, imagetype.basetype) : + join(type_to_glsl(imagetype), components), + ">"); } else SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime."); @@ -252,9 +261,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id) } const char *arrayed = type.image.arrayed ? "Array" : ""; const char *ms = type.image.ms ? "MS" : ""; - const char *rw = typed_load ? "RW" : ""; + const char *rw = typed_load && !force_image_srv ? "RW" : ""; + + if (force_image_srv) + typed_load = false; + if (typed_load && interlocked_resources.count(id)) rw = "RasterizerOrdered"; + return join(rw, "Texture", dim, ms, arrayed, "<", typed_load ? image_format_to_type(type.image.format, imagetype.basetype) : join(type_to_glsl(imagetype), components), @@ -2971,8 +2985,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var) case SPIRType::Image: if (type.image.sampled == 2 && type.image.dim != DimSubpassData) { - space = 'u'; // UAV - resource_flags = HLSL_BINDING_AUTO_UAV_BIT; + if (has_decoration(var.self, DecorationNonWritable) && hlsl_options.nonwritable_uav_texture_as_srv) + { + space = 't'; // SRV + resource_flags = HLSL_BINDING_AUTO_SRV_BIT; + } + else + { + space = 'u'; // UAV + resource_flags = HLSL_BINDING_AUTO_UAV_BIT; + } } else { @@ -4813,7 +4835,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]"); // The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4", // except that the underlying type changes how the data is interpreted. - if (var && !subpass_data) + + bool force_srv = + hlsl_options.nonwritable_uav_texture_as_srv && var && has_decoration(var->self, DecorationNonWritable); + pure = force_srv; + + if (var && !subpass_data && !force_srv) imgexpr = remap_swizzle(get(result_type), image_format_to_components(get(var->basetype).image.format), imgexpr); } diff --git a/3rdparty/spirv-cross/spirv_hlsl.hpp b/3rdparty/spirv-cross/spirv_hlsl.hpp index 29b38e628..acc150695 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.hpp +++ b/3rdparty/spirv-cross/spirv_hlsl.hpp @@ -113,6 +113,11 @@ public: // Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used. // By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead. bool force_storage_buffer_as_uav = false; + + // Forces any storage image type marked as NonWritable to be considered an SRV instead. + // For this to work with function call parameters, NonWritable must be considered to be part of the type system + // so that NonWritable image arguments are also translated to Texture rather than RWTexture. + bool nonwritable_uav_texture_as_srv = false; }; explicit CompilerHLSL(std::vector spirv_) diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 361c338a5..397cb4fc1 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -174,6 +174,7 @@ void CompilerMSL::build_implicit_builtins() if (need_subpass_input && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) && builtin == BuiltInFragCoord) { + mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var.self); builtin_frag_coord_id = var.self; has_frag_coord = true; } @@ -181,6 +182,7 @@ void CompilerMSL::build_implicit_builtins() if (need_sample_pos && builtin == BuiltInSampleId) { builtin_sample_id_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInSampleId, var.self); has_sample_id = true; } @@ -190,18 +192,22 @@ void CompilerMSL::build_implicit_builtins() { case BuiltInVertexIndex: builtin_vertex_idx_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInVertexIndex, var.self); has_vertex_idx = true; break; case BuiltInBaseVertex: builtin_base_vertex_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInBaseVertex, var.self); has_base_vertex = true; break; case BuiltInInstanceIndex: builtin_instance_idx_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var.self); has_instance_idx = true; break; case BuiltInBaseInstance: builtin_base_instance_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInBaseInstance, var.self); has_base_instance = true; break; default: @@ -215,10 +221,12 @@ void CompilerMSL::build_implicit_builtins() { case BuiltInInvocationId: builtin_invocation_id_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var.self); has_invocation_id = true; break; case BuiltInPrimitiveId: builtin_primitive_id_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var.self); has_primitive_id = true; break; default: @@ -229,12 +237,14 @@ void CompilerMSL::build_implicit_builtins() if ((need_subgroup_mask || needs_subgroup_invocation_id) && builtin == BuiltInSubgroupLocalInvocationId) { builtin_subgroup_invocation_id_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInSubgroupLocalInvocationId, var.self); has_subgroup_invocation_id = true; } if (need_subgroup_ge_mask && builtin == BuiltInSubgroupSize) { builtin_subgroup_size_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInSubgroupSize, var.self); has_subgroup_size = true; } @@ -245,10 +255,12 @@ void CompilerMSL::build_implicit_builtins() case BuiltInInstanceIndex: // The view index here is derived from the instance index. builtin_instance_idx_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var.self); has_instance_idx = true; break; case BuiltInViewIndex: builtin_view_idx_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var.self); has_view_idx = true; break; default: @@ -645,7 +657,10 @@ void CompilerMSL::mark_implicit_builtin(StorageClass storage, BuiltIn builtin, u assert(active_builtins != nullptr); active_builtins->set(builtin); - get_entry_point().interface_variables.push_back(id); + + auto &var = get_entry_point().interface_variables; + if (find(begin(var), end(var), VariableID(id)) == end(var)) + var.push_back(id); } uint32_t CompilerMSL::build_constant_uint_array_pointer() @@ -10505,7 +10520,12 @@ string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uin if (var) { - bool is_buffer_variable = var->storage == StorageClassUniform || var->storage == StorageClassStorageBuffer; + // Only allow -> dereference for block types. This is so we get expressions like + // buffer[i]->first_member.second_member, rather than buffer[i]->first->second. + bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock); + + bool is_buffer_variable = + is_block && (var->storage == StorageClassUniform || var->storage == StorageClassStorageBuffer); declared_as_pointer = is_buffer_variable && is_array(get(var->basetype)); }