diff --git a/reference/opt/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag b/reference/opt/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag new file mode 100644 index 00000000..544c5705 --- /dev/null +++ b/reference/opt/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag @@ -0,0 +1,46 @@ +struct UBO_1_1 +{ + float4 v[64]; +}; + +ConstantBuffer ubos[] : register(b0, space3); +ByteAddressBuffer ssbos[] : register(t0, space4); +Texture2D uSamplers[] : register(t0, space0); +SamplerState uSamps[] : register(s0, space2); +Texture2D uCombinedSamplers[] : register(t0, space1); +SamplerState _uCombinedSamplers_sampler[] : register(s0, space1); + +static int vIndex; +static float4 FragColor; +static float2 vUV; + +struct SPIRV_Cross_Input +{ + nointerpolation int vIndex : TEXCOORD0; + float2 vUV : TEXCOORD1; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + int _22 = vIndex + 10; + int _32 = vIndex + 40; + FragColor = uSamplers[NonUniformResourceIndex(_22)].Sample(uSamps[NonUniformResourceIndex(_32)], vUV); + FragColor = uCombinedSamplers[NonUniformResourceIndex(_22)].Sample(_uCombinedSamplers_sampler[NonUniformResourceIndex(_22)], vUV); + FragColor += ubos[NonUniformResourceIndex(vIndex + 20)].v[_32]; + FragColor += asfloat(ssbos[NonUniformResourceIndex(vIndex + 50)].Load4((vIndex + 60) * 16 + 0)); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + vIndex = stage_input.vIndex; + vUV = stage_input.vUV; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/opt/shaders-msl/frag/nonuniform-qualifier.msl2.frag b/reference/opt/shaders-msl/frag/nonuniform-qualifier.msl2.frag new file mode 100644 index 00000000..510d1ca5 --- /dev/null +++ b/reference/opt/shaders-msl/frag/nonuniform-qualifier.msl2.frag @@ -0,0 +1,50 @@ +#include +#include + +using namespace metal; + +struct UBO +{ + float4 v[64]; +}; + +struct SSBO +{ + float4 v[1]; +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + int vIndex [[user(locn0)]]; + float2 vUV [[user(locn1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant UBO* ubos_0 [[buffer(0)]], constant UBO* ubos_1 [[buffer(1)]], const device SSBO* ssbos_0 [[buffer(2)]], const device SSBO* ssbos_1 [[buffer(3)]], array, 8> uSamplers [[texture(0)]], array, 8> uCombinedSamplers [[texture(8)]], array uSamps [[sampler(1)]], array uCombinedSamplersSmplr [[sampler(8)]]) +{ + constant UBO* ubos[] = + { + ubos_0, + ubos_1, + }; + + const device SSBO* ssbos[] = + { + ssbos_0, + ssbos_1, + }; + + main0_out out = {}; + int _24 = in.vIndex + 10; + int _35 = in.vIndex + 40; + out.FragColor = uSamplers[_24].sample(uSamps[_35], in.vUV); + out.FragColor = uCombinedSamplers[_24].sample(uCombinedSamplersSmplr[_24], in.vUV); + out.FragColor += ubos[(in.vIndex + 20)]->v[_35]; + out.FragColor += ssbos[(in.vIndex + 50)]->v[in.vIndex + 60]; + return out; +} + diff --git a/reference/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag b/reference/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag new file mode 100644 index 00000000..8f5e022e --- /dev/null +++ b/reference/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag @@ -0,0 +1,46 @@ +struct UBO_1_1 +{ + float4 v[64]; +}; + +ConstantBuffer ubos[] : register(b0, space3); +ByteAddressBuffer ssbos[] : register(t0, space4); +Texture2D uSamplers[] : register(t0, space0); +SamplerState uSamps[] : register(s0, space2); +Texture2D uCombinedSamplers[] : register(t0, space1); +SamplerState _uCombinedSamplers_sampler[] : register(s0, space1); + +static int vIndex; +static float4 FragColor; +static float2 vUV; + +struct SPIRV_Cross_Input +{ + nointerpolation int vIndex : TEXCOORD0; + float2 vUV : TEXCOORD1; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + int i = vIndex; + FragColor = uSamplers[NonUniformResourceIndex(i + 10)].Sample(uSamps[NonUniformResourceIndex(i + 40)], vUV); + int _47 = i + 10; + FragColor = uCombinedSamplers[NonUniformResourceIndex(_47)].Sample(_uCombinedSamplers_sampler[NonUniformResourceIndex(_47)], vUV); + FragColor += ubos[NonUniformResourceIndex(i + 20)].v[i + 40]; + FragColor += asfloat(ssbos[NonUniformResourceIndex(i + 50)].Load4((i + 60) * 16 + 0)); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + vIndex = stage_input.vIndex; + vUV = stage_input.vUV; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-msl/frag/nonuniform-qualifier.msl2.frag b/reference/shaders-msl/frag/nonuniform-qualifier.msl2.frag new file mode 100644 index 00000000..377a27d3 --- /dev/null +++ b/reference/shaders-msl/frag/nonuniform-qualifier.msl2.frag @@ -0,0 +1,51 @@ +#include +#include + +using namespace metal; + +struct UBO +{ + float4 v[64]; +}; + +struct SSBO +{ + float4 v[1]; +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + int vIndex [[user(locn0)]]; + float2 vUV [[user(locn1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant UBO* ubos_0 [[buffer(0)]], constant UBO* ubos_1 [[buffer(1)]], const device SSBO* ssbos_0 [[buffer(2)]], const device SSBO* ssbos_1 [[buffer(3)]], array, 8> uSamplers [[texture(0)]], array, 8> uCombinedSamplers [[texture(8)]], array uSamps [[sampler(1)]], array uCombinedSamplersSmplr [[sampler(8)]]) +{ + constant UBO* ubos[] = + { + ubos_0, + ubos_1, + }; + + const device SSBO* ssbos[] = + { + ssbos_0, + ssbos_1, + }; + + main0_out out = {}; + int i = in.vIndex; + int _24 = i + 10; + out.FragColor = uSamplers[_24].sample(uSamps[i + 40], in.vUV); + int _50 = i + 10; + out.FragColor = uCombinedSamplers[_50].sample(uCombinedSamplersSmplr[_50], in.vUV); + out.FragColor += ubos[(i + 20)]->v[i + 40]; + out.FragColor += ssbos[(i + 50)]->v[i + 60]; + return out; +} + diff --git a/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag b/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag new file mode 100644 index 00000000..0aadd148 --- /dev/null +++ b/shaders-hlsl/frag/nonuniform-qualifier.nonuniformresource.sm51.frag @@ -0,0 +1,28 @@ +#version 450 +#extension GL_EXT_nonuniform_qualifier : require + +layout(set = 0, binding = 0) uniform texture2D uSamplers[]; +layout(set = 1, binding = 0) uniform sampler2D uCombinedSamplers[]; +layout(set = 2, binding = 0) uniform sampler uSamps[]; +layout(location = 0) flat in int vIndex; +layout(location = 1) in vec2 vUV; +layout(location = 0) out vec4 FragColor; + +layout(set = 3, binding = 0) uniform UBO +{ + vec4 v[64]; +} ubos[]; + +layout(set = 4, binding = 0) readonly buffer SSBO +{ + vec4 v[]; +} ssbos[]; + +void main() +{ + int i = vIndex; + FragColor = texture(sampler2D(uSamplers[nonuniformEXT(i + 10)], uSamps[nonuniformEXT(i + 40)]), vUV); + FragColor = texture(uCombinedSamplers[nonuniformEXT(i + 10)], vUV); + FragColor += ubos[nonuniformEXT(i + 20)].v[nonuniformEXT(i + 40)]; + FragColor += ssbos[nonuniformEXT(i + 50)].v[nonuniformEXT(i + 60)]; +} diff --git a/shaders-msl/frag/nonuniform-qualifier.msl2.frag b/shaders-msl/frag/nonuniform-qualifier.msl2.frag new file mode 100644 index 00000000..ba9dd7fb --- /dev/null +++ b/shaders-msl/frag/nonuniform-qualifier.msl2.frag @@ -0,0 +1,28 @@ +#version 450 +#extension GL_EXT_nonuniform_qualifier : require + +layout(binding = 0) uniform texture2D uSamplers[8]; +layout(binding = 8) uniform sampler2D uCombinedSamplers[8]; +layout(binding = 1) uniform sampler uSamps[7]; +layout(location = 0) flat in int vIndex; +layout(location = 1) in vec2 vUV; +layout(location = 0) out vec4 FragColor; + +layout(set = 0, binding = 0) uniform UBO +{ + vec4 v[64]; +} ubos[2]; + +layout(set = 0, binding = 2) readonly buffer SSBO +{ + vec4 v[]; +} ssbos[2]; + +void main() +{ + int i = vIndex; + FragColor = texture(sampler2D(uSamplers[nonuniformEXT(i + 10)], uSamps[nonuniformEXT(i + 40)]), vUV); + FragColor = texture(uCombinedSamplers[nonuniformEXT(i + 10)], vUV); + FragColor += ubos[nonuniformEXT(i + 20)].v[nonuniformEXT(i + 40)]; + FragColor += ssbos[nonuniformEXT(i + 50)].v[nonuniformEXT(i + 60)]; +} diff --git a/spirv_cpp.cpp b/spirv_cpp.cpp index 19d93b7b..90566c1c 100644 --- a/spirv_cpp.cpp +++ b/spirv_cpp.cpp @@ -317,7 +317,7 @@ string CompilerCPP::compile() backend.basic_uint_type = "uint32_t"; backend.swizzle_is_function = true; backend.shared_is_implied = true; - backend.flexible_member_array_supported = false; + backend.unsized_array_supported = false; backend.explicit_struct_type = true; backend.use_initializer_list = true; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 128405c6..3e37f2c4 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -9918,7 +9918,7 @@ string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index) return to_expression(size); else if (size) return convert_to_string(size); - else if (!backend.flexible_member_array_supported) + else if (!backend.unsized_array_supported) { // For runtime-sized arrays, we can work around // lack of standard support for this by simply having @@ -11837,6 +11837,9 @@ void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &exp void CompilerGLSL::convert_non_uniform_expression(const SPIRType &type, std::string &expr) { + if (*backend.nonuniform_qualifier == '\0') + return; + // Handle SPV_EXT_descriptor_indexing. if (type.basetype == SPIRType::Sampler || type.basetype == SPIRType::SampledImage || type.basetype == SPIRType::Image) diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index 79fd0444..5f26ecf4 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -375,7 +375,7 @@ protected: const char *nonuniform_qualifier = "nonuniformEXT"; bool swizzle_is_function = false; bool shared_is_implied = false; - bool flexible_member_array_supported = true; + bool unsized_array_supported = true; bool explicit_struct_type = false; bool use_initializer_list = false; bool use_typed_initializer_list = false; diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 28cf70d7..62e79dcf 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -4647,6 +4647,27 @@ uint32_t CompilerHLSL::remap_num_workgroups_builtin() return variable_id; } +void CompilerHLSL::validate_shader_model() +{ + // Check for nonuniform qualifier. + // Instead of looping over all decorations to find this, just look at capabilities. + for (auto &cap : ir.declared_capabilities) + { + switch (cap) + { + case CapabilityShaderNonUniformEXT: + case CapabilityRuntimeDescriptorArrayEXT: + if (hlsl_options.shader_model < 51) + SPIRV_CROSS_THROW("Shader model 5.1 or higher is required to use bindless resources or NonUniformResourceIndex."); + default: + break; + } + } + + if (ir.addressing_model != AddressingModelLogical) + SPIRV_CROSS_THROW("Only Logical addressing model can be used with HLSL."); +} + string CompilerHLSL::compile() { // Do not deal with ES-isms like precision, older extensions and such. @@ -4663,7 +4684,7 @@ string CompilerHLSL::compile() backend.basic_uint_type = "uint"; backend.swizzle_is_function = false; backend.shared_is_implied = true; - backend.flexible_member_array_supported = false; + backend.unsized_array_supported = true; backend.explicit_struct_type = false; backend.use_initializer_list = true; backend.use_constructor_splatting = false; @@ -4672,8 +4693,10 @@ string CompilerHLSL::compile() backend.can_declare_struct_inline = false; backend.can_declare_arrays_inline = false; backend.can_return_array = false; + backend.nonuniform_qualifier = "NonUniformResourceIndex"; build_function_control_flow_graphs_and_analyze(); + validate_shader_model(); update_active_builtins(); analyze_image_and_sampler_usage(); diff --git a/spirv_hlsl.hpp b/spirv_hlsl.hpp index 50bade21..d96c911f 100644 --- a/spirv_hlsl.hpp +++ b/spirv_hlsl.hpp @@ -220,6 +220,8 @@ private: // Custom root constant layout, which should be emitted // when translating push constant ranges. std::vector root_constants_layout; + + void validate_shader_model(); }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/spirv_msl.cpp b/spirv_msl.cpp index e6824c93..4a4f77a5 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -577,7 +577,7 @@ string CompilerMSL::compile() backend.use_initializer_list = true; backend.use_typed_initializer_list = true; backend.native_row_major_matrix = false; - backend.flexible_member_array_supported = false; + backend.unsized_array_supported = false; backend.can_declare_arrays_inline = false; backend.can_return_array = false; backend.boolean_mix_support = false; @@ -585,6 +585,7 @@ string CompilerMSL::compile() backend.array_is_value_type = false; backend.comparison_image_samples_scalar = true; backend.native_pointers = true; + backend.nonuniform_qualifier = ""; capture_output_to_buffer = msl_options.capture_output_to_buffer; is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer; diff --git a/test_shaders.py b/test_shaders.py index aad2aedb..5c9e31e6 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -220,13 +220,18 @@ def shader_to_win_path(shader): ignore_fxc = False def validate_shader_hlsl(shader, force_no_external_validation, paths): - subprocess.check_call([paths.glslang, '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader]) + if not '.nonuniformresource' in shader: + # glslang HLSL does not support this, so rely on fxc to test it. + subprocess.check_call([paths.glslang, '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader]) is_no_fxc = '.nofxc.' in shader global ignore_fxc if (not ignore_fxc) and (not force_no_external_validation) and (not is_no_fxc): try: win_path = shader_to_win_path(shader) - subprocess.check_call(['fxc', '-nologo', shader_model_hlsl(shader), win_path]) + args = ['fxc', '-nologo', shader_model_hlsl(shader), win_path] + if '.nonuniformresource.' in shader: + args.append('/enable_unbounded_descriptor_tables') + subprocess.check_call(args) except OSError as oe: if (oe.errno != errno.ENOENT): # Ignore not found errors print('Failed to run FXC.')