diff --git a/reference/opt/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag b/reference/opt/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag new file mode 100644 index 00000000..5b894de8 --- /dev/null +++ b/reference/opt/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag @@ -0,0 +1,31 @@ +Texture2D uShadow : register(t0); +SamplerComparisonState _uShadow_sampler : register(s0); +Texture2D uTexture : register(t1); +SamplerComparisonState uSampler : register(s2); + +static float3 vUV; +static float FragColor; + +struct SPIRV_Cross_Input +{ + float3 vUV : TEXCOORD0; +}; + +struct SPIRV_Cross_Output +{ + float FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = uShadow.SampleCmp(_uShadow_sampler, vUV.xy, vUV.z) + uTexture.SampleCmp(uSampler, vUV.xy, vUV.z); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + 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/asm/frag/unknown-depth-state.asm.frag b/reference/opt/shaders-msl/asm/frag/unknown-depth-state.asm.frag new file mode 100644 index 00000000..e8a88623 --- /dev/null +++ b/reference/opt/shaders-msl/asm/frag/unknown-depth-state.asm.frag @@ -0,0 +1,22 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +struct main0_in +{ + float3 vUV [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], depth2d uShadow [[texture(0)]], depth2d uTexture [[texture(1)]], sampler uShadowSmplr [[sampler(0)]], sampler uSampler [[sampler(2)]]) +{ + main0_out out = {}; + out.FragColor = uShadow.sample_compare(uShadowSmplr, in.vUV.xy, in.vUV.z) + uTexture.sample_compare(uSampler, in.vUV.xy, in.vUV.z); + return out; +} + diff --git a/reference/opt/shaders/asm/frag/unknown-depth-state.asm.vk.frag b/reference/opt/shaders/asm/frag/unknown-depth-state.asm.vk.frag new file mode 100644 index 00000000..6953ec61 --- /dev/null +++ b/reference/opt/shaders/asm/frag/unknown-depth-state.asm.vk.frag @@ -0,0 +1,13 @@ +#version 450 + +layout(binding = 0) uniform sampler2DShadow uShadow; +uniform sampler2DShadow SPIRV_Cross_CombineduTextureuSampler; + +layout(location = 0) in vec3 vUV; +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = texture(uShadow, vec3(vUV.xy, vUV.z)) + texture(SPIRV_Cross_CombineduTextureuSampler, vec3(vUV.xy, vUV.z)); +} + diff --git a/reference/opt/shaders/asm/frag/unknown-depth-state.asm.vk.frag.vk b/reference/opt/shaders/asm/frag/unknown-depth-state.asm.vk.frag.vk new file mode 100644 index 00000000..2f997036 --- /dev/null +++ b/reference/opt/shaders/asm/frag/unknown-depth-state.asm.vk.frag.vk @@ -0,0 +1,14 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler2DShadow uShadow; +layout(set = 0, binding = 1) uniform texture2D uTexture; +layout(set = 0, binding = 2) uniform samplerShadow uSampler; + +layout(location = 0) in vec3 vUV; +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = texture(uShadow, vec3(vUV.xy, vUV.z)) + texture(sampler2DShadow(uTexture, uSampler), vec3(vUV.xy, vUV.z)); +} + diff --git a/reference/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag b/reference/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag new file mode 100644 index 00000000..027dd00c --- /dev/null +++ b/reference/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag @@ -0,0 +1,41 @@ +Texture2D uShadow : register(t0); +SamplerComparisonState _uShadow_sampler : register(s0); +Texture2D uTexture : register(t1); +SamplerComparisonState uSampler : register(s2); + +static float3 vUV; +static float FragColor; + +struct SPIRV_Cross_Input +{ + float3 vUV : TEXCOORD0; +}; + +struct SPIRV_Cross_Output +{ + float FragColor : SV_Target0; +}; + +float sample_combined() +{ + return uShadow.SampleCmp(_uShadow_sampler, vUV.xy, vUV.z); +} + +float sample_separate() +{ + return uTexture.SampleCmp(uSampler, vUV.xy, vUV.z); +} + +void frag_main() +{ + FragColor = sample_combined() + sample_separate(); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + vUV = stage_input.vUV; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag b/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag new file mode 100644 index 00000000..005af22e --- /dev/null +++ b/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag @@ -0,0 +1,34 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +struct main0_in +{ + float3 vUV [[user(locn0)]]; +}; + +float sample_combined(thread float3& vUV, thread depth2d uShadow, thread const sampler uShadowSmplr) +{ + return uShadow.sample_compare(uShadowSmplr, vUV.xy, vUV.z); +} + +float sample_separate(thread float3& vUV, thread depth2d uTexture, thread sampler uSampler) +{ + return uTexture.sample_compare(uSampler, vUV.xy, vUV.z); +} + +fragment main0_out main0(main0_in in [[stage_in]], depth2d uShadow [[texture(0)]], depth2d uTexture [[texture(1)]], sampler uShadowSmplr [[sampler(0)]], sampler uSampler [[sampler(2)]]) +{ + main0_out out = {}; + out.FragColor = sample_combined(in.vUV, uShadow, uShadowSmplr) + sample_separate(in.vUV, uTexture, uSampler); + return out; +} + diff --git a/reference/shaders/asm/frag/unknown-depth-state.asm.vk.frag b/reference/shaders/asm/frag/unknown-depth-state.asm.vk.frag new file mode 100644 index 00000000..7729d30c --- /dev/null +++ b/reference/shaders/asm/frag/unknown-depth-state.asm.vk.frag @@ -0,0 +1,23 @@ +#version 450 + +layout(binding = 0) uniform sampler2DShadow uShadow; +uniform sampler2DShadow SPIRV_Cross_CombineduTextureuSampler; + +layout(location = 0) in vec3 vUV; +layout(location = 0) out float FragColor; + +float sample_combined() +{ + return texture(uShadow, vec3(vUV.xy, vUV.z)); +} + +float sample_separate() +{ + return texture(SPIRV_Cross_CombineduTextureuSampler, vec3(vUV.xy, vUV.z)); +} + +void main() +{ + FragColor = sample_combined() + sample_separate(); +} + diff --git a/reference/shaders/asm/frag/unknown-depth-state.asm.vk.frag.vk b/reference/shaders/asm/frag/unknown-depth-state.asm.vk.frag.vk new file mode 100644 index 00000000..711fa277 --- /dev/null +++ b/reference/shaders/asm/frag/unknown-depth-state.asm.vk.frag.vk @@ -0,0 +1,24 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler2DShadow uShadow; +layout(set = 0, binding = 1) uniform texture2D uTexture; +layout(set = 0, binding = 2) uniform samplerShadow uSampler; + +layout(location = 0) in vec3 vUV; +layout(location = 0) out float FragColor; + +float sample_combined() +{ + return texture(uShadow, vec3(vUV.xy, vUV.z)); +} + +float sample_separate() +{ + return texture(sampler2DShadow(uTexture, uSampler), vec3(vUV.xy, vUV.z)); +} + +void main() +{ + FragColor = sample_combined() + sample_separate(); +} + diff --git a/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag b/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag new file mode 100644 index 00000000..89036f0e --- /dev/null +++ b/shaders-hlsl/asm/frag/unknown-depth-state.asm.frag @@ -0,0 +1,71 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 6 +; Bound: 44 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %vUV %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %sample_combined_ "sample_combined(" + OpName %sample_separate_ "sample_separate(" + OpName %uShadow "uShadow" + OpName %vUV "vUV" + OpName %uTexture "uTexture" + OpName %uSampler "uSampler" + OpName %FragColor "FragColor" + OpDecorate %uShadow DescriptorSet 0 + OpDecorate %uShadow Binding 0 + OpDecorate %vUV Location 0 + OpDecorate %uTexture DescriptorSet 0 + OpDecorate %uTexture Binding 1 + OpDecorate %uSampler DescriptorSet 0 + OpDecorate %uSampler Binding 2 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %7 = OpTypeFunction %float + %12 = OpTypeImage %float 2D 2 0 0 1 Unknown + %13 = OpTypeSampledImage %12 +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 + %uShadow = OpVariable %_ptr_UniformConstant_13 UniformConstant + %v3float = OpTypeVector %float 3 +%_ptr_Input_v3float = OpTypePointer Input %v3float + %vUV = OpVariable %_ptr_Input_v3float Input +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %12 + %uTexture = OpVariable %_ptr_UniformConstant_25 UniformConstant + %29 = OpTypeSampler +%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29 + %uSampler = OpVariable %_ptr_UniformConstant_29 UniformConstant +%_ptr_Output_float = OpTypePointer Output %float + %FragColor = OpVariable %_ptr_Output_float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %41 = OpFunctionCall %float %sample_combined_ + %42 = OpFunctionCall %float %sample_separate_ + %43 = OpFAdd %float %41 %42 + OpStore %FragColor %43 + OpReturn + OpFunctionEnd +%sample_combined_ = OpFunction %float None %7 + %9 = OpLabel + %16 = OpLoad %13 %uShadow + %20 = OpLoad %v3float %vUV + %21 = OpCompositeExtract %float %20 2 + %22 = OpImageSampleDrefImplicitLod %float %16 %20 %21 + OpReturnValue %22 + OpFunctionEnd +%sample_separate_ = OpFunction %float None %7 + %11 = OpLabel + %28 = OpLoad %12 %uTexture + %32 = OpLoad %29 %uSampler + %33 = OpSampledImage %13 %28 %32 + %34 = OpLoad %v3float %vUV + %35 = OpCompositeExtract %float %34 2 + %36 = OpImageSampleDrefImplicitLod %float %33 %34 %35 + OpReturnValue %36 + OpFunctionEnd diff --git a/shaders-msl/asm/frag/unknown-depth-state.asm.frag b/shaders-msl/asm/frag/unknown-depth-state.asm.frag new file mode 100644 index 00000000..89036f0e --- /dev/null +++ b/shaders-msl/asm/frag/unknown-depth-state.asm.frag @@ -0,0 +1,71 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 6 +; Bound: 44 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %vUV %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %sample_combined_ "sample_combined(" + OpName %sample_separate_ "sample_separate(" + OpName %uShadow "uShadow" + OpName %vUV "vUV" + OpName %uTexture "uTexture" + OpName %uSampler "uSampler" + OpName %FragColor "FragColor" + OpDecorate %uShadow DescriptorSet 0 + OpDecorate %uShadow Binding 0 + OpDecorate %vUV Location 0 + OpDecorate %uTexture DescriptorSet 0 + OpDecorate %uTexture Binding 1 + OpDecorate %uSampler DescriptorSet 0 + OpDecorate %uSampler Binding 2 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %7 = OpTypeFunction %float + %12 = OpTypeImage %float 2D 2 0 0 1 Unknown + %13 = OpTypeSampledImage %12 +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 + %uShadow = OpVariable %_ptr_UniformConstant_13 UniformConstant + %v3float = OpTypeVector %float 3 +%_ptr_Input_v3float = OpTypePointer Input %v3float + %vUV = OpVariable %_ptr_Input_v3float Input +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %12 + %uTexture = OpVariable %_ptr_UniformConstant_25 UniformConstant + %29 = OpTypeSampler +%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29 + %uSampler = OpVariable %_ptr_UniformConstant_29 UniformConstant +%_ptr_Output_float = OpTypePointer Output %float + %FragColor = OpVariable %_ptr_Output_float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %41 = OpFunctionCall %float %sample_combined_ + %42 = OpFunctionCall %float %sample_separate_ + %43 = OpFAdd %float %41 %42 + OpStore %FragColor %43 + OpReturn + OpFunctionEnd +%sample_combined_ = OpFunction %float None %7 + %9 = OpLabel + %16 = OpLoad %13 %uShadow + %20 = OpLoad %v3float %vUV + %21 = OpCompositeExtract %float %20 2 + %22 = OpImageSampleDrefImplicitLod %float %16 %20 %21 + OpReturnValue %22 + OpFunctionEnd +%sample_separate_ = OpFunction %float None %7 + %11 = OpLabel + %28 = OpLoad %12 %uTexture + %32 = OpLoad %29 %uSampler + %33 = OpSampledImage %13 %28 %32 + %34 = OpLoad %v3float %vUV + %35 = OpCompositeExtract %float %34 2 + %36 = OpImageSampleDrefImplicitLod %float %33 %34 %35 + OpReturnValue %36 + OpFunctionEnd diff --git a/shaders/asm/frag/unknown-depth-state.asm.vk.frag b/shaders/asm/frag/unknown-depth-state.asm.vk.frag new file mode 100644 index 00000000..89036f0e --- /dev/null +++ b/shaders/asm/frag/unknown-depth-state.asm.vk.frag @@ -0,0 +1,71 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 6 +; Bound: 44 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %vUV %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %sample_combined_ "sample_combined(" + OpName %sample_separate_ "sample_separate(" + OpName %uShadow "uShadow" + OpName %vUV "vUV" + OpName %uTexture "uTexture" + OpName %uSampler "uSampler" + OpName %FragColor "FragColor" + OpDecorate %uShadow DescriptorSet 0 + OpDecorate %uShadow Binding 0 + OpDecorate %vUV Location 0 + OpDecorate %uTexture DescriptorSet 0 + OpDecorate %uTexture Binding 1 + OpDecorate %uSampler DescriptorSet 0 + OpDecorate %uSampler Binding 2 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %7 = OpTypeFunction %float + %12 = OpTypeImage %float 2D 2 0 0 1 Unknown + %13 = OpTypeSampledImage %12 +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 + %uShadow = OpVariable %_ptr_UniformConstant_13 UniformConstant + %v3float = OpTypeVector %float 3 +%_ptr_Input_v3float = OpTypePointer Input %v3float + %vUV = OpVariable %_ptr_Input_v3float Input +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %12 + %uTexture = OpVariable %_ptr_UniformConstant_25 UniformConstant + %29 = OpTypeSampler +%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29 + %uSampler = OpVariable %_ptr_UniformConstant_29 UniformConstant +%_ptr_Output_float = OpTypePointer Output %float + %FragColor = OpVariable %_ptr_Output_float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %41 = OpFunctionCall %float %sample_combined_ + %42 = OpFunctionCall %float %sample_separate_ + %43 = OpFAdd %float %41 %42 + OpStore %FragColor %43 + OpReturn + OpFunctionEnd +%sample_combined_ = OpFunction %float None %7 + %9 = OpLabel + %16 = OpLoad %13 %uShadow + %20 = OpLoad %v3float %vUV + %21 = OpCompositeExtract %float %20 2 + %22 = OpImageSampleDrefImplicitLod %float %16 %20 %21 + OpReturnValue %22 + OpFunctionEnd +%sample_separate_ = OpFunction %float None %7 + %11 = OpLabel + %28 = OpLoad %12 %uTexture + %32 = OpLoad %29 %uSampler + %33 = OpSampledImage %13 %28 %32 + %34 = OpLoad %v3float %vUV + %35 = OpCompositeExtract %float %34 2 + %36 = OpImageSampleDrefImplicitLod %float %33 %34 %35 + OpReturnValue %36 + OpFunctionEnd diff --git a/spirv_cross.cpp b/spirv_cross.cpp index a95e4e28..3e460e9f 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -4367,11 +4367,43 @@ bool Compiler::has_active_builtin(BuiltIn builtin, StorageClass storage) void Compiler::analyze_image_and_sampler_usage() { - CombinedImageSamplerUsageHandler handler(*this); + CombinedImageSamplerDrefHandler dref_handler(*this); + traverse_all_reachable_opcodes(get(entry_point), dref_handler); + + CombinedImageSamplerUsageHandler handler(*this, dref_handler.dref_combined_samplers); traverse_all_reachable_opcodes(get(entry_point), handler); - comparison_samplers = move(handler.comparison_samplers); - comparison_images = move(handler.comparison_images); + comparison_ids = move(handler.comparison_ids); need_subpass_input = handler.need_subpass_input; + + // Forward information from separate images and samplers into combined image samplers. + for (auto &combined : combined_image_samplers) + if (comparison_ids.count(combined.sampler_id)) + comparison_ids.insert(combined.combined_id); +} + +bool Compiler::CombinedImageSamplerDrefHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t) +{ + // Mark all sampled images which are used with Dref. + switch (opcode) + { + case OpImageSampleDrefExplicitLod: + case OpImageSampleDrefImplicitLod: + case OpImageSampleProjDrefExplicitLod: + case OpImageSampleProjDrefImplicitLod: + case OpImageSparseSampleProjDrefImplicitLod: + case OpImageSparseSampleDrefImplicitLod: + case OpImageSparseSampleProjDrefExplicitLod: + case OpImageSparseSampleDrefExplicitLod: + case OpImageDrefGather: + case OpImageSparseDrefGather: + dref_combined_samplers.insert(args[2]); + return true; + + default: + break; + } + + return true; } bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint32_t *args, uint32_t length) @@ -4392,20 +4424,12 @@ bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint return true; } -void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_images(uint32_t image) +void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_ids(uint32_t id) { - // Traverse the variable dependency hierarchy and tag everything in its path with comparison images. - comparison_images.insert(image); - for (auto &img : dependency_hierarchy[image]) - add_hierarchy_to_comparison_images(img); -} - -void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_samplers(uint32_t sampler) -{ - // Traverse the variable dependency hierarchy and tag everything in its path with comparison samplers. - comparison_samplers.insert(sampler); - for (auto &samp : dependency_hierarchy[sampler]) - add_hierarchy_to_comparison_samplers(samp); + // Traverse the variable dependency hierarchy and tag everything in its path with comparison ids. + comparison_ids.insert(id); + for (auto &dep_id : dependency_hierarchy[id]) + add_hierarchy_to_comparison_ids(dep_id); } bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_t *args, uint32_t length) @@ -4425,6 +4449,10 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ auto &type = compiler.get(args[0]); if (type.image.dim == DimSubpassData) need_subpass_input = true; + + // If we load a SampledImage and it will be used with Dref, propagate the state up. + if (dref_combined_samplers.count(args[1]) != 0) + add_hierarchy_to_comparison_ids(args[1]); break; } @@ -4434,16 +4462,20 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ return false; uint32_t result_type = args[0]; + uint32_t result_id = args[1]; auto &type = compiler.get(result_type); - if (type.image.depth) + if (type.image.depth || dref_combined_samplers.count(result_id) != 0) { // This image must be a depth image. uint32_t image = args[2]; - add_hierarchy_to_comparison_images(image); + add_hierarchy_to_comparison_ids(image); - // This sampler must be a SamplerComparisionState, and not a regular SamplerState. + // This sampler must be a SamplerComparisonState, and not a regular SamplerState. uint32_t sampler = args[3]; - add_hierarchy_to_comparison_samplers(sampler); + add_hierarchy_to_comparison_ids(sampler); + + // Mark the OpSampledImage itself as being comparison state. + comparison_ids.insert(result_id); } return true; } @@ -4654,3 +4686,8 @@ bool Compiler::is_desktop_only_format(spv::ImageFormat format) return false; } + +bool Compiler::image_is_comparison(const spirv_cross::SPIRType &type, uint32_t id) const +{ + return type.image.depth || (comparison_ids.count(id) != 0); +} diff --git a/spirv_cross.hpp b/spirv_cross.hpp index afe903d5..b25e1c19 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -826,8 +826,7 @@ protected: // There might be unrelated IDs found in this set which do not correspond to actual variables. // This set should only be queried for the existence of samplers which are already known to be variables or parameter IDs. // Similar is implemented for images, as well as if subpass inputs are needed. - std::unordered_set comparison_samplers; - std::unordered_set comparison_images; + std::unordered_set comparison_ids; bool need_subpass_input = false; // In certain backends, we will need to use a dummy sampler to be able to emit code. @@ -836,23 +835,37 @@ protected: uint32_t dummy_sampler_id = 0; void analyze_image_and_sampler_usage(); + + struct CombinedImageSamplerDrefHandler : OpcodeHandler + { + CombinedImageSamplerDrefHandler(Compiler &compiler_) + : compiler(compiler_) + { + } + bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override; + + Compiler &compiler; + std::unordered_set dref_combined_samplers; + }; + struct CombinedImageSamplerUsageHandler : OpcodeHandler { - CombinedImageSamplerUsageHandler(Compiler &compiler_) + CombinedImageSamplerUsageHandler(Compiler &compiler_, + const std::unordered_set &dref_combined_samplers_) : compiler(compiler_) + , dref_combined_samplers(dref_combined_samplers_) { } bool begin_function_scope(const uint32_t *args, uint32_t length) override; bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override; Compiler &compiler; + const std::unordered_set &dref_combined_samplers; std::unordered_map> dependency_hierarchy; - std::unordered_set comparison_images; - std::unordered_set comparison_samplers; + std::unordered_set comparison_ids; - void add_hierarchy_to_comparison_samplers(uint32_t sampler); - void add_hierarchy_to_comparison_images(uint32_t sampler); + void add_hierarchy_to_comparison_ids(uint32_t ids); bool need_subpass_input = false; }; @@ -868,6 +881,8 @@ protected: Bitset combined_decoration_for_member(const SPIRType &type, uint32_t index) const; static bool is_desktop_only_format(spv::ImageFormat format); + bool image_is_comparison(const SPIRType &type, uint32_t id) const; + private: // Used only to implement the old deprecated get_entry_point() interface. const SPIREntryPoint &get_first_entry_point(const std::string &name) const; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index d0f81c0f..5b71ab1d 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -3460,7 +3460,7 @@ bool CompilerGLSL::check_explicit_lod_allowed(uint32_t lod) return allowed; } -string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod) +string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t tex) { const char *type; switch (imgtype.image.dim) @@ -3512,7 +3512,7 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp // GLES has very limited support for shadow samplers. // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers, // everything else can just throw - if (imgtype.image.depth && is_legacy_es()) + if (image_is_comparison(imgtype, tex) && is_legacy_es()) { if (op == "texture" || op == "textureProj") require_extension_internal("GL_EXT_shadow_samplers"); @@ -3520,8 +3520,8 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES")); } - bool is_es_and_depth = (is_legacy_es() && imgtype.image.depth); - std::string type_prefix = imgtype.image.depth ? "shadow" : "texture"; + bool is_es_and_depth = is_legacy_es() && image_is_comparison(imgtype, tex); + std::string type_prefix = image_is_comparison(imgtype, tex) ? "shadow" : "texture"; if (op == "texture") return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type); @@ -3764,7 +3764,7 @@ void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_i if (options.vulkan_semantics && combined_image_samplers.empty()) { emit_binary_func_op(result_type, result_id, image_id, samp_id, - type_to_glsl(get(result_type)).c_str()); + type_to_glsl(get(result_type), result_id).c_str()); // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types. forwarded_temporaries.erase(result_id); @@ -3930,7 +3930,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) expr += ")"; // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here. - if (is_legacy() && imgtype.image.depth) + if (is_legacy() && image_is_comparison(imgtype, img)) expr += ".r"; emit_op(result_type, id, expr, forward); @@ -3953,8 +3953,9 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) // Returns the function name for a texture sampling function for the specified image and sampling characteristics. // For some subclasses, the function is a method on the specified image. -string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, - bool has_array_offsets, bool has_offset, bool has_grad, bool, uint32_t lod) +string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, bool is_fetch, bool is_gather, + bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, bool, + uint32_t lod) { string fname; @@ -3964,7 +3965,7 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. bool workaround_lod_array_shadow_as_grad = false; if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - imgtype.image.depth && lod) + image_is_comparison(imgtype, tex) && lod) { auto *constant_lod = maybe_get(lod); if (!constant_lod || constant_lod->scalar_f32() != 0.0f) @@ -3994,7 +3995,7 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is if (has_offset) fname += "Offset"; - return is_legacy() ? legacy_tex_op(fname, imgtype, lod) : fname; + return is_legacy() ? legacy_tex_op(fname, imgtype, lod, tex) : fname; } std::string CompilerGLSL::convert_separate_image_to_combined(uint32_t id) @@ -4079,7 +4080,7 @@ string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, boo // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. bool workaround_lod_array_shadow_as_grad = ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - imgtype.image.depth && lod; + image_is_comparison(imgtype, img) && lod; if (dref) { @@ -8418,7 +8419,7 @@ string CompilerGLSL::type_to_array_glsl(const SPIRType &type) } } -string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */) +string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id) { auto &imagetype = get(type.image.type); string res; @@ -8491,8 +8492,11 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */) } // "Shadow" state in GLSL only exists for samplers and combined image samplers. - if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) && type.image.depth) + if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) && + image_is_comparison(type, id)) + { res += "Shadow"; + } return res; } @@ -8538,7 +8542,7 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id) case SPIRType::Sampler: // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing // this distinction into the type system. - return comparison_samplers.count(id) ? "samplerShadow" : "sampler"; + return comparison_ids.count(id) ? "samplerShadow" : "sampler"; case SPIRType::Void: return "void"; diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index ee2176e4..7205def7 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -491,7 +491,7 @@ protected: void replace_fragment_output(SPIRVariable &var); void replace_fragment_outputs(); bool check_explicit_lod_allowed(uint32_t lod); - std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod); + std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t id); uint32_t indent = 0; diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 16457905..aaa05cc0 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -224,7 +224,7 @@ static bool hlsl_opcode_is_sign_invariant(Op opcode) } } -string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type) +string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t) { auto &imagetype = get(type.image.type); const char *dim = nullptr; @@ -275,7 +275,7 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type) ">"); } -string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type) +string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type, uint32_t id) { auto &imagetype = get(type.image.type); string res; @@ -338,18 +338,18 @@ string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type) res += "MS"; if (type.image.arrayed) res += "Array"; - if (type.image.depth) + if (image_is_comparison(type, id)) res += "Shadow"; return res; } -string CompilerHLSL::image_type_hlsl(const SPIRType &type) +string CompilerHLSL::image_type_hlsl(const SPIRType &type, uint32_t id) { if (hlsl_options.shader_model <= 30) - return image_type_hlsl_legacy(type); + return image_type_hlsl_legacy(type, id); else - return image_type_hlsl_modern(type); + return image_type_hlsl_modern(type, id); } // The optional id parameter indicates the object whose type we are trying @@ -370,10 +370,10 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id) case SPIRType::Image: case SPIRType::SampledImage: - return image_type_hlsl(type); + return image_type_hlsl(type, id); case SPIRType::Sampler: - return comparison_samplers.count(id) ? "SamplerComparisonState" : "SamplerState"; + return comparison_ids.count(id) ? "SamplerComparisonState" : "SamplerState"; case SPIRType::Void: return "void"; @@ -2060,7 +2060,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret { // Manufacture automatic sampler arg for SampledImage texture decl += ", "; - decl += join(arg_type.image.depth ? "SamplerComparisonState " : "SamplerState ", + decl += join(image_is_comparison(arg_type, arg.id) ? "SamplerComparisonState " : "SamplerState ", to_sampler_expression(arg.id), type_to_array_glsl(arg_type)); } @@ -2575,7 +2575,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i) { texop += img_expr; - if (imgtype.image.depth) + if (image_is_comparison(imgtype, img)) { if (gather) { @@ -2927,13 +2927,13 @@ void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var) if (type.basetype == SPIRType::Image && type.image.sampled == 2) is_coherent = has_decoration(var.self, DecorationCoherent); - statement(is_coherent ? "globallycoherent " : "", image_type_hlsl_modern(type), " ", to_name(var.self), - type_to_array_glsl(type), to_resource_binding(var), ";"); + statement(is_coherent ? "globallycoherent " : "", image_type_hlsl_modern(type, var.self), " ", + to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";"); if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer) { // For combined image samplers, also emit a combined image sampler. - if (type.image.depth) + if (image_is_comparison(type, var.self)) statement("SamplerComparisonState ", to_sampler_expression(var.self), type_to_array_glsl(type), to_resource_binding_sampler(var), ";"); else @@ -2944,7 +2944,7 @@ void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var) } case SPIRType::Sampler: - if (comparison_samplers.count(var.self)) + if (comparison_ids.count(var.self)) statement("SamplerComparisonState ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";"); else diff --git a/spirv_hlsl.hpp b/spirv_hlsl.hpp index 0f2acf33..bcc82b10 100644 --- a/spirv_hlsl.hpp +++ b/spirv_hlsl.hpp @@ -118,9 +118,9 @@ public: private: std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; - std::string image_type_hlsl(const SPIRType &type); - std::string image_type_hlsl_modern(const SPIRType &type); - std::string image_type_hlsl_legacy(const SPIRType &type); + std::string image_type_hlsl(const SPIRType &type, uint32_t id); + std::string image_type_hlsl_modern(const SPIRType &type, uint32_t id); + std::string image_type_hlsl_legacy(const SPIRType &type, uint32_t id); void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override; void emit_hlsl_entry_point(); void emit_header() override; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 08d9f6a2..4f69c571 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -3633,9 +3633,7 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) // Bypass pointers because we need the real image struct auto &img_type = get(type.self).image; - bool shadow_image = comparison_images.count(id) != 0; - - if (img_type.depth || shadow_image) + if (image_is_comparison(type, id)) { switch (img_type.dim) {