Implement workaround for textureLod on 2D array shadow.

This does not exist in GLSL, but it exists in HLSL if LOD == 0.0.
This commit is contained in:
Hans-Kristian Arntzen 2017-06-23 09:44:41 +02:00
parent c6051bbbfa
commit ad2b7c05e7
6 changed files with 188 additions and 12 deletions

View File

@ -0,0 +1,27 @@
#version 450
uniform sampler2DArrayShadow SPIRV_Cross_CombinedShadowMapShadowSamplerPCF;
layout(location = 0) in vec2 texCoords;
layout(location = 1) in float cascadeIndex;
layout(location = 2) in float fragDepth;
layout(location = 0) out vec4 _entryPointOutput;
vec4 _main(vec2 texCoords_1, float cascadeIndex_1, float fragDepth_1)
{
vec4 _60 = vec4(vec3(texCoords_1, cascadeIndex_1), fragDepth_1);
float c = textureGrad(SPIRV_Cross_CombinedShadowMapShadowSamplerPCF, vec4(_60.xyz, _60.w), vec2(0.0), vec2(0.0));
return vec4(c, c, c, c);
}
void main()
{
vec2 texCoords_1 = texCoords;
float cascadeIndex_1 = cascadeIndex;
float fragDepth_1 = fragDepth;
vec2 param = texCoords_1;
float param_1 = cascadeIndex_1;
float param_2 = fragDepth_1;
_entryPointOutput = _main(param, param_1, param_2);
}

View File

@ -1,8 +1,8 @@
#version 450
in float v0;
in float v1;
out float FragColor;
layout(location = 0) in float v0;
layout(location = 1) in float v1;
layout(location = 0) out float FragColor;
void main()
{

View File

@ -0,0 +1,113 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 70
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %texCoords_1 %cascadeIndex_1 %fragDepth_1 %_entryPointOutput
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpName %main "main"
OpName %_main_vf2_f1_f1_ "@main(vf2;f1;f1;"
OpName %texCoords "texCoords"
OpName %cascadeIndex "cascadeIndex"
OpName %fragDepth "fragDepth"
OpName %c "c"
OpName %ShadowMap "ShadowMap"
OpName %ShadowSamplerPCF "ShadowSamplerPCF"
OpName %texCoords_0 "texCoords"
OpName %texCoords_1 "texCoords"
OpName %cascadeIndex_0 "cascadeIndex"
OpName %cascadeIndex_1 "cascadeIndex"
OpName %fragDepth_0 "fragDepth"
OpName %fragDepth_1 "fragDepth"
OpName %_entryPointOutput "@entryPointOutput"
OpName %param "param"
OpName %param_0 "param"
OpName %param_1 "param"
OpDecorate %ShadowMap DescriptorSet 0
OpDecorate %ShadowSamplerPCF DescriptorSet 0
OpDecorate %texCoords_1 Location 0
OpDecorate %cascadeIndex_1 Location 1
OpDecorate %fragDepth_1 Location 2
OpDecorate %_entryPointOutput Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%_ptr_Function_v2float = OpTypePointer Function %v2float
%_ptr_Function_float = OpTypePointer Function %float
%v4float = OpTypeVector %float 4
%11 = OpTypeFunction %v4float %_ptr_Function_v2float %_ptr_Function_float %_ptr_Function_float
%18 = OpTypeImage %float 2D 0 1 0 1 Unknown
%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
%ShadowMap = OpVariable %_ptr_UniformConstant_18 UniformConstant
%22 = OpTypeSampler
%_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22
%ShadowSamplerPCF = OpVariable %_ptr_UniformConstant_22 UniformConstant
%26 = OpTypeImage %float 2D 1 1 0 1 Unknown
%27 = OpTypeSampledImage %26
%v3float = OpTypeVector %float 3
%float_0 = OpConstant %float 0
%_ptr_Input_v2float = OpTypePointer Input %v2float
%texCoords_1 = OpVariable %_ptr_Input_v2float Input
%_ptr_Input_float = OpTypePointer Input %float
%cascadeIndex_1 = OpVariable %_ptr_Input_float Input
%fragDepth_1 = OpVariable %_ptr_Input_float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%texCoords_0 = OpVariable %_ptr_Function_v2float Function
%cascadeIndex_0 = OpVariable %_ptr_Function_float Function
%fragDepth_0 = OpVariable %_ptr_Function_float Function
%param = OpVariable %_ptr_Function_v2float Function
%param_0 = OpVariable %_ptr_Function_float Function
%param_1 = OpVariable %_ptr_Function_float Function
%53 = OpLoad %v2float %texCoords_1
OpStore %texCoords_0 %53
%57 = OpLoad %float %cascadeIndex_1
OpStore %cascadeIndex_0 %57
%60 = OpLoad %float %fragDepth_1
OpStore %fragDepth_0 %60
%64 = OpLoad %v2float %texCoords_0
OpStore %param %64
%66 = OpLoad %float %cascadeIndex_0
OpStore %param_0 %66
%68 = OpLoad %float %fragDepth_0
OpStore %param_1 %68
%69 = OpFunctionCall %v4float %_main_vf2_f1_f1_ %param %param_0 %param_1
OpStore %_entryPointOutput %69
OpReturn
OpFunctionEnd
%_main_vf2_f1_f1_ = OpFunction %v4float None %11
%texCoords = OpFunctionParameter %_ptr_Function_v2float
%cascadeIndex = OpFunctionParameter %_ptr_Function_float
%fragDepth = OpFunctionParameter %_ptr_Function_float
%16 = OpLabel
%c = OpVariable %_ptr_Function_float Function
%21 = OpLoad %18 %ShadowMap
%25 = OpLoad %22 %ShadowSamplerPCF
%28 = OpSampledImage %27 %21 %25
%29 = OpLoad %v2float %texCoords
%30 = OpLoad %float %cascadeIndex
%32 = OpCompositeExtract %float %29 0
%33 = OpCompositeExtract %float %29 1
%34 = OpCompositeConstruct %v3float %32 %33 %30
%35 = OpLoad %float %fragDepth
%36 = OpCompositeExtract %float %34 0
%37 = OpCompositeExtract %float %34 1
%38 = OpCompositeExtract %float %34 2
%39 = OpCompositeConstruct %v4float %36 %37 %38 %35
%41 = OpCompositeExtract %float %39 3
%42 = OpImageSampleDrefExplicitLod %float %28 %39 %41 Lod %float_0
OpStore %c %42
%43 = OpLoad %float %c
%44 = OpLoad %float %c
%45 = OpLoad %float %c
%46 = OpLoad %float %c
%47 = OpCompositeConstruct %v4float %43 %44 %45 %46
OpReturnValue %47
OpFunctionEnd

View File

@ -15,6 +15,9 @@
OpName %b "b"
OpName %v1 "v1"
OpName %FragColor "FragColor"
OpDecorate %v0 Location 0
OpDecorate %v1 Location 1
OpDecorate %FragColor Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%float = OpTypeFloat 32

View File

@ -2973,6 +2973,19 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is
{
string fname;
// textureLod on sampler2DArrayShadow does not exist in GLSL for some reason.
// 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.
bool workaround_lod_array_shadow_as_grad = false;
if (imgtype.image.arrayed && imgtype.image.dim == Dim2D && imgtype.image.depth && lod)
{
auto *constant_lod = maybe_get<SPIRConstant>(lod);
if (!constant_lod || constant_lod->scalar_f32() != 0.0f)
SPIRV_CROSS_THROW("textureLod on sampler2DArraySahdow is not constant 0.0. This cannot be expressed in GLSL.");
workaround_lod_array_shadow_as_grad = true;
}
if (is_fetch)
fname += "texelFetch";
else
@ -2985,9 +2998,9 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is
fname += "Offsets";
if (is_proj)
fname += "Proj";
if (has_grad)
if (has_grad || workaround_lod_array_shadow_as_grad)
fname += "Grad";
if (!!lod)
if (!!lod && !workaround_lod_array_shadow_as_grad)
fname += "Lod";
}
@ -2998,7 +3011,7 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is
}
// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &, bool, bool, bool, uint32_t coord,
string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool, bool, bool, uint32_t coord,
uint32_t coord_components, uint32_t dref, uint32_t grad_x, uint32_t grad_y,
uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp,
uint32_t sample, bool *p_forward)
@ -3030,7 +3043,18 @@ string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &, bool, bool
// Only enclose the UV expression if needed.
auto coord_expr = (*swizzle_expr == '\0') ? to_expression(coord) : (to_enclosed_expression(coord) + swizzle_expr);
// TODO: implement rest ... A bit intensive.
// textureLod on sampler2DArrayShadow does not exist in GLSL for some reason.
// 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.
bool workaround_lod_array_shadow_as_grad = false;
if (imgtype.image.arrayed && imgtype.image.dim == Dim2D && imgtype.image.depth && lod)
{
auto *constant_lod = maybe_get<SPIRConstant>(lod);
if (!constant_lod || constant_lod->scalar_f32() != 0.0f)
SPIRV_CROSS_THROW("textureLod on sampler2DArraySahdow is not constant 0.0. This cannot be expressed in GLSL.");
workaround_lod_array_shadow_as_grad = true;
}
if (dref)
{
@ -3075,6 +3099,14 @@ string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &, bool, bool
}
if (lod)
{
if (workaround_lod_array_shadow_as_grad)
{
// Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
// Implementing this as plain texture() is not safe on some implementations.
farg_str += ", vec2(0.0), vec2(0.0)";
}
else
{
if (check_explicit_lod_allowed(lod))
{
@ -3083,6 +3115,7 @@ string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &, bool, bool
farg_str += to_expression(lod);
}
}
}
if (coffset)
{

View File

@ -161,7 +161,7 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
if vulkan or spirv:
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path] + extra_args)
validate_shader(vulkan_glsl_path, vulkan)
validate_shader(vulkan_glsl_path, True)
return (spirv_path, glsl_path, vulkan_glsl_path if vulkan else None)