mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-12-15 08:03:30 -08:00
tests/hlsl: Add a sampler min/max reduction filtering test.
The Metal runner could in principle support this feature using MTLSamplerDescriptor.reductionMode, but that requires macOS 26.0/Tahoe, which is newer than my current setup.
This commit is contained in:
Notes:
Henri Verbeet
2025-11-26 17:14:34 +01:00
Approved-by: Henri Verbeet (@hverbeet) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1846
@@ -243,6 +243,7 @@ vkd3d_shader_tests = \
|
||||
tests/hlsl/sample-cmp.shader_test \
|
||||
tests/hlsl/sample-grad.shader_test \
|
||||
tests/hlsl/sample-level.shader_test \
|
||||
tests/hlsl/sample-minmax.shader_test \
|
||||
tests/hlsl/sampler-offset.shader_test \
|
||||
tests/hlsl/sampler-state.shader_test \
|
||||
tests/hlsl/sampler.shader_test \
|
||||
|
||||
63
tests/hlsl/sample-minmax.shader_test
Normal file
63
tests/hlsl/sample-minmax.shader_test
Normal file
@@ -0,0 +1,63 @@
|
||||
[require]
|
||||
filter-minmax
|
||||
|
||||
[rtv 0]
|
||||
format r32g32b32a32-float
|
||||
size (2d, 64, 64)
|
||||
|
||||
[srv 0]
|
||||
size (2d, 4, 4)
|
||||
.00 .00 .00 1.0 .25 .00 .00 1.0 .50 .00 .00 1.0 .75 .00 .00 1.0
|
||||
.00 .25 .00 1.0 .25 .25 .00 1.0 .50 .25 .00 1.0 .75 .25 .00 1.0
|
||||
.00 .50 .00 1.0 .25 .50 .00 1.0 .50 .50 .00 1.0 .75 .50 .00 1.0
|
||||
.00 .75 .00 1.0 .25 .75 .00 1.0 .50 .75 .00 1.0 .75 .75 .00 1.0
|
||||
|
||||
[vertex shader]
|
||||
void main(float4 p : POSITION, out float2 t : TEXCOORD, out float4 position : SV_Position)
|
||||
{
|
||||
t.x = (p.x + 1.0) / 2.0;
|
||||
t.y = (-p.y + 1.0) / 2.0;
|
||||
position = p;
|
||||
}
|
||||
|
||||
[pixel shader]
|
||||
Texture2D t;
|
||||
sampler s;
|
||||
|
||||
float4 main(float2 p : TEXCOORD) : SV_Target
|
||||
{
|
||||
return t.Sample(s, floor(p * 8.0) / 8.0);
|
||||
}
|
||||
|
||||
[sampler 0]
|
||||
filter linear linear point
|
||||
|
||||
[test]
|
||||
draw quad
|
||||
probe (36, 20) f32(.375, .125, 0, 1)
|
||||
probe (20, 36) f32(.125, .375, 0, 1)
|
||||
probe (36, 36) f32(.375, .375, 0, 1)
|
||||
probe (52, 36) f32(.625, .375, 0, 1)
|
||||
probe (36, 52) f32(.375, .625, 0, 1)
|
||||
|
||||
[sampler 0]
|
||||
filter minimum linear linear point
|
||||
|
||||
[test]
|
||||
draw quad
|
||||
todo(d3d12) probe (36, 20) f32(.25, .00, 0, 1)
|
||||
todo(d3d12) probe (20, 36) f32(.00, .25, 0, 1)
|
||||
todo(d3d12) probe (36, 36) f32(.25, .25, 0, 1)
|
||||
todo(d3d12) probe (52, 36) f32(.50, .25, 0, 1)
|
||||
todo(d3d12) probe (36, 52) f32(.25, .50, 0, 1)
|
||||
|
||||
[sampler 0]
|
||||
filter maximum linear linear point
|
||||
|
||||
[test]
|
||||
draw quad
|
||||
todo(d3d12) probe (36, 20) f32(.50, .25, 0, 1)
|
||||
todo(d3d12) probe (20, 36) f32(.25, .50, 0, 1)
|
||||
todo(d3d12) probe (36, 36) f32(.50, .50, 0, 1)
|
||||
todo(d3d12) probe (52, 36) f32(.75, .50, 0, 1)
|
||||
todo(d3d12) probe (36, 52) f32(.50, .75, 0, 1)
|
||||
@@ -480,6 +480,7 @@ static const char *const shader_cap_strings[] =
|
||||
[SHADER_CAP_CULL_DISTANCE] = "cull-distance",
|
||||
[SHADER_CAP_DEPTH_BOUNDS] = "depth-bounds",
|
||||
[SHADER_CAP_DESCRIPTORS] = "descriptors",
|
||||
[SHADER_CAP_FILTER_MINMAX] = "filter-minmax",
|
||||
[SHADER_CAP_FLOAT64] = "float64",
|
||||
[SHADER_CAP_FOG] = "fog",
|
||||
[SHADER_CAP_GEOMETRY_SHADER] = "geometry-shader",
|
||||
@@ -647,6 +648,9 @@ static void parse_sampler_directive(struct sampler *sampler, const char *line)
|
||||
}
|
||||
else if (match_string(line, "filter", &line))
|
||||
{
|
||||
D3D12_FILTER_REDUCTION_TYPE reduction = D3D12_FILTER_REDUCTION_TYPE_STANDARD;
|
||||
unsigned int i;
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *string;
|
||||
@@ -663,15 +667,19 @@ static void parse_sampler_directive(struct sampler *sampler, const char *line)
|
||||
{"linear linear point", D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT},
|
||||
{"linear linear linear", D3D12_FILTER_MIN_MAG_MIP_LINEAR},
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
if (sampler->func)
|
||||
reduction = D3D12_FILTER_REDUCTION_TYPE_COMPARISON;
|
||||
else if (match_string(line, "minimum", &line))
|
||||
reduction = D3D12_FILTER_REDUCTION_TYPE_MINIMUM;
|
||||
else if (match_string(line, "maximum", &line))
|
||||
reduction = D3D12_FILTER_REDUCTION_TYPE_MAXIMUM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(filters); ++i)
|
||||
{
|
||||
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;
|
||||
sampler->filter = (reduction << D3D12_FILTER_REDUCTION_TYPE_SHIFT) | filters[i].filter;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -680,6 +688,7 @@ static void parse_sampler_directive(struct sampler *sampler, const char *line)
|
||||
}
|
||||
else if (match_string(line, "comparison", &line))
|
||||
{
|
||||
sampler->filter &= ~(D3D12_FILTER_REDUCTION_TYPE_MASK << D3D12_FILTER_REDUCTION_TYPE_SHIFT);
|
||||
sampler->filter |= D3D12_FILTER_REDUCTION_TYPE_COMPARISON << D3D12_FILTER_REDUCTION_TYPE_SHIFT;
|
||||
sampler->func = parse_comparison_func(line, &line);
|
||||
return;
|
||||
|
||||
@@ -158,6 +158,7 @@ enum shader_cap
|
||||
SHADER_CAP_CULL_DISTANCE,
|
||||
SHADER_CAP_DEPTH_BOUNDS,
|
||||
SHADER_CAP_DESCRIPTORS,
|
||||
SHADER_CAP_FILTER_MINMAX,
|
||||
SHADER_CAP_FLOAT64,
|
||||
SHADER_CAP_FOG,
|
||||
SHADER_CAP_GEOMETRY_SHADER,
|
||||
|
||||
@@ -293,6 +293,7 @@ static bool is_nvidia_windows_device(ID3D11Device *device)
|
||||
|
||||
static BOOL init_test_context(struct d3d11_shader_runner *runner)
|
||||
{
|
||||
D3D11_FEATURE_DATA_D3D11_OPTIONS1 options1 = {0};
|
||||
D3D11_FEATURE_DATA_D3D11_OPTIONS2 options2 = {0};
|
||||
D3D11_FEATURE_DATA_D3D11_OPTIONS3 options3 = {0};
|
||||
D3D11_FEATURE_DATA_DOUBLES doubles = {0};
|
||||
@@ -331,26 +332,27 @@ static BOOL init_test_context(struct d3d11_shader_runner *runner)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
runner->caps.runner = "d3d11.dll";
|
||||
runner->caps.compiler = HLSL_COMPILER;
|
||||
runner->caps.minimum_shader_model = SHADER_MODEL_4_0;
|
||||
runner->caps.maximum_shader_model = SHADER_MODEL_5_0;
|
||||
|
||||
runner->caps.shader_caps[SHADER_CAP_CULL_DISTANCE] = true;
|
||||
hr = ID3D11Device_CheckFeatureSupport(runner->device, D3D11_FEATURE_DOUBLES,
|
||||
&doubles, sizeof(doubles));
|
||||
ok(hr == S_OK, "Failed to check double precision feature support, hr %#lx.\n", hr);
|
||||
runner->caps.shader_caps[SHADER_CAP_FLOAT64] = doubles.DoublePrecisionFloatShaderOps;
|
||||
runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true;
|
||||
|
||||
hr = ID3D11Device_CheckFeatureSupport(runner->device,
|
||||
D3D11_FEATURE_D3D11_OPTIONS1, &options1, sizeof(options1));
|
||||
ok(hr == S_OK, "Failed to check feature options1 support, hr %#lx.\n", hr);
|
||||
hr = ID3D11Device_CheckFeatureSupport(runner->device,
|
||||
D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2));
|
||||
ok(hr == S_OK, "Failed to check feature options2 support, hr %#lx.\n", hr);
|
||||
|
||||
hr = ID3D11Device_CheckFeatureSupport(runner->device,
|
||||
D3D11_FEATURE_D3D11_OPTIONS3, &options3, sizeof(options3));
|
||||
ok(hr == S_OK, "Failed to check feature options3 support, hr %#lx.\n", hr);
|
||||
|
||||
runner->caps.runner = "d3d11.dll";
|
||||
runner->caps.compiler = HLSL_COMPILER;
|
||||
runner->caps.minimum_shader_model = SHADER_MODEL_4_0;
|
||||
runner->caps.maximum_shader_model = SHADER_MODEL_5_0;
|
||||
runner->caps.shader_caps[SHADER_CAP_CULL_DISTANCE] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX] = options1.MinMaxFiltering;
|
||||
runner->caps.shader_caps[SHADER_CAP_FLOAT64] = doubles.DoublePrecisionFloatShaderOps;
|
||||
runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_ROV] = options2.ROVsSupported;
|
||||
runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer;
|
||||
runner->caps.shader_caps[SHADER_CAP_TESSELLATION_SHADER] = true;
|
||||
|
||||
@@ -1132,6 +1132,7 @@ static void d3d12_runner_init_caps(struct d3d12_shader_runner *runner,
|
||||
runner->caps.shader_caps[SHADER_CAP_CULL_DISTANCE] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_DEPTH_BOUNDS] = options2.DepthBoundsTestSupported;
|
||||
runner->caps.shader_caps[SHADER_CAP_DESCRIPTORS] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_FLOAT64] = options.DoublePrecisionFloatShaderOps;
|
||||
if (is_geometry_shader_supported(device))
|
||||
runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true;
|
||||
|
||||
@@ -166,6 +166,8 @@ static bool check_gl_extensions(struct gl_runner *runner)
|
||||
runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = true;
|
||||
if (check_gl_extension("GL_ARB_tessellation_shader", count))
|
||||
runner->caps.shader_caps[SHADER_CAP_TESSELLATION_SHADER] = true;
|
||||
if (check_gl_extension("GL_ARB_texture_filter_minmax", count))
|
||||
runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1108,6 +1110,24 @@ static GLenum get_compare_op_gl(D3D12_COMPARISON_FUNC op)
|
||||
}
|
||||
}
|
||||
|
||||
static GLenum get_texture_reduction_mode_gl(D3D12_FILTER filter)
|
||||
{
|
||||
D3D12_FILTER_REDUCTION_TYPE r = D3D12_DECODE_FILTER_REDUCTION(filter);
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case D3D12_FILTER_REDUCTION_TYPE_STANDARD:
|
||||
case D3D12_FILTER_REDUCTION_TYPE_COMPARISON:
|
||||
return GL_WEIGHTED_AVERAGE_ARB;
|
||||
case D3D12_FILTER_REDUCTION_TYPE_MINIMUM:
|
||||
return GL_MIN;
|
||||
case D3D12_FILTER_REDUCTION_TYPE_MAXIMUM:
|
||||
return GL_MAX;
|
||||
default:
|
||||
fatal_error("Unhandled reduction type %#x.\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Blob **vs_blob)
|
||||
{
|
||||
ID3D10Blob *fs_blob, *hs_blob = NULL, *ds_blob = NULL, *gs_blob = NULL;
|
||||
@@ -1301,6 +1321,8 @@ 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 (runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX])
|
||||
glSamplerParameteri(id, GL_TEXTURE_REDUCTION_MODE_ARB, get_texture_reduction_mode_gl(sampler->filter));
|
||||
if (sampler->func)
|
||||
{
|
||||
glSamplerParameteri(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
|
||||
@@ -76,6 +76,7 @@ struct physical_device_info
|
||||
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_to_helper_invocation_features;
|
||||
VkPhysicalDeviceProperties2 properties2;
|
||||
VkPhysicalDeviceDriverPropertiesKHR driver_properties;
|
||||
VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT filter_minmax_properties;
|
||||
};
|
||||
|
||||
static struct vulkan_shader_runner *vulkan_shader_runner(struct shader_runner *r)
|
||||
@@ -1026,6 +1027,24 @@ static VkSamplerAddressMode vk_address_mode_from_d3d12(D3D12_TEXTURE_ADDRESS_MOD
|
||||
}
|
||||
}
|
||||
|
||||
static VkSamplerReductionModeEXT vk_reduction_mode_from_d3d12(D3D12_FILTER filter)
|
||||
{
|
||||
D3D12_FILTER_REDUCTION_TYPE r = D3D12_DECODE_FILTER_REDUCTION(filter);
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case D3D12_FILTER_REDUCTION_TYPE_STANDARD:
|
||||
case D3D12_FILTER_REDUCTION_TYPE_COMPARISON:
|
||||
return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
||||
case D3D12_FILTER_REDUCTION_TYPE_MINIMUM:
|
||||
return VK_SAMPLER_REDUCTION_MODE_MIN;
|
||||
case D3D12_FILTER_REDUCTION_TYPE_MAXIMUM:
|
||||
return VK_SAMPLER_REDUCTION_MODE_MAX;
|
||||
default:
|
||||
fatal_error("Unhandled reduction type %#x.\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_runner *runner)
|
||||
{
|
||||
VkDescriptorSetLayoutCreateInfo set_desc = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
|
||||
@@ -1073,6 +1092,15 @@ static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_r
|
||||
VkSamplerCreateInfo sampler_desc = {.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
struct vulkan_sampler *vulkan_sampler = &runner->samplers[i];
|
||||
const struct sampler *sampler = &runner->r.samplers[i];
|
||||
VkSamplerReductionModeCreateInfoEXT reduction_desc;
|
||||
|
||||
reduction_desc.reductionMode = vk_reduction_mode_from_d3d12(sampler->filter);
|
||||
if (reduction_desc.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE)
|
||||
{
|
||||
sampler_desc.pNext = &reduction_desc;
|
||||
reduction_desc.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT;
|
||||
reduction_desc.pNext = NULL;
|
||||
}
|
||||
|
||||
sampler_desc.magFilter = (sampler->filter & 0x4) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
sampler_desc.minFilter = (sampler->filter & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
@@ -1695,6 +1723,7 @@ static bool check_device_extensions(struct vulkan_shader_runner *runner,
|
||||
device_extensions[] =
|
||||
{
|
||||
{VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME},
|
||||
{VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME},
|
||||
{VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME},
|
||||
{VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME},
|
||||
{VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, true},
|
||||
@@ -1718,6 +1747,8 @@ static bool check_device_extensions(struct vulkan_shader_runner *runner,
|
||||
enabled_extensions->names[enabled_extensions->count++] = name;
|
||||
if (!strcmp(name, VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME))
|
||||
runner->caps.shader_caps[SHADER_CAP_ROV] = true;
|
||||
if (!strcmp(name, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME))
|
||||
runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX] = true;
|
||||
if (!strcmp(name, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME))
|
||||
runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = true;
|
||||
if (!strcmp(name, VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME))
|
||||
@@ -1776,10 +1807,22 @@ static void get_physical_device_info(struct vulkan_shader_runner *runner, struct
|
||||
info->driver_properties.pNext = list;
|
||||
}
|
||||
|
||||
if (runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX])
|
||||
{
|
||||
info->filter_minmax_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT;
|
||||
info->filter_minmax_properties.pNext = info->properties2.pNext;
|
||||
info->properties2.pNext = &info->filter_minmax_properties;
|
||||
}
|
||||
|
||||
if (context->vkGetPhysicalDeviceFeatures2KHR)
|
||||
VK_CALL(vkGetPhysicalDeviceProperties2KHR(context->phys_device, &info->properties2));
|
||||
else
|
||||
VK_CALL(vkGetPhysicalDeviceProperties(context->phys_device, &info->properties2.properties));
|
||||
|
||||
if (runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX]
|
||||
&& (!info->filter_minmax_properties.filterMinmaxSingleComponentFormats
|
||||
|| !info->filter_minmax_properties.filterMinmaxImageComponentMapping))
|
||||
runner->caps.shader_caps[SHADER_CAP_FILTER_MINMAX] = false;
|
||||
}
|
||||
|
||||
static uint32_t get_format_support(const struct vulkan_test_context *context, enum DXGI_FORMAT format)
|
||||
|
||||
Reference in New Issue
Block a user