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:
Henri Verbeet
2025-11-21 17:32:23 +01:00
parent 1007ba40b5
commit dc7cdec9a5
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
8 changed files with 156 additions and 14 deletions

View File

@@ -243,6 +243,7 @@ vkd3d_shader_tests = \
tests/hlsl/sample-cmp.shader_test \ tests/hlsl/sample-cmp.shader_test \
tests/hlsl/sample-grad.shader_test \ tests/hlsl/sample-grad.shader_test \
tests/hlsl/sample-level.shader_test \ tests/hlsl/sample-level.shader_test \
tests/hlsl/sample-minmax.shader_test \
tests/hlsl/sampler-offset.shader_test \ tests/hlsl/sampler-offset.shader_test \
tests/hlsl/sampler-state.shader_test \ tests/hlsl/sampler-state.shader_test \
tests/hlsl/sampler.shader_test \ tests/hlsl/sampler.shader_test \

View 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)

View File

@@ -480,6 +480,7 @@ static const char *const shader_cap_strings[] =
[SHADER_CAP_CULL_DISTANCE] = "cull-distance", [SHADER_CAP_CULL_DISTANCE] = "cull-distance",
[SHADER_CAP_DEPTH_BOUNDS] = "depth-bounds", [SHADER_CAP_DEPTH_BOUNDS] = "depth-bounds",
[SHADER_CAP_DESCRIPTORS] = "descriptors", [SHADER_CAP_DESCRIPTORS] = "descriptors",
[SHADER_CAP_FILTER_MINMAX] = "filter-minmax",
[SHADER_CAP_FLOAT64] = "float64", [SHADER_CAP_FLOAT64] = "float64",
[SHADER_CAP_FOG] = "fog", [SHADER_CAP_FOG] = "fog",
[SHADER_CAP_GEOMETRY_SHADER] = "geometry-shader", [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)) else if (match_string(line, "filter", &line))
{ {
D3D12_FILTER_REDUCTION_TYPE reduction = D3D12_FILTER_REDUCTION_TYPE_STANDARD;
unsigned int i;
static const struct static const struct
{ {
const char *string; 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 point", D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT},
{"linear linear linear", D3D12_FILTER_MIN_MAG_MIP_LINEAR}, {"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) for (i = 0; i < ARRAY_SIZE(filters); ++i)
{ {
if (match_string(line, filters[i].string, &line)) if (match_string(line, filters[i].string, &line))
{ {
sampler->filter = filters[i].filter; sampler->filter = (reduction << D3D12_FILTER_REDUCTION_TYPE_SHIFT) | filters[i].filter;
if (sampler->func)
sampler->filter |= D3D12_FILTER_REDUCTION_TYPE_COMPARISON << D3D12_FILTER_REDUCTION_TYPE_SHIFT;
return; return;
} }
} }
@@ -680,6 +688,7 @@ static void parse_sampler_directive(struct sampler *sampler, const char *line)
} }
else if (match_string(line, "comparison", &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->filter |= D3D12_FILTER_REDUCTION_TYPE_COMPARISON << D3D12_FILTER_REDUCTION_TYPE_SHIFT;
sampler->func = parse_comparison_func(line, &line); sampler->func = parse_comparison_func(line, &line);
return; return;

View File

@@ -158,6 +158,7 @@ enum shader_cap
SHADER_CAP_CULL_DISTANCE, SHADER_CAP_CULL_DISTANCE,
SHADER_CAP_DEPTH_BOUNDS, SHADER_CAP_DEPTH_BOUNDS,
SHADER_CAP_DESCRIPTORS, SHADER_CAP_DESCRIPTORS,
SHADER_CAP_FILTER_MINMAX,
SHADER_CAP_FLOAT64, SHADER_CAP_FLOAT64,
SHADER_CAP_FOG, SHADER_CAP_FOG,
SHADER_CAP_GEOMETRY_SHADER, SHADER_CAP_GEOMETRY_SHADER,

View File

@@ -293,6 +293,7 @@ static bool is_nvidia_windows_device(ID3D11Device *device)
static BOOL init_test_context(struct d3d11_shader_runner *runner) 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_OPTIONS2 options2 = {0};
D3D11_FEATURE_DATA_D3D11_OPTIONS3 options3 = {0}; D3D11_FEATURE_DATA_D3D11_OPTIONS3 options3 = {0};
D3D11_FEATURE_DATA_DOUBLES doubles = {0}; D3D11_FEATURE_DATA_DOUBLES doubles = {0};
@@ -331,26 +332,27 @@ static BOOL init_test_context(struct d3d11_shader_runner *runner)
return FALSE; 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, hr = ID3D11Device_CheckFeatureSupport(runner->device, D3D11_FEATURE_DOUBLES,
&doubles, sizeof(doubles)); &doubles, sizeof(doubles));
ok(hr == S_OK, "Failed to check double precision feature support, hr %#lx.\n", hr); ok(hr == S_OK, "Failed to check double precision feature support, hr %#lx.\n", hr);
runner->caps.shader_caps[SHADER_CAP_FLOAT64] = doubles.DoublePrecisionFloatShaderOps; hr = ID3D11Device_CheckFeatureSupport(runner->device,
runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true; 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, hr = ID3D11Device_CheckFeatureSupport(runner->device,
D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2)); D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2));
ok(hr == S_OK, "Failed to check feature options2 support, hr %#lx.\n", hr); ok(hr == S_OK, "Failed to check feature options2 support, hr %#lx.\n", hr);
hr = ID3D11Device_CheckFeatureSupport(runner->device, hr = ID3D11Device_CheckFeatureSupport(runner->device,
D3D11_FEATURE_D3D11_OPTIONS3, &options3, sizeof(options3)); D3D11_FEATURE_D3D11_OPTIONS3, &options3, sizeof(options3));
ok(hr == S_OK, "Failed to check feature options3 support, hr %#lx.\n", hr); 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_ROV] = options2.ROVsSupported;
runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer; runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer;
runner->caps.shader_caps[SHADER_CAP_TESSELLATION_SHADER] = true; runner->caps.shader_caps[SHADER_CAP_TESSELLATION_SHADER] = true;

View File

@@ -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_CULL_DISTANCE] = true;
runner->caps.shader_caps[SHADER_CAP_DEPTH_BOUNDS] = options2.DepthBoundsTestSupported; runner->caps.shader_caps[SHADER_CAP_DEPTH_BOUNDS] = options2.DepthBoundsTestSupported;
runner->caps.shader_caps[SHADER_CAP_DESCRIPTORS] = true; 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; runner->caps.shader_caps[SHADER_CAP_FLOAT64] = options.DoublePrecisionFloatShaderOps;
if (is_geometry_shader_supported(device)) if (is_geometry_shader_supported(device))
runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true; runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true;

View File

@@ -166,6 +166,8 @@ static bool check_gl_extensions(struct gl_runner *runner)
runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = true; runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = true;
if (check_gl_extension("GL_ARB_tessellation_shader", count)) if (check_gl_extension("GL_ARB_tessellation_shader", count))
runner->caps.shader_caps[SHADER_CAP_TESSELLATION_SHADER] = true; 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; 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) 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; 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_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_MAG_FILTER, get_texture_filter_mag_gl(sampler->filter));
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, get_texture_filter_min_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) if (sampler->func)
{ {
glSamplerParameteri(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glSamplerParameteri(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);

View File

@@ -76,6 +76,7 @@ struct physical_device_info
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_to_helper_invocation_features; VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_to_helper_invocation_features;
VkPhysicalDeviceProperties2 properties2; VkPhysicalDeviceProperties2 properties2;
VkPhysicalDeviceDriverPropertiesKHR driver_properties; VkPhysicalDeviceDriverPropertiesKHR driver_properties;
VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT filter_minmax_properties;
}; };
static struct vulkan_shader_runner *vulkan_shader_runner(struct shader_runner *r) 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) static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_runner *runner)
{ {
VkDescriptorSetLayoutCreateInfo set_desc = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; 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}; VkSamplerCreateInfo sampler_desc = {.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
struct vulkan_sampler *vulkan_sampler = &runner->samplers[i]; struct vulkan_sampler *vulkan_sampler = &runner->samplers[i];
const struct sampler *sampler = &runner->r.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.magFilter = (sampler->filter & 0x4) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
sampler_desc.minFilter = (sampler->filter & 0x10) ? 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[] = device_extensions[] =
{ {
{VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME}, {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_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME},
{VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME}, {VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME},
{VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, true}, {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; enabled_extensions->names[enabled_extensions->count++] = name;
if (!strcmp(name, VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME)) if (!strcmp(name, VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME))
runner->caps.shader_caps[SHADER_CAP_ROV] = true; 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)) if (!strcmp(name, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME))
runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = true; runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX] = true;
if (!strcmp(name, VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME)) 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; 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) if (context->vkGetPhysicalDeviceFeatures2KHR)
VK_CALL(vkGetPhysicalDeviceProperties2KHR(context->phys_device, &info->properties2)); VK_CALL(vkGetPhysicalDeviceProperties2KHR(context->phys_device, &info->properties2));
else else
VK_CALL(vkGetPhysicalDeviceProperties(context->phys_device, &info->properties2.properties)); 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) static uint32_t get_format_support(const struct vulkan_test_context *context, enum DXGI_FORMAT format)