tests/shader-runner: Add sampler comparison tests.

This commit is contained in:
Conor McCarthy 2024-02-23 12:30:16 +10:00 committed by Alexandre Julliard
parent 7273d7f54f
commit 7fcf1b6ca2
Notes: Alexandre Julliard 2024-03-11 23:05:27 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/673
8 changed files with 265 additions and 19 deletions

View File

@ -163,6 +163,7 @@ vkd3d_shader_tests = \
tests/hlsl/return.shader_test \ tests/hlsl/return.shader_test \
tests/hlsl/round.shader_test \ tests/hlsl/round.shader_test \
tests/hlsl/sample-bias.shader_test \ tests/hlsl/sample-bias.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/sampler-offset.shader_test \ tests/hlsl/sampler-offset.shader_test \

View File

@ -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<float> 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<float> 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<float> 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)

View File

@ -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 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; enum texture_data_type data_type;
unsigned int texel_size; unsigned int texel_size;
DXGI_FORMAT format; DXGI_FORMAT format;
bool is_shadow;
} }
formats[] = 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 float", TEXTURE_DATA_FLOAT, 8, DXGI_FORMAT_R32G32_FLOAT},
{"r32g32 int", TEXTURE_DATA_SINT, 8, DXGI_FORMAT_R32G32_SINT}, {"r32g32 int", TEXTURE_DATA_SINT, 8, DXGI_FORMAT_R32G32_SINT},
{"r32g32 uint", TEXTURE_DATA_UINT, 8, DXGI_FORMAT_R32G32_UINT}, {"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 float", TEXTURE_DATA_FLOAT, 4, DXGI_FORMAT_R32_FLOAT},
{"r32 sint", TEXTURE_DATA_SINT, 4, DXGI_FORMAT_R32_SINT}, {"r32 sint", TEXTURE_DATA_SINT, 4, DXGI_FORMAT_R32_SINT},
{"r32 uint", TEXTURE_DATA_UINT, 4, DXGI_FORMAT_R32_UINT}, {"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) if (data_type)
*data_type = formats[i].data_type; *data_type = formats[i].data_type;
*texel_size = formats[i].texel_size; *texel_size = formats[i].texel_size;
if (is_shadow)
*is_shadow = formats[i].is_shadow;
return formats[i].format; 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)) if (match_string(line, filters[i].string, &line))
{ {
sampler->filter = filters[i].filter; sampler->filter = filters[i].filter;
if (sampler->func)
sampler->filter |= D3D12_FILTER_REDUCTION_TYPE_COMPARISON << D3D12_FILTER_REDUCTION_TYPE_SHIFT;
return; return;
} }
} }
fatal_error("Unknown sampler filter '%s'.\n", line); 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 else
{ {
fatal_error("Unknown sampler directive '%s'.\n", line); 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)) 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)) 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); fatal_error("Malformed input layout directive '%s'.\n", line);
line = rest; 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"))) if (!(rest = strpbrk(line, " \n")))
rest = line + strlen(line); rest = line + strlen(line);

View File

@ -63,6 +63,7 @@ struct sampler
D3D12_FILTER filter; D3D12_FILTER filter;
D3D12_TEXTURE_ADDRESS_MODE u_address, v_address, w_address; D3D12_TEXTURE_ADDRESS_MODE u_address, v_address, w_address;
D3D12_COMPARISON_FUNC func;
}; };
enum resource_type enum resource_type
@ -86,6 +87,7 @@ struct resource_params
enum resource_dimension dimension; enum resource_dimension dimension;
DXGI_FORMAT format; DXGI_FORMAT format;
bool is_shadow;
enum texture_data_type data_type; enum texture_data_type data_type;
unsigned int texel_size; unsigned int texel_size;
unsigned int stride; unsigned int stride;

View File

@ -509,7 +509,7 @@ static ID3D11SamplerState *create_sampler(ID3D11Device *device, const struct sam
desc.AddressU = (D3D11_TEXTURE_ADDRESS_MODE)sampler->u_address; desc.AddressU = (D3D11_TEXTURE_ADDRESS_MODE)sampler->u_address;
desc.AddressV = (D3D11_TEXTURE_ADDRESS_MODE)sampler->v_address; desc.AddressV = (D3D11_TEXTURE_ADDRESS_MODE)sampler->v_address;
desc.AddressW = (D3D11_TEXTURE_ADDRESS_MODE)sampler->w_address; desc.AddressW = (D3D11_TEXTURE_ADDRESS_MODE)sampler->w_address;
desc.ComparisonFunc = D3D11_COMPARISON_NEVER; desc.ComparisonFunc = sampler->func;
desc.MaxLOD = D3D11_FLOAT32_MAX; desc.MaxLOD = D3D11_FLOAT32_MAX;
hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11_sampler); hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11_sampler);

View File

@ -325,6 +325,7 @@ static ID3D12RootSignature *d3d12_runner_create_root_signature(struct d3d12_shad
sampler_desc->AddressU = sampler->u_address; sampler_desc->AddressU = sampler->u_address;
sampler_desc->AddressV = sampler->v_address; sampler_desc->AddressV = sampler->v_address;
sampler_desc->AddressW = sampler->w_address; sampler_desc->AddressW = sampler->w_address;
sampler_desc->ComparisonFunc = sampler->func;
sampler_desc->MaxLOD = FLT_MAX; sampler_desc->MaxLOD = FLT_MAX;
sampler_desc->ShaderRegister = sampler->slot; sampler_desc->ShaderRegister = sampler->slot;
sampler_desc->RegisterSpace = 0; sampler_desc->RegisterSpace = 0;

View File

@ -36,6 +36,7 @@ struct format_info
enum DXGI_FORMAT f; enum DXGI_FORMAT f;
unsigned int component_count; unsigned int component_count;
bool is_integer; bool is_integer;
bool is_shadow;
GLenum internal_format; GLenum internal_format;
GLenum format; GLenum format;
GLenum type; GLenum type;
@ -283,27 +284,28 @@ static void gl_runner_cleanup(struct gl_runner *runner)
ok(ret, "Failed to terminate EGL display connection.\n"); 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; size_t i;
static const struct format_info format_info[] = static const struct format_info format_info[] =
{ {
{DXGI_FORMAT_UNKNOWN, 1, true, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, {DXGI_FORMAT_UNKNOWN, 1, true, false, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT},
{DXGI_FORMAT_R32G32B32A32_FLOAT, 4, false, GL_RGBA32F, GL_RGBA, GL_FLOAT}, {DXGI_FORMAT_R32G32B32A32_FLOAT, 4, false, false, GL_RGBA32F, GL_RGBA, GL_FLOAT},
{DXGI_FORMAT_R32G32B32A32_UINT, 4, true, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, {DXGI_FORMAT_R32G32B32A32_UINT, 4, true, false, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT},
{DXGI_FORMAT_R32G32B32A32_SINT, 4, true, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, {DXGI_FORMAT_R32G32B32A32_SINT, 4, true, false, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT},
{DXGI_FORMAT_R32G32_FLOAT, 2, false, GL_RG32F, GL_RG, GL_FLOAT}, {DXGI_FORMAT_R32G32_FLOAT, 2, false, false, GL_RG32F, GL_RG, GL_FLOAT},
{DXGI_FORMAT_R32G32_UINT, 2, true, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, {DXGI_FORMAT_R32G32_UINT, 2, true, false, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT},
{DXGI_FORMAT_R32G32_SINT, 2, true, GL_RG32I, GL_RG_INTEGER, GL_INT}, {DXGI_FORMAT_R32G32_SINT, 2, true, false, GL_RG32I, GL_RG_INTEGER, GL_INT},
{DXGI_FORMAT_R32_FLOAT, 1, false, GL_R32F, GL_RED, GL_FLOAT}, {DXGI_FORMAT_R32_FLOAT, 1, false, false, GL_R32F, GL_RED, GL_FLOAT},
{DXGI_FORMAT_R32_UINT, 1, true, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, {DXGI_FORMAT_R32_FLOAT, 1, false, true, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT},
{DXGI_FORMAT_R32_SINT, 1, true, GL_R32I, GL_RED_INTEGER, GL_INT}, {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) 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]; 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; 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); glGenTextures(1, &resource->id);
glBindTexture(GL_TEXTURE_2D, resource->id); glBindTexture(GL_TEXTURE_2D, resource->id);
glTexStorage2D(GL_TEXTURE_2D, params->level_count, 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) 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); glGenBuffers(1, &resource->id);
glBindBuffer(GL_TEXTURE_BUFFER, 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; 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) static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Blob **vs_blob)
{ {
struct vkd3d_shader_code vs_code, fs_code; 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_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 (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; 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, signature_element = vkd3d_shader_find_signature_element(&vs_input_signature,
element->name, element->index, 0); element->name, element->index, 0);
attribute_idx = signature_element->register_index; 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); glBindBuffer(GL_ARRAY_BUFFER, vbo_info[element->slot].id);
if (format->is_integer) if (format->is_integer)

View File

@ -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) 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};
@ -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.addressModeU = vk_address_mode_from_d3d12(sampler->u_address);
sampler_desc.addressModeV = vk_address_mode_from_d3d12(sampler->v_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.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; sampler_desc.maxLod = FLT_MAX;
VK_CALL(vkCreateSampler(runner->device, &sampler_desc, NULL, &vulkan_sampler->vk_sampler)); VK_CALL(vkCreateSampler(runner->device, &sampler_desc, NULL, &vulkan_sampler->vk_sampler));