diff --git a/reference/shaders/asm/frag/texture-shadow-lod.asm.frag b/reference/shaders/asm/frag/texture-shadow-lod.asm.frag new file mode 100644 index 000000000..49efaef1f --- /dev/null +++ b/reference/shaders/asm/frag/texture-shadow-lod.asm.frag @@ -0,0 +1,14 @@ +#version 450 +#extension GL_EXT_texture_shadow_lod : require + +layout(binding = 0) uniform sampler2DArrayShadow uShadow2DArray; + +layout(location = 0) out vec4 FragColor; +layout(location = 0) in vec4 vUV; +layout(location = 1) in float vLod; + +void main() +{ + FragColor = vec4(textureLod(uShadow2DArray, vec4(vUV.xyz, vUV.w), vLod)); +} + diff --git a/reference/shaders/frag/texture-shadow-lod-bias.frag b/reference/shaders/frag/texture-shadow-lod-bias.frag new file mode 100644 index 000000000..ed21d3e1a --- /dev/null +++ b/reference/shaders/frag/texture-shadow-lod-bias.frag @@ -0,0 +1,17 @@ +#version 450 +#extension GL_EXT_texture_shadow_lod : require + +layout(binding = 0) uniform sampler2DArrayShadow uShadow2DArray; + +layout(location = 0) in vec4 vUV; +layout(location = 1) in float vBias; +layout(location = 0) out vec4 FragColor; + +void main() +{ + float r = 0.0; + r += texture(uShadow2DArray, vec4(vUV.xyz, vUV.w), vBias); + r += textureOffset(uShadow2DArray, vec4(vUV.xyz, vUV.w), ivec2(1), vBias); + FragColor = vec4(r); +} + diff --git a/reference/shaders/frag/texture-shadow-lod.frag b/reference/shaders/frag/texture-shadow-lod.frag new file mode 100644 index 000000000..2487250c9 --- /dev/null +++ b/reference/shaders/frag/texture-shadow-lod.frag @@ -0,0 +1,19 @@ +#version 450 +#extension GL_EXT_texture_shadow_lod : require + +layout(binding = 0) uniform sampler2DArrayShadow uShadow2DArray; +layout(binding = 1) uniform samplerCubeShadow uShadowCube; + +layout(location = 0) in vec4 vUV; +layout(location = 1) in float vLod; +layout(location = 0) out vec4 FragColor; + +void main() +{ + float r = 0.0; + r += textureLod(uShadow2DArray, vec4(vUV.xyz, vUV.w), vLod); + r += textureLod(uShadowCube, vec4(vUV.xyz, vUV.w), vLod); + r += textureLodOffset(uShadow2DArray, vec4(vUV.xyz, vUV.w), vLod, ivec2(1)); + FragColor = vec4(r); +} + diff --git a/shaders/asm/frag/texture-shadow-lod.asm.frag b/shaders/asm/frag/texture-shadow-lod.asm.frag new file mode 100644 index 000000000..c5af14e62 --- /dev/null +++ b/shaders/asm/frag/texture-shadow-lod.asm.frag @@ -0,0 +1,45 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 50 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %FragColor %vUV %vLod + OpExecutionMode %main OriginUpperLeft + OpName %main "main" + OpName %FragColor "FragColor" + OpName %uShadow2DArray "uShadow2DArray" + OpName %vUV "vUV" + OpName %vLod "vLod" + OpDecorate %FragColor Location 0 + OpDecorate %uShadow2DArray DescriptorSet 0 + OpDecorate %uShadow2DArray Binding 0 + OpDecorate %vUV Location 0 + OpDecorate %vLod Location 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output + %10 = OpTypeImage %float 2D 1 1 0 1 Unknown + %11 = OpTypeSampledImage %10 +%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11 +%uShadow2DArray = OpVariable %_ptr_UniformConstant_11 UniformConstant +%_ptr_Input_v4float = OpTypePointer Input %v4float + %vUV = OpVariable %_ptr_Input_v4float Input +%_ptr_Input_float = OpTypePointer Input %float + %vLod = OpVariable %_ptr_Input_float Input + %main = OpFunction %void None %3 + %5 = OpLabel + %14 = OpLoad %11 %uShadow2DArray + %17 = OpLoad %v4float %vUV + %19 = OpLoad %float %vLod + %20 = OpCompositeExtract %float %17 3 + %21 = OpImageSampleDrefExplicitLod %float %14 %17 %20 Lod %19 + %22 = OpCompositeConstruct %v4float %21 %21 %21 %21 + OpStore %FragColor %22 + OpReturn + OpFunctionEnd diff --git a/shaders/frag/texture-shadow-lod-bias.frag b/shaders/frag/texture-shadow-lod-bias.frag new file mode 100644 index 000000000..1d10f5cac --- /dev/null +++ b/shaders/frag/texture-shadow-lod-bias.frag @@ -0,0 +1,16 @@ +#version 450 +#extension GL_EXT_texture_shadow_lod : require + +layout(binding = 0) uniform sampler2DArrayShadow uShadow2DArray; + +layout(location = 0) in vec4 vUV; +layout(location = 1) in float vBias; +layout(location = 0) out vec4 FragColor; + +void main() +{ + float r = 0.0; + r += texture(uShadow2DArray, vUV, vBias); + r += textureOffset(uShadow2DArray, vUV, ivec2(1, 1), vBias); + FragColor = vec4(r); +} diff --git a/shaders/frag/texture-shadow-lod.frag b/shaders/frag/texture-shadow-lod.frag new file mode 100644 index 000000000..3e538a5a8 --- /dev/null +++ b/shaders/frag/texture-shadow-lod.frag @@ -0,0 +1,18 @@ +#version 450 +#extension GL_EXT_texture_shadow_lod : require + +layout(binding = 0) uniform sampler2DArrayShadow uShadow2DArray; +layout(binding = 1) uniform samplerCubeShadow uShadowCube; + +layout(location = 0) in vec4 vUV; +layout(location = 1) in float vLod; +layout(location = 0) out vec4 FragColor; + +void main() +{ + float r = 0.0; + r += textureLod(uShadow2DArray, vUV, vLod); + r += textureLod(uShadowCube, vUV, vLod); + r += textureLodOffset(uShadow2DArray, vUV, vLod, ivec2(1, 1)); + FragColor = vec4(r); +} diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index a20f4498d..3cd8766b6 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -8236,6 +8236,17 @@ std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool base_args.is_proj = proj != 0; string expr; + + // texture() with bias on sampler2DArrayShadow or samplerCubeArrayShadow requires GL_EXT_texture_shadow_lod. + // textureOffset() with bias on sampler2DArrayShadow also requires it. + if (bias != 0 && dref != 0 && !fetch && !gather && + ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || + (imgtype.image.arrayed && imgtype.image.dim == DimCube)) && + is_depth_image(imgtype, img)) + { + require_extension_internal("GL_EXT_texture_shadow_lod"); + } + TextureFunctionNameArguments name_args = {}; name_args.base = base_args; @@ -8372,10 +8383,12 @@ string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args) { if (!expression_is_constant_null(args.lod)) { - SPIRV_CROSS_THROW("textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be " - "expressed in GLSL."); + require_extension_internal("GL_EXT_texture_shadow_lod"); + } + else + { + workaround_lod_array_shadow_as_grad = true; } - workaround_lod_array_shadow_as_grad = true; } if (args.is_sparse_feedback) @@ -8510,9 +8523,11 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool // To emulate this, we will have to use textureGrad with a constant gradient of 0. // The workaround will assert that the LOD is in fact constant 0, or we cannot emit correct code. // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. + // If GL_EXT_texture_shadow_lod is in use, textureLod is available directly with arbitrary LOD. bool workaround_lod_array_shadow_as_grad = ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - is_depth_image(imgtype, img) && args.lod != 0 && !args.base.is_fetch; + is_depth_image(imgtype, img) && args.lod != 0 && !args.base.is_fetch && + !has_extension("GL_EXT_texture_shadow_lod"); if (args.dref) {