diff --git a/Makefile.am b/Makefile.am index 06fd43ab..e1f8cfc2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -163,6 +163,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 00000000..6fe76487 --- /dev/null +++ b/tests/hlsl/sample-cmp.shader_test @@ -0,0 +1,144 @@ +[require] +shader model >= 4.0 + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison never + +[srv 0] +format r32 float shadow +size (2d, 2, 2) +0.5 0.5 +0.5 0.5 + +[pixel shader] +Texture2D t : register(t0); +SamplerComparisonState s : register(s0); + +float4 main() : sv_target +{ + float ref = 0.5, delta = 0.00000007; + return float4( + t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref - delta), + t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref), + t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref + delta), + 1.0); +} + +[test] +draw quad +probe all rgba (0.0, 0.0, 0.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison less + +[test] +draw quad +probe all rgba (1.0, 0.0, 0.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison equal + +[test] +draw quad +probe all rgba (0.0, 1.0, 0.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison less equal + +[test] +draw quad +probe all rgba (1.0, 1.0, 0.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison greater + +[test] +draw quad +probe all rgba (0.0, 0.0, 1.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison not equal + +[test] +draw quad +probe all rgba (1.0, 0.0, 1.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison greater equal + +[test] +draw quad +probe all rgba (0.0, 1.0, 1.0, 1.0) + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison always + +[test] +draw quad +probe all rgba (1.0, 1.0, 1.0, 1.0) + + +[sampler 0] +filter linear linear linear +address clamp clamp clamp +comparison greater + +% Non-constant ref +[pixel shader] +Texture2D t : register(t0); +SamplerComparisonState s : register(s0); + +float ref, delta; + +float4 main() : sv_target +{ + return float4( + t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref - delta), + t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref), + t.SampleCmpLevelZero(s, float2(0.5, 0.5), ref + delta), + 1.0); +} + +[test] +uniform 0 float 0.5 +uniform 1 float 0.00000007 +draw quad +probe all rgba (0.0, 0.0, 1.0, 1.0) + + +[pixel shader] +Texture2D t : register(t0); +SamplerComparisonState s : register(s0); + +float ref; + +float4 main() : sv_target +{ + float delta = 0.00000007; + return float4( + t.SampleCmp(s, float2(0.5, 0.5), ref - delta), + t.SampleCmp(s, float2(0.5, 0.5), 0.5), + t.SampleCmp(s, float2(0.5, 0.5), ref + delta), + 1.0); +} + +[test] +uniform 0 float 0.5 +draw quad +probe all rgba (0.0, 0.0, 1.0, 1.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 0d6bb8ec..ccdda5b7 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -324,7 +324,8 @@ static void parse_require_directive(struct shader_runner *runner, const char *li } } -static DXGI_FORMAT parse_format(const char *line, enum texture_data_type *data_type, unsigned int *texel_size, const char **rest) +static DXGI_FORMAT parse_format(const char *line, enum texture_data_type *data_type, unsigned int *texel_size, + bool *is_shadow, const char **rest) { static const struct { @@ -332,6 +333,7 @@ static DXGI_FORMAT parse_format(const char *line, enum texture_data_type *data_t enum texture_data_type data_type; unsigned int texel_size; DXGI_FORMAT format; + bool is_shadow; } formats[] = { @@ -341,6 +343,7 @@ static DXGI_FORMAT parse_format(const char *line, enum texture_data_type *data_t {"r32g32 float", TEXTURE_DATA_FLOAT, 8, DXGI_FORMAT_R32G32_FLOAT}, {"r32g32 int", TEXTURE_DATA_SINT, 8, DXGI_FORMAT_R32G32_SINT}, {"r32g32 uint", TEXTURE_DATA_UINT, 8, DXGI_FORMAT_R32G32_UINT}, + {"r32 float shadow", TEXTURE_DATA_FLOAT, 4, DXGI_FORMAT_R32_FLOAT, true}, {"r32 float", TEXTURE_DATA_FLOAT, 4, DXGI_FORMAT_R32_FLOAT}, {"r32 sint", TEXTURE_DATA_SINT, 4, DXGI_FORMAT_R32_SINT}, {"r32 uint", TEXTURE_DATA_UINT, 4, DXGI_FORMAT_R32_UINT}, @@ -354,6 +357,8 @@ static DXGI_FORMAT parse_format(const char *line, enum texture_data_type *data_t if (data_type) *data_type = formats[i].data_type; *texel_size = formats[i].texel_size; + if (is_shadow) + *is_shadow = formats[i].is_shadow; return formats[i].format; } } @@ -410,12 +415,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[] = + { + {"less equal", D3D12_COMPARISON_FUNC_LESS_EQUAL}, + {"not equal", D3D12_COMPARISON_FUNC_NOT_EQUAL}, + {"greater equal", D3D12_COMPARISON_FUNC_GREATER_EQUAL}, + {"never", D3D12_COMPARISON_FUNC_NEVER}, + {"less", D3D12_COMPARISON_FUNC_LESS}, + {"equal", D3D12_COMPARISON_FUNC_EQUAL}, + {"greater", D3D12_COMPARISON_FUNC_GREATER}, + {"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); @@ -426,7 +465,7 @@ static void parse_resource_directive(struct resource_params *resource, const cha { if (match_string(line, "format", &line)) { - resource->format = parse_format(line, &resource->data_type, &resource->texel_size, &line); + resource->format = parse_format(line, &resource->data_type, &resource->texel_size, &resource->is_shadow, &line); } else if (match_string(line, "stride", &line)) { @@ -513,7 +552,7 @@ static void parse_input_layout_directive(struct shader_runner *runner, const cha fatal_error("Malformed input layout directive '%s'.\n", line); line = rest; - element->format = parse_format(line, NULL, &element->texel_size, &line); + element->format = parse_format(line, NULL, &element->texel_size, NULL, &line); if (!(rest = strpbrk(line, " \n"))) rest = line + strlen(line); diff --git a/tests/shader_runner.h b/tests/shader_runner.h index ec6c340c..5666b2d5 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -63,6 +63,7 @@ struct sampler D3D12_FILTER filter; D3D12_TEXTURE_ADDRESS_MODE u_address, v_address, w_address; + D3D12_COMPARISON_FUNC func; }; enum resource_type @@ -86,6 +87,7 @@ struct resource_params enum resource_dimension dimension; DXGI_FORMAT format; + bool is_shadow; enum texture_data_type data_type; unsigned int texel_size; unsigned int stride; diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 528c04e9..d9310497 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -509,7 +509,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 ca137512..ce27ad22 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; diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index 7f208953..de7e49b0 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -36,6 +36,7 @@ struct format_info enum DXGI_FORMAT f; unsigned int component_count; bool is_integer; + bool is_shadow; GLenum internal_format; GLenum format; GLenum type; @@ -283,27 +284,28 @@ static void gl_runner_cleanup(struct gl_runner *runner) ok(ret, "Failed to terminate EGL display connection.\n"); } -static const struct format_info *get_format_info(enum DXGI_FORMAT format) +static const struct format_info *get_format_info(enum DXGI_FORMAT format, bool is_shadow) { size_t i; static const struct format_info format_info[] = { - {DXGI_FORMAT_UNKNOWN, 1, true, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, - {DXGI_FORMAT_R32G32B32A32_FLOAT, 4, false, GL_RGBA32F, GL_RGBA, GL_FLOAT}, - {DXGI_FORMAT_R32G32B32A32_UINT, 4, true, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, - {DXGI_FORMAT_R32G32B32A32_SINT, 4, true, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, - {DXGI_FORMAT_R32G32_FLOAT, 2, false, GL_RG32F, GL_RG, GL_FLOAT}, - {DXGI_FORMAT_R32G32_UINT, 2, true, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, - {DXGI_FORMAT_R32G32_SINT, 2, true, GL_RG32I, GL_RG_INTEGER, GL_INT}, - {DXGI_FORMAT_R32_FLOAT, 1, false, GL_R32F, GL_RED, GL_FLOAT}, - {DXGI_FORMAT_R32_UINT, 1, true, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, - {DXGI_FORMAT_R32_SINT, 1, true, GL_R32I, GL_RED_INTEGER, GL_INT}, + {DXGI_FORMAT_UNKNOWN, 1, true, false, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, + {DXGI_FORMAT_R32G32B32A32_FLOAT, 4, false, false, GL_RGBA32F, GL_RGBA, GL_FLOAT}, + {DXGI_FORMAT_R32G32B32A32_UINT, 4, true, false, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, + {DXGI_FORMAT_R32G32B32A32_SINT, 4, true, false, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, + {DXGI_FORMAT_R32G32_FLOAT, 2, false, false, GL_RG32F, GL_RG, GL_FLOAT}, + {DXGI_FORMAT_R32G32_UINT, 2, true, false, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, + {DXGI_FORMAT_R32G32_SINT, 2, true, false, GL_RG32I, GL_RG_INTEGER, GL_INT}, + {DXGI_FORMAT_R32_FLOAT, 1, false, false, GL_R32F, GL_RED, GL_FLOAT}, + {DXGI_FORMAT_R32_FLOAT, 1, false, true, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, + {DXGI_FORMAT_R32_UINT, 1, true, false, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, + {DXGI_FORMAT_R32_SINT, 1, true, false, GL_R32I, GL_RED_INTEGER, GL_INT}, }; for (i = 0; i < ARRAY_SIZE(format_info); ++i) { - if (format_info[i].f == format) + if (format_info[i].f == format && format_info[i].is_shadow == is_shadow) return &format_info[i]; } @@ -314,7 +316,7 @@ static void init_resource_2d(struct gl_resource *resource, const struct resource { unsigned int offset, w, h, i; - resource->format = get_format_info(params->format); + resource->format = get_format_info(params->format, params->is_shadow); glGenTextures(1, &resource->id); glBindTexture(GL_TEXTURE_2D, resource->id); glTexStorage2D(GL_TEXTURE_2D, params->level_count, @@ -336,7 +338,7 @@ static void init_resource_2d(struct gl_resource *resource, const struct resource static void init_resource_buffer(struct gl_resource *resource, const struct resource_params *params) { - resource->format = get_format_info(params->format); + resource->format = get_format_info(params->format, false); glGenBuffers(1, &resource->id); glBindBuffer(GL_TEXTURE_BUFFER, resource->id); @@ -721,6 +723,31 @@ static GLenum get_texture_filter_min_gl(D3D12_FILTER filter) return filter & 0x10 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; } +static GLenum get_compare_op_gl(D3D12_COMPARISON_FUNC op) +{ + switch (op) + { + case D3D12_COMPARISON_FUNC_NEVER: + return GL_NEVER; + case D3D12_COMPARISON_FUNC_LESS: + return GL_LESS; + case D3D12_COMPARISON_FUNC_EQUAL: + return GL_EQUAL; + case D3D12_COMPARISON_FUNC_LESS_EQUAL: + return GL_LEQUAL; + case D3D12_COMPARISON_FUNC_GREATER: + return GL_GREATER; + case D3D12_COMPARISON_FUNC_NOT_EQUAL: + return GL_NOTEQUAL; + case D3D12_COMPARISON_FUNC_GREATER_EQUAL: + return GL_GEQUAL; + case D3D12_COMPARISON_FUNC_ALWAYS: + return GL_ALWAYS; + default: + fatal_error("Unhandled compare op %#x.\n", op); + } +} + static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Blob **vs_blob) { struct vkd3d_shader_code vs_code, fs_code; @@ -837,6 +864,11 @@ static bool gl_runner_draw(struct shader_runner *r, glSamplerParameteri(id, GL_TEXTURE_WRAP_R, get_texture_wrap_gl(sampler->w_address)); glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, get_texture_filter_mag_gl(sampler->filter)); glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, get_texture_filter_min_gl(sampler->filter)); + if (sampler->func) + { + glSamplerParameteri(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameteri(id, GL_TEXTURE_COMPARE_FUNC, get_compare_op_gl(sampler->func)); + } sampler_info[i].id = id; } @@ -938,7 +970,7 @@ static bool gl_runner_draw(struct shader_runner *r, signature_element = vkd3d_shader_find_signature_element(&vs_input_signature, element->name, element->index, 0); attribute_idx = signature_element->register_index; - format = get_format_info(element->format); + format = get_format_info(element->format, false); glBindBuffer(GL_ARRAY_BUFFER, vbo_info[element->slot].id); if (format->is_integer) diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index d2cfd7ee..a3bbf170 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -841,6 +841,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}; @@ -905,6 +930,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));