-- v5: tests/shader-runner: Add sampler comparison tests.
From: Conor McCarthy cmccarthy@codeweavers.com
--- Makefile.am | 1 + tests/hlsl/sample-cmp.shader_test | 160 ++++++++++++++++++++++++++++++ tests/shader_runner.c | 36 +++++++ tests/shader_runner.h | 2 + tests/shader_runner_d3d11.c | 3 +- tests/shader_runner_d3d12.c | 2 + tests/shader_runner_gl.c | 3 + tests/shader_runner_vulkan.c | 28 ++++++ 8 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 tests/hlsl/sample-cmp.shader_test
diff --git a/Makefile.am b/Makefile.am index 9e761ef32..27607d7ab 100644 --- a/Makefile.am +++ b/Makefile.am @@ -160,6 +160,7 @@ vkd3d_shader_tests = \ tests/hlsl/return.shader_test \ tests/hlsl/round.shader_test \ tests/hlsl/sample-bias.shader_test \ + tests/hlsl/sample-cmp.shader_test \ tests/hlsl/sample-grad.shader_test \ tests/hlsl/sample-level.shader_test \ tests/hlsl/sampler-offset.shader_test \ diff --git a/tests/hlsl/sample-cmp.shader_test b/tests/hlsl/sample-cmp.shader_test new file mode 100644 index 000000000..902e3b2c7 --- /dev/null +++ b/tests/hlsl/sample-cmp.shader_test @@ -0,0 +1,160 @@ +[require] +shader model >= 4.0 + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison never + +[srv 0] +format r32 float +size (2d, 2, 2) +0.5 0.5 +0.5 0.5 + +[pixel shader] +Texture2D<float> t : register(t0); +SamplerComparisonState s : register(s0); + +float ref; + +float4 main() : sv_target +{ + return t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref); +} + +[test] +uniform 0 float 1.0 +draw quad +probe all r (0.0) + +uniform 0 float 0.0 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison less + +[test] +uniform 0 float 0.0 +draw quad +probe all r (1.0) + +uniform 0 float 0.5 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison equal + +[test] +uniform 0 float 0.5 +draw quad +probe all r (1.0) + +uniform 0 float 0.5000001 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison less equal + +[test] +% fails on 0.5, at least on RADV +uniform 0 float 0.4999999 +draw quad +probe all r (1.0) + +uniform 0 float 0.5000001 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison greater + +[test] +uniform 0 float 1.0 +draw quad +probe all r (1.0) + +uniform 0 float 0.5 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison not equal + +[test] +uniform 0 float 0.5000001 +draw quad +probe all r (1.0) + +uniform 0 float 0.5 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison greater equal + +[test] +% fails on 0.5, at least on RADV +uniform 0 float 0.5000001 +draw quad +probe all r (1.0) + +uniform 0 float 0.4999999 +draw quad +probe all r (0.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison always + +[test] +uniform 0 float 0.0 +draw quad +probe all r (1.0) + +uniform 0 float 1.0 +draw quad +probe all r (1.0) + + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison greater + +[pixel shader] +Texture2D<float> t : register(t0); +SamplerComparisonState s : register(s0); + +float ref; + +float4 main() : sv_target +{ + return t.SampleCmp(s, float2(0.5, 0.5), ref); +} + +[test] +uniform 0 float 1.0 +draw quad +probe all r (1.0) + +uniform 0 float 0.0 +draw quad +probe all r (0.0) + diff --git a/tests/shader_runner.c b/tests/shader_runner.c index d0d806508..9df47b58a 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -410,12 +410,46 @@ static void parse_sampler_directive(struct sampler *sampler, const char *line) if (match_string(line, filters[i].string, &line)) { sampler->filter = filters[i].filter; + if (sampler->func) + sampler->filter |= D3D12_FILTER_REDUCTION_TYPE_COMPARISON << D3D12_FILTER_REDUCTION_TYPE_SHIFT; return; } }
fatal_error("Unknown sampler filter '%s'.\n", line); } + else if (match_string(line, "comparison", &line)) + { + static const struct + { + const char *string; + D3D12_COMPARISON_FUNC func; + } + funcs[] = + { + {"never", D3D12_COMPARISON_FUNC_NEVER}, + {"less", D3D12_COMPARISON_FUNC_LESS}, + {"equal", D3D12_COMPARISON_FUNC_EQUAL}, + {"less equal", D3D12_COMPARISON_FUNC_LESS_EQUAL}, + {"greater", D3D12_COMPARISON_FUNC_GREATER}, + {"not equal", D3D12_COMPARISON_FUNC_NOT_EQUAL}, + {"greater equal", D3D12_COMPARISON_FUNC_GREATER_EQUAL}, + {"always", D3D12_COMPARISON_FUNC_ALWAYS}, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(funcs); ++i) + { + if (match_string(line, funcs[i].string, &line)) + { + sampler->filter |= D3D12_FILTER_REDUCTION_TYPE_COMPARISON << D3D12_FILTER_REDUCTION_TYPE_SHIFT; + sampler->func = funcs[i].func; + return; + } + } + + fatal_error("Unknown sampler func '%s'.\n", line); + } else { fatal_error("Unknown sampler directive '%s'.\n", line); @@ -1716,6 +1750,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c
case STATE_SAMPLER: parse_sampler_directive(current_sampler, line); + if (current_sampler->func && !caps->sampler_comparison) + skip_tests = true; break;
case STATE_TEST: diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 62358d78c..ea642da01 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -62,6 +62,7 @@ struct sampler
D3D12_FILTER filter; D3D12_TEXTURE_ADDRESS_MODE u_address, v_address, w_address; + D3D12_COMPARISON_FUNC func; };
enum resource_type @@ -126,6 +127,7 @@ struct shader_runner_caps bool float64; bool int64; bool rov; + bool sampler_comparison; };
struct shader_runner diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 528c04e9d..6adf56ad7 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -272,6 +272,7 @@ static BOOL init_test_context(struct d3d11_shader_runner *runner) runner->caps.runner = "d3d11.dll"; runner->caps.minimum_shader_model = SHADER_MODEL_4_0; runner->caps.maximum_shader_model = SHADER_MODEL_5_1; + runner->caps.sampler_comparison = true;
hr = ID3D11Device_CheckFeatureSupport(runner->device, D3D11_FEATURE_DOUBLES, &doubles, sizeof(doubles)); @@ -509,7 +510,7 @@ static ID3D11SamplerState *create_sampler(ID3D11Device *device, const struct sam desc.AddressU = (D3D11_TEXTURE_ADDRESS_MODE)sampler->u_address; desc.AddressV = (D3D11_TEXTURE_ADDRESS_MODE)sampler->v_address; desc.AddressW = (D3D11_TEXTURE_ADDRESS_MODE)sampler->w_address; - desc.ComparisonFunc = D3D11_COMPARISON_NEVER; + desc.ComparisonFunc = sampler->func; desc.MaxLOD = D3D11_FLOAT32_MAX;
hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11_sampler); diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index ca1375124..898aa3668 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -325,6 +325,7 @@ static ID3D12RootSignature *d3d12_runner_create_root_signature(struct d3d12_shad sampler_desc->AddressU = sampler->u_address; sampler_desc->AddressV = sampler->v_address; sampler_desc->AddressW = sampler->w_address; + sampler_desc->ComparisonFunc = sampler->func; sampler_desc->MaxLOD = FLT_MAX; sampler_desc->ShaderRegister = sampler->slot; sampler_desc->RegisterSpace = 0; @@ -633,6 +634,7 @@ static void d3d12_runner_init_caps(struct d3d12_shader_runner *runner) runner->caps.float64 = options.DoublePrecisionFloatShaderOps; runner->caps.int64 = options1.Int64ShaderOps; runner->caps.rov = options.ROVsSupported; + runner->caps.sampler_comparison = true; }
void run_shader_tests_d3d12(void *dxc_compiler) diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index 6cec33a43..efece3f99 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -228,6 +228,9 @@ static bool gl_runner_init(struct gl_runner *runner) runner->caps.runner = "OpenGL"; runner->caps.minimum_shader_model = SHADER_MODEL_4_0; runner->caps.maximum_shader_model = SHADER_MODEL_5_1; + /* Some OpenGL driver versions require a depth format for sampler comparison, + * which causes more trouble than it's worth. */ + runner->caps.sampler_comparison = false;
trace("Using device %u.\n", i); runner->display = display; diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 35db729b5..3b0966a1d 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -810,6 +810,31 @@ static VkSamplerAddressMode vk_address_mode_from_d3d12(D3D12_TEXTURE_ADDRESS_MOD } }
+static enum VkCompareOp vk_compare_op_from_d3d12(D3D12_COMPARISON_FUNC op) +{ + switch (op) + { + case D3D12_COMPARISON_FUNC_NEVER: + return VK_COMPARE_OP_NEVER; + case D3D12_COMPARISON_FUNC_LESS: + return VK_COMPARE_OP_LESS; + case D3D12_COMPARISON_FUNC_EQUAL: + return VK_COMPARE_OP_EQUAL; + case D3D12_COMPARISON_FUNC_LESS_EQUAL: + return VK_COMPARE_OP_LESS_OR_EQUAL; + case D3D12_COMPARISON_FUNC_GREATER: + return VK_COMPARE_OP_GREATER; + case D3D12_COMPARISON_FUNC_NOT_EQUAL: + return VK_COMPARE_OP_NOT_EQUAL; + case D3D12_COMPARISON_FUNC_GREATER_EQUAL: + return VK_COMPARE_OP_GREATER_OR_EQUAL; + case D3D12_COMPARISON_FUNC_ALWAYS: + return VK_COMPARE_OP_ALWAYS; + default: + fatal_error("Unhandled compare op %#x.\n", op); + } +} + static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_runner *runner) { VkDescriptorSetLayoutCreateInfo set_desc = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; @@ -874,6 +899,8 @@ static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_r sampler_desc.addressModeU = vk_address_mode_from_d3d12(sampler->u_address); sampler_desc.addressModeV = vk_address_mode_from_d3d12(sampler->v_address); sampler_desc.addressModeW = vk_address_mode_from_d3d12(sampler->w_address); + sampler_desc.compareEnable = !!sampler->func; + sampler_desc.compareOp = sampler->func ? vk_compare_op_from_d3d12(sampler->func) : 0; sampler_desc.maxLod = FLT_MAX;
VK_CALL(vkCreateSampler(runner->device, &sampler_desc, NULL, &vulkan_sampler->vk_sampler)); @@ -1462,6 +1489,7 @@ void run_shader_tests_vulkan(void)
runner.caps.minimum_shader_model = SHADER_MODEL_4_0; runner.caps.maximum_shader_model = SHADER_MODEL_5_1; + runner.caps.sampler_comparison = true; run_shader_tests(&runner.r, &runner.caps, &vulkan_runner_ops, NULL);
cleanup_vulkan_runner(&runner);
+ /* Some OpenGL driver versions require a depth format for sampler comparison,
I think that's the correct/expected behaviour. I think there are two fairly straightforward ways to address that though: - Declare the format for the SRV as something like "format r32 float shadow" in the test, and then use either GL_DEPTH_COMPONENT32F or GL_R32F depending on the "shadow" flag. - Simply always use GL_DEPTH_COMPONENT32F for the "r32 float" format. Depth formats are valid texture formats in OpenGL. We wouldn't then be able to create e.g. a "r32 uint" view on that texture, but at least for the moment that's not a concern for the shader runner.