diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 21525f5a2..c062795c6 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -731,6 +731,13 @@ void CompilerGLSL::emit_header() statement("#endif"); } } + else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters") + { + // Soft-enable this extension on plain GLSL. + statement("#ifdef ", ext); + statement("#extension ", ext, " : enable"); + statement("#endif"); + } else statement("#extension ", ext, " : require"); } @@ -2943,16 +2950,28 @@ void CompilerGLSL::emit_resources() } else if (id.get_type() == TypeType) { - auto &type = id.get(); - if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer && - (!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) && - !ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock))) + auto *type = &id.get(); + + bool is_natural_struct = + type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer && + (!has_decoration(type->self, DecorationBlock) && !has_decoration(type->self, DecorationBufferBlock)); + + // Special case, ray payload and hit attribute blocks are not really blocks, just regular structs. + if (type->basetype == SPIRType::Struct && type->pointer && has_decoration(type->self, DecorationBlock) && + (type->storage == StorageClassRayPayloadNV || type->storage == StorageClassIncomingRayPayloadNV || + type->storage == StorageClassHitAttributeNV)) + { + type = &get(type->parent_type); + is_natural_struct = true; + } + + if (is_natural_struct) { if (emitted) statement(""); emitted = false; - emit_struct(type); + emit_struct(*type); } } } @@ -3070,6 +3089,8 @@ void CompilerGLSL::emit_resources() statement(""); emitted = false; + bool emitted_base_instance = false; + // Output in/out interfaces. ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { auto &type = this->get(var.basetype); @@ -3092,13 +3113,42 @@ void CompilerGLSL::emit_resources() } else if (is_builtin_variable(var)) { + auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); // For gl_InstanceIndex emulation on GLES, the API user needs to // supply this uniform. - if (options.vertex.support_nonzero_base_instance && - ir.meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics) + + // The draw parameter extension is soft-enabled on GL with some fallbacks. + if (!options.vulkan_semantics) { - statement("uniform int SPIRV_Cross_BaseInstance;"); - emitted = true; + if (!emitted_base_instance && + ((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) || + (builtin == BuiltInBaseInstance))) + { + statement("#ifdef GL_ARB_shader_draw_parameters"); + statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB"); + statement("#else"); + // A crude, but simple workaround which should be good enough for non-indirect draws. + statement("uniform int SPIRV_Cross_BaseInstance;"); + statement("#endif"); + emitted = true; + emitted_base_instance = true; + } + else if (builtin == BuiltInBaseVertex) + { + statement("#ifdef GL_ARB_shader_draw_parameters"); + statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB"); + statement("#else"); + // A crude, but simple workaround which should be good enough for non-indirect draws. + statement("uniform int SPIRV_Cross_BaseVertex;"); + statement("#endif"); + } + else if (builtin == BuiltInDrawIndex) + { + statement("#ifndef GL_ARB_shader_draw_parameters"); + // Cannot really be worked around. + statement("#error GL_ARB_shader_draw_parameters is not supported."); + statement("#endif"); + } } } }); @@ -6817,7 +6867,14 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) if (options.vulkan_semantics) return "gl_InstanceIndex"; else if (options.vertex.support_nonzero_base_instance) + { + if (!options.vulkan_semantics) + { + // This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported. + require_extension_internal("GL_ARB_shader_draw_parameters"); + } return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID. + } else return "gl_InstanceID"; case BuiltInPrimitiveId: @@ -6859,33 +6916,69 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) return "gl_LocalInvocationIndex"; case BuiltInHelperInvocation: return "gl_HelperInvocation"; + case BuiltInBaseVertex: if (options.es) SPIRV_CROSS_THROW("BaseVertex not supported in ES profile."); - if (options.version < 460) + + if (options.vulkan_semantics) { - require_extension_internal("GL_ARB_shader_draw_parameters"); - return "gl_BaseVertexARB"; + if (options.version < 460) + { + require_extension_internal("GL_ARB_shader_draw_parameters"); + return "gl_BaseVertexARB"; + } + return "gl_BaseVertex"; } - return "gl_BaseVertex"; + else + { + // On regular GL, this is soft-enabled and we emit ifdefs in code. + require_extension_internal("GL_ARB_shader_draw_parameters"); + return "SPIRV_Cross_BaseVertex"; + } + break; + case BuiltInBaseInstance: if (options.es) SPIRV_CROSS_THROW("BaseInstance not supported in ES profile."); - if (options.version < 460) + + if (options.vulkan_semantics) { - require_extension_internal("GL_ARB_shader_draw_parameters"); - return "gl_BaseInstanceARB"; + if (options.version < 460) + { + require_extension_internal("GL_ARB_shader_draw_parameters"); + return "gl_BaseInstanceARB"; + } + return "gl_BaseInstance"; } - return "gl_BaseInstance"; + else + { + // On regular GL, this is soft-enabled and we emit ifdefs in code. + require_extension_internal("GL_ARB_shader_draw_parameters"); + return "SPIRV_Cross_BaseInstance"; + } + break; + case BuiltInDrawIndex: if (options.es) SPIRV_CROSS_THROW("DrawIndex not supported in ES profile."); - if (options.version < 460) + + if (options.vulkan_semantics) { + if (options.version < 460) + { + require_extension_internal("GL_ARB_shader_draw_parameters"); + return "gl_DrawIDARB"; + } + return "gl_DrawID"; + } + else + { + // On regular GL, this is soft-enabled and we emit ifdefs in code. require_extension_internal("GL_ARB_shader_draw_parameters"); return "gl_DrawIDARB"; } - return "gl_DrawID"; + break; case BuiltInSampleId: if (options.es && options.version < 320) @@ -10792,21 +10885,26 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpReportIntersectionNV: statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");"); + flush_control_dependent_expressions(current_emitting_block->self); break; case OpIgnoreIntersectionNV: statement("ignoreIntersectionNV();"); + flush_control_dependent_expressions(current_emitting_block->self); break; case OpTerminateRayNV: statement("terminateRayNV();"); + flush_control_dependent_expressions(current_emitting_block->self); break; case OpTraceNV: statement("traceNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ", to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ", to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ", to_expression(ops[9]), ", ", to_expression(ops[10]), ");"); + flush_control_dependent_expressions(current_emitting_block->self); break; case OpExecuteCallableNV: statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");"); + flush_control_dependent_expressions(current_emitting_block->self); break; case OpConvertUToPtr: @@ -13407,6 +13505,7 @@ void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &ex case BuiltInBaseInstance: case BuiltInDrawIndex: case BuiltInFragStencilRefEXT: + case BuiltInInstanceCustomIndexNV: expected_type = SPIRType::Int; break; @@ -13416,6 +13515,9 @@ void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &ex case BuiltInLocalInvocationIndex: case BuiltInWorkgroupSize: case BuiltInNumWorkgroups: + case BuiltInIncomingRayFlagsNV: + case BuiltInLaunchIdNV: + case BuiltInLaunchSizeNV: expected_type = SPIRType::UInt; break; diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index f27163c20..680d3d796 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -23,6 +23,41 @@ using namespace spv; using namespace SPIRV_CROSS_NAMESPACE; using namespace std; +enum class ImageFormatNormalizedState +{ + None = 0, + Unorm = 1, + Snorm = 2 +}; + +static ImageFormatNormalizedState image_format_to_normalized_state(ImageFormat fmt) +{ + switch (fmt) + { + case ImageFormatR8: + case ImageFormatR16: + case ImageFormatRg8: + case ImageFormatRg16: + case ImageFormatRgba8: + case ImageFormatRgba16: + case ImageFormatRgb10A2: + return ImageFormatNormalizedState::Unorm; + + case ImageFormatR8Snorm: + case ImageFormatR16Snorm: + case ImageFormatRg8Snorm: + case ImageFormatRg16Snorm: + case ImageFormatRgba8Snorm: + case ImageFormatRgba16Snorm: + return ImageFormatNormalizedState::Snorm; + + default: + break; + } + + return ImageFormatNormalizedState::None; +} + static unsigned image_format_to_components(ImageFormat fmt) { switch (fmt) @@ -1423,66 +1458,14 @@ void CompilerHLSL::emit_resources() } } - if (required_textureSizeVariants != 0) + emit_texture_size_variants(required_texture_size_variants.srv, "4", false, ""); + for (uint32_t norm = 0; norm < 3; norm++) { - static const char *types[QueryTypeCount] = { "float4", "int4", "uint4" }; - static const char *dims[QueryDimCount] = { "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray", - "Texture3D", "Buffer", "TextureCube", "TextureCubeArray", - "Texture2DMS", "Texture2DMSArray" }; - - static const bool has_lod[QueryDimCount] = { true, true, true, true, true, false, true, true, false, false }; - - static const char *ret_types[QueryDimCount] = { - "uint", "uint2", "uint2", "uint3", "uint3", "uint", "uint2", "uint3", "uint2", "uint3", - }; - - static const uint32_t return_arguments[QueryDimCount] = { - 1, 2, 2, 3, 3, 1, 2, 3, 2, 3, - }; - - for (uint32_t index = 0; index < QueryDimCount; index++) + for (uint32_t comp = 0; comp < 4; comp++) { - for (uint32_t type_index = 0; type_index < QueryTypeCount; type_index++) - { - uint32_t bit = 16 * type_index + index; - uint64_t mask = 1ull << bit; - - if ((required_textureSizeVariants & mask) == 0) - continue; - - statement(ret_types[index], " SPIRV_Cross_textureSize(", dims[index], "<", types[type_index], - "> Tex, uint Level, out uint Param)"); - begin_scope(); - statement(ret_types[index], " ret;"); - switch (return_arguments[index]) - { - case 1: - if (has_lod[index]) - statement("Tex.GetDimensions(Level, ret.x, Param);"); - else - { - statement("Tex.GetDimensions(ret.x);"); - statement("Param = 0u;"); - } - break; - case 2: - if (has_lod[index]) - statement("Tex.GetDimensions(Level, ret.x, ret.y, Param);"); - else - statement("Tex.GetDimensions(ret.x, ret.y, Param);"); - break; - case 3: - if (has_lod[index]) - statement("Tex.GetDimensions(Level, ret.x, ret.y, ret.z, Param);"); - else - statement("Tex.GetDimensions(ret.x, ret.y, ret.z, Param);"); - break; - } - - statement("return ret;"); - end_scope(); - statement(""); - } + static const char *qualifiers[] = { "", "unorm ", "snorm " }; + static const char *vecsizes[] = { "", "2", "3", "4" }; + emit_texture_size_variants(required_texture_size_variants.uav[norm][comp], vecsizes[comp], true, qualifiers[norm]); } } @@ -1845,6 +1828,83 @@ void CompilerHLSL::emit_resources() } } +void CompilerHLSL::emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, const char *type_qualifier) +{ + if (variant_mask == 0) + return; + + static const char *types[QueryTypeCount] = { "float", "int", "uint" }; + static const char *dims[QueryDimCount] = { "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray", + "Texture3D", "Buffer", "TextureCube", "TextureCubeArray", + "Texture2DMS", "Texture2DMSArray" }; + + static const bool has_lod[QueryDimCount] = { true, true, true, true, true, false, true, true, false, false }; + + static const char *ret_types[QueryDimCount] = { + "uint", "uint2", "uint2", "uint3", "uint3", "uint", "uint2", "uint3", "uint2", "uint3", + }; + + static const uint32_t return_arguments[QueryDimCount] = { + 1, 2, 2, 3, 3, 1, 2, 3, 2, 3, + }; + + for (uint32_t index = 0; index < QueryDimCount; index++) + { + for (uint32_t type_index = 0; type_index < QueryTypeCount; type_index++) + { + uint32_t bit = 16 * type_index + index; + uint64_t mask = 1ull << bit; + + if ((variant_mask & mask) == 0) + continue; + + statement(ret_types[index], " SPIRV_Cross_", (uav ? "image" : "texture"), "Size(", (uav ? "RW" : ""), + dims[index], "<", type_qualifier, types[type_index], vecsize_qualifier, + "> Tex, ", (uav ? "" : "uint Level, "), "out uint Param)"); + begin_scope(); + statement(ret_types[index], " ret;"); + switch (return_arguments[index]) + { + case 1: + if (has_lod[index] && !uav) + statement("Tex.GetDimensions(Level, ret.x, Param);"); + else + { + statement("Tex.GetDimensions(ret.x);"); + statement("Param = 0u;"); + } + break; + case 2: + if (has_lod[index] && !uav) + statement("Tex.GetDimensions(Level, ret.x, ret.y, Param);"); + else if (!uav) + statement("Tex.GetDimensions(ret.x, ret.y, Param);"); + else + { + statement("Tex.GetDimensions(ret.x, ret.y);"); + statement("Param = 0u;"); + } + break; + case 3: + if (has_lod[index] && !uav) + statement("Tex.GetDimensions(Level, ret.x, ret.y, ret.z, Param);"); + else if (!uav) + statement("Tex.GetDimensions(ret.x, ret.y, ret.z, Param);"); + else + { + statement("Tex.GetDimensions(ret.x, ret.y, ret.z);"); + statement("Param = 0u;"); + } + break; + } + + statement("return ret;"); + end_scope(); + statement(""); + } + } +} + string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index) { auto &flags = get_member_decoration_bitset(type.self, index); @@ -4834,8 +4894,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto result_type = ops[0]; auto id = ops[1]; - require_texture_query_variant(expression_type(ops[2])); - + require_texture_query_variant(ops[2]); auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter"); statement("uint ", dummy_samples_levels, ";"); @@ -4853,12 +4912,22 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto result_type = ops[0]; auto id = ops[1]; - require_texture_query_variant(expression_type(ops[2])); + require_texture_query_variant(ops[2]); + bool uav = expression_type(ops[2]).image.sampled == 2; + + if (const auto *var = maybe_get_backing_variable(ops[2])) + if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var->self, DecorationNonWritable)) + uav = false; auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter"); statement("uint ", dummy_samples_levels, ";"); - auto expr = join("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", dummy_samples_levels, ")"); + string expr; + if (uav) + expr = join("SPIRV_Cross_imageSize(", to_expression(ops[2]), ", ", dummy_samples_levels, ")"); + else + expr = join("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", dummy_samples_levels, ")"); + auto &restype = get(ops[0]); expr = bitcast_expression(restype, SPIRType::UInt, expr); emit_op(result_type, id, expr, true); @@ -4871,14 +4940,25 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto result_type = ops[0]; auto id = ops[1]; - require_texture_query_variant(expression_type(ops[2])); + require_texture_query_variant(ops[2]); + bool uav = expression_type(ops[2]).image.sampled == 2; + if (opcode == OpImageQueryLevels && uav) + SPIRV_CROSS_THROW("Cannot query levels for UAV images."); + + if (const auto *var = maybe_get_backing_variable(ops[2])) + if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var->self, DecorationNonWritable)) + uav = false; // Keep it simple and do not emit special variants to make this look nicer ... // This stuff is barely, if ever, used. forced_temporaries.insert(id); auto &type = get(result_type); statement(variable_decl(type, to_name(id)), ";"); - statement("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", to_name(id), ");"); + + if (uav) + statement("SPIRV_Cross_imageSize(", to_expression(ops[2]), ", ", to_name(id), ");"); + else + statement("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", to_name(id), ");"); auto &restype = get(ops[0]); auto expr = bitcast_expression(restype, SPIRType::UInt, to_name(id)); @@ -5192,8 +5272,16 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) } } -void CompilerHLSL::require_texture_query_variant(const SPIRType &type) +void CompilerHLSL::require_texture_query_variant(uint32_t var_id) { + if (const auto *var = maybe_get_backing_variable(var_id)) + var_id = var->self; + + auto &type = expression_type(var_id); + bool uav = type.image.sampled == 2; + if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var_id, DecorationNonWritable)) + uav = false; + uint32_t bit = 0; switch (type.image.dim) { @@ -5242,11 +5330,15 @@ void CompilerHLSL::require_texture_query_variant(const SPIRType &type) SPIRV_CROSS_THROW("Unsupported query type."); } + auto norm_state = image_format_to_normalized_state(type.image.format); + auto &variant = uav ? required_texture_size_variants.uav[uint32_t(norm_state)][image_format_to_components(type.image.format) - 1] : + required_texture_size_variants.srv; + uint64_t mask = 1ull << bit; - if ((required_textureSizeVariants & mask) == 0) + if ((variant & mask) == 0) { force_recompile(); - required_textureSizeVariants |= mask; + variant |= mask; } } diff --git a/3rdparty/spirv-cross/spirv_hlsl.hpp b/3rdparty/spirv-cross/spirv_hlsl.hpp index e98c6443a..fa3b656f0 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.hpp +++ b/3rdparty/spirv-cross/spirv_hlsl.hpp @@ -264,8 +264,23 @@ private: bool requires_scalar_reflect = false; bool requires_scalar_refract = false; bool requires_scalar_faceforward = false; - uint64_t required_textureSizeVariants = 0; - void require_texture_query_variant(const SPIRType &type); + + struct TextureSizeVariants + { + // MSVC 2013 workaround. + TextureSizeVariants() + { + srv = 0; + for (auto &unorm : uav) + for (auto &u : unorm) + u = 0; + } + uint64_t srv; + uint64_t uav[3][4]; + } required_texture_size_variants; + + void require_texture_query_variant(uint32_t var_id); + void emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, const char *type_qualifier); enum TextureQueryVariantDim {