vkd3d-shader: Implement scanning combined resource/sampler information.

This commit is contained in:
Henri Verbeet 2023-10-15 01:26:32 +02:00 committed by Alexandre Julliard
parent d190fdf8c5
commit 9de793f180
Notes: Alexandre Julliard 2023-11-13 23:31:05 +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/466
4 changed files with 354 additions and 1 deletions

View File

@ -96,6 +96,11 @@ enum vkd3d_shader_structure_type
* \since 1.9
*/
VKD3D_SHADER_STRUCTURE_TYPE_VARYING_MAP_INFO,
/**
* The structure is a vkd3d_shader_scan_combined_resource_sampler_info structure.
* \since 1.10
*/
VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE),
};
@ -1478,6 +1483,49 @@ struct vkd3d_shader_scan_descriptor_info
unsigned int descriptor_count;
};
/**
* This structure describes a single resource-sampler pair. It is returned as
* part of struct vkd3d_shader_scan_combined_resource_sampler_info.
*
* \since 1.10
*/
struct vkd3d_shader_combined_resource_sampler_info
{
unsigned int resource_space;
unsigned int resource_index;
unsigned int sampler_space;
unsigned int sampler_index;
};
/**
* A chained structure describing the resource-sampler pairs used by a shader.
*
* This structure extends vkd3d_shader_compile_info.
*
* The information returned in this structure can be used to populate the
* \ref vkd3d_shader_interface_info.combined_samplers field. This is
* particularly useful when targeting environments without separate binding
* points for samplers and resources, like OpenGL.
*
* Members of this structure are allocated by vkd3d-shader and should be freed
* with vkd3d_shader_free_scan_combined_resource_sampler_info() when no longer
* needed.
*
* \since 1.10
*/
struct vkd3d_shader_scan_combined_resource_sampler_info
{
/** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO. */
enum vkd3d_shader_structure_type type;
/** Optional pointer to a structure containing further parameters. */
const void *next;
/** Pointer to an array of resource-sampler pairs. */
struct vkd3d_shader_combined_resource_sampler_info *combined_samplers;
/** The number of resource-sampler pairs in \ref combined_samplers. */
unsigned int combined_sampler_count;
};
/**
* Data type of a shader varying, returned as part of struct
* vkd3d_shader_signature_element.
@ -2379,6 +2427,21 @@ VKD3D_SHADER_API void vkd3d_shader_build_varying_map(const struct vkd3d_shader_s
const struct vkd3d_shader_signature *input_signature,
unsigned int *count, struct vkd3d_shader_varying_map *varyings);
/**
* Free members of struct vkd3d_shader_scan_combined_resource_sampler_info
* allocated by vkd3d_shader_scan().
*
* This function may free members of
* vkd3d_shader_scan_combined_resource_sampler_info, but does not free the
* structure itself.
*
* \param info Combined resource-sampler information to free.
*
* \since 1.10
*/
VKD3D_SHADER_API void vkd3d_shader_free_scan_combined_resource_sampler_info(
struct vkd3d_shader_scan_combined_resource_sampler_info *info);
#endif /* VKD3D_SHADER_NO_PROTOTYPES */
/** Type of vkd3d_shader_get_version(). */
@ -2451,6 +2514,10 @@ typedef void (*PFN_vkd3d_shader_build_varying_map)(const struct vkd3d_shader_sig
/** Type of vkd3d_shader_free_scan_signature_info(). \since 1.9 */
typedef void (*PFN_vkd3d_shader_free_scan_signature_info)(struct vkd3d_shader_scan_signature_info *info);
/** Type of vkd3d_shader_free_scan_combined_resource_sampler_info(). \since 1.10 */
typedef void (*PFN_vkd3d_shader_free_scan_combined_resource_sampler_info)(
struct vkd3d_shader_scan_combined_resource_sampler_info *info);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -8,6 +8,7 @@ global:
vkd3d_shader_free_dxbc;
vkd3d_shader_free_messages;
vkd3d_shader_free_root_signature;
vkd3d_shader_free_scan_combined_resource_sampler_info;
vkd3d_shader_free_scan_descriptor_info;
vkd3d_shader_free_scan_signature_info;
vkd3d_shader_free_shader_code;

View File

@ -617,6 +617,8 @@ static bool vkd3d_shader_signature_from_shader_signature(struct vkd3d_shader_sig
struct vkd3d_shader_scan_context
{
const struct vkd3d_shader_version *version;
struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info;
size_t descriptors_size;
@ -638,21 +640,28 @@ struct vkd3d_shader_scan_context
size_t cf_info_count;
enum vkd3d_shader_api_version api_version;
struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info;
size_t combined_samplers_size;
};
static void vkd3d_shader_scan_context_init(struct vkd3d_shader_scan_context *context,
const struct vkd3d_shader_version *version,
const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info,
struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info,
struct vkd3d_shader_message_context *message_context)
{
unsigned int i;
memset(context, 0, sizeof(*context));
context->version = version;
context->scan_descriptor_info = scan_descriptor_info;
context->message_context = message_context;
context->location.source_name = compile_info->source_name;
context->location.line = 2; /* Line 1 is the version token. */
context->api_version = VKD3D_SHADER_API_VERSION_1_2;
context->combined_sampler_info = combined_sampler_info;
for (i = 0; i < compile_info->option_count; ++i)
{
@ -861,6 +870,82 @@ static void vkd3d_shader_scan_combined_sampler_declaration(
&semantic->resource.range, semantic->resource_type, VKD3D_SHADER_RESOURCE_DATA_FLOAT);
}
static void vkd3d_shader_scan_combined_sampler_usage(struct vkd3d_shader_scan_context *context,
const struct vkd3d_shader_register *resource, const struct vkd3d_shader_register *sampler)
{
struct vkd3d_shader_scan_combined_resource_sampler_info *info;
struct vkd3d_shader_combined_resource_sampler_info *s;
unsigned resource_space = 0, sampler_space = 0;
unsigned int resource_idx, sampler_idx, i;
if (!(info = context->combined_sampler_info))
return;
if (resource->type == VKD3DSPR_RESOURCE)
resource_idx = resource->idx[1].offset;
else
resource_idx = resource->idx[0].offset;
if (!sampler)
sampler_idx = VKD3D_SHADER_DUMMY_SAMPLER_INDEX;
else if (sampler->type == VKD3DSPR_SAMPLER)
sampler_idx = sampler->idx[1].offset;
else
sampler_idx = sampler->idx[0].offset;
if (vkd3d_shader_ver_ge(context->version, 5, 1))
{
const struct vkd3d_shader_scan_descriptor_info1 *info = context->scan_descriptor_info;
const struct vkd3d_shader_descriptor_info1 *d;
for (i = 0; i < info->descriptor_count; ++i)
{
d = &info->descriptors[i];
if (d->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SRV)
continue;
if (d->register_id != resource->idx[0].offset)
continue;
resource_space = d->register_space;
break;
}
if (sampler)
{
for (i = 0; i < info->descriptor_count; ++i)
{
d = &info->descriptors[i];
if (d->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
continue;
if (d->register_id != sampler->idx[0].offset)
continue;
sampler_space = d->register_space;
break;
}
}
}
for (i = 0; i < info->combined_sampler_count; ++i)
{
s = &info->combined_samplers[i];
if (s->resource_space == resource_space && s->resource_index == resource_idx
&& s->sampler_space == sampler_space && s->sampler_index == sampler_idx)
return;
}
if (!vkd3d_array_reserve((void **)&info->combined_samplers, &context->combined_samplers_size,
info->combined_sampler_count + 1, sizeof(*info->combined_samplers)))
{
ERR("Failed to allocate combined sampler info.\n");
return;
}
s = &info->combined_samplers[info->combined_sampler_count++];
s->resource_space = resource_space;
s->resource_index = resource_idx;
s->sampler_space = sampler_space;
s->sampler_index = sampler_idx;
}
static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_context *context,
const struct vkd3d_shader_resource *resource, enum vkd3d_shader_resource_type resource_type,
enum vkd3d_shader_resource_data_type resource_data_type,
@ -954,6 +1039,7 @@ static void vkd3d_shader_scan_error(struct vkd3d_shader_scan_context *context,
static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *context,
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_register *sampler_reg;
struct vkd3d_shader_cf_info *cf_info;
unsigned int i;
@ -1102,6 +1188,58 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte
if (context->cf_info_count)
context->cf_info[context->cf_info_count - 1].inside_block = false;
break;
case VKD3DSIH_TEX:
if (context->version->major == 1)
sampler_reg = &instruction->dst[0].reg;
else
sampler_reg = &instruction->src[1].reg;
vkd3d_shader_scan_combined_sampler_usage(context, sampler_reg, sampler_reg);
break;
case VKD3DSIH_TEXBEM:
case VKD3DSIH_TEXBEML:
case VKD3DSIH_TEXDP3TEX:
case VKD3DSIH_TEXM3x2TEX:
case VKD3DSIH_TEXM3x3SPEC:
case VKD3DSIH_TEXM3x3TEX:
case VKD3DSIH_TEXM3x3VSPEC:
case VKD3DSIH_TEXREG2AR:
case VKD3DSIH_TEXREG2GB:
case VKD3DSIH_TEXREG2RGB:
sampler_reg = &instruction->dst[0].reg;
vkd3d_shader_scan_combined_sampler_usage(context, sampler_reg, sampler_reg);
break;
case VKD3DSIH_GATHER4:
case VKD3DSIH_GATHER4_C:
case VKD3DSIH_SAMPLE:
case VKD3DSIH_SAMPLE_B:
case VKD3DSIH_SAMPLE_C:
case VKD3DSIH_SAMPLE_C_LZ:
case VKD3DSIH_SAMPLE_GRAD:
case VKD3DSIH_SAMPLE_LOD:
vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[1].reg, &instruction->src[2].reg);
break;
case VKD3DSIH_GATHER4_PO:
case VKD3DSIH_GATHER4_PO_C:
vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[2].reg, &instruction->src[3].reg);
break;
case VKD3DSIH_LD:
case VKD3DSIH_LD2DMS:
vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[1].reg, NULL);
break;
case VKD3DSIH_BUFINFO:
case VKD3DSIH_SAMPLE_INFO:
if (instruction->src[0].reg.type == VKD3DSPR_RESOURCE)
vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[0].reg, NULL);
break;
case VKD3DSIH_LD_RAW:
case VKD3DSIH_RESINFO:
if (instruction->src[1].reg.type == VKD3DSPR_RESOURCE)
vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[1].reg, NULL);
break;
case VKD3DSIH_LD_STRUCTURED:
if (instruction->src[2].reg.type == VKD3DSPR_RESOURCE)
vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[2].reg, NULL);
break;
default:
break;
}
@ -1173,6 +1311,7 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
struct vkd3d_shader_message_context *message_context,
struct vkd3d_shader_scan_descriptor_info1 *descriptor_info1, struct vkd3d_shader_parser *parser)
{
struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info;
struct vkd3d_shader_scan_descriptor_info1 local_descriptor_info1 = {0};
struct vkd3d_shader_scan_descriptor_info *descriptor_info;
struct vkd3d_shader_scan_signature_info *signature_info;
@ -1193,7 +1332,16 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
}
signature_info = vkd3d_find_struct(compile_info->next, SCAN_SIGNATURE_INFO);
vkd3d_shader_scan_context_init(&context, compile_info, descriptor_info1, message_context);
if ((combined_sampler_info = vkd3d_find_struct(compile_info->next, SCAN_COMBINED_RESOURCE_SAMPLER_INFO)))
{
combined_sampler_info->combined_samplers = NULL;
combined_sampler_info->combined_sampler_count = 0;
if (!descriptor_info1)
descriptor_info1 = &local_descriptor_info1;
}
vkd3d_shader_scan_context_init(&context, &parser->shader_version, compile_info,
descriptor_info1, combined_sampler_info, message_context);
if (TRACE_ON())
{
@ -1239,6 +1387,8 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
if (ret < 0)
{
if (combined_sampler_info)
vkd3d_shader_free_scan_combined_resource_sampler_info(combined_sampler_info);
if (descriptor_info)
vkd3d_shader_free_scan_descriptor_info(descriptor_info);
if (descriptor_info1)
@ -1528,6 +1678,14 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
return ret;
}
void vkd3d_shader_free_scan_combined_resource_sampler_info(
struct vkd3d_shader_scan_combined_resource_sampler_info *info)
{
TRACE("info %p.\n", info);
vkd3d_free(info->combined_samplers);
}
void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info)
{
TRACE("scan_descriptor_info %p.\n", scan_descriptor_info);

View File

@ -853,6 +853,132 @@ static void test_build_varying_map(void)
ok(map[1].input_mask == 0x3, "Got map[1].input_mask %#x.\n", map[1].input_mask);
}
static void test_scan_combined_resource_samplers(void)
{
struct vkd3d_shader_hlsl_source_info hlsl_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO};
struct vkd3d_shader_compile_info info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO};
PFN_vkd3d_shader_free_scan_combined_resource_sampler_info pfn_free_combined_sampler_info;
struct vkd3d_shader_scan_combined_resource_sampler_info combined_sampler_info;
struct vkd3d_shader_combined_resource_sampler_info *s;
struct vkd3d_shader_code d3dbc;
int rc;
static const char ps_3_0_source[] =
"sampler s[3];\n"
"\n"
"float4 main(float4 coord : TEXCOORD) : COLOR\n"
"{\n"
" float4 r;\n"
"\n"
" r = tex2D(s[0], coord.xy);\n"
" r += tex2D(s[2], coord.xy);\n"
"\n"
" return r;\n"
"}\n";
static const uint32_t ps_5_1[] =
{
#if 0
Texture2D<float4> t0[8] : register(t8, space4);
Texture2D<float4> t1[4] : register(t9, space5);
SamplerState s2[4] : register(s10, space6);
SamplerState s3[8] : register(s11, space7);
float4 main(float4 coord : TEXCOORD) : SV_TARGET
{
float4 r;
r = t0[7].Sample(s2[3], coord.xy);
r += t1[2].Sample(s3[6], coord.xy);
r += t0[4].Load(coord.xyz);
return r;
}
#endif
0x43425844, 0x743f5994, 0x0c6d43cf, 0xde114c10, 0xc1adc69a, 0x00000001, 0x000001f8, 0x00000003,
0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x0000070f, 0x43584554, 0x44524f4f, 0xababab00,
0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x58454853, 0x0000015c, 0x00000051,
0x00000057, 0x0100086a, 0x0600005a, 0x00306e46, 0x00000000, 0x0000000a, 0x0000000d, 0x00000006,
0x0600005a, 0x00306e46, 0x00000001, 0x0000000b, 0x00000012, 0x00000007, 0x07001858, 0x00307e46,
0x00000000, 0x00000008, 0x0000000f, 0x00005555, 0x00000004, 0x07001858, 0x00307e46, 0x00000001,
0x00000009, 0x0000000c, 0x00005555, 0x00000005, 0x03001062, 0x00101072, 0x00000000, 0x03000065,
0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x0b000045, 0x001000f2, 0x00000000, 0x00101046,
0x00000000, 0x00207e46, 0x00000000, 0x0000000f, 0x00206000, 0x00000000, 0x0000000d, 0x0b000045,
0x001000f2, 0x00000001, 0x00101046, 0x00000000, 0x00207e46, 0x00000001, 0x0000000b, 0x00206000,
0x00000001, 0x00000011, 0x07000000, 0x001000f2, 0x00000000, 0x00100e46, 0x00000000, 0x00100e46,
0x00000001, 0x0500001b, 0x001000f2, 0x00000001, 0x00101a46, 0x00000000, 0x0800002d, 0x001000f2,
0x00000001, 0x00100e46, 0x00000001, 0x00207e46, 0x00000000, 0x0000000c, 0x07000000, 0x001020f2,
0x00000000, 0x00100e46, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
};
pfn_free_combined_sampler_info = vkd3d_shader_free_scan_combined_resource_sampler_info;
hlsl_info.profile = "ps_3_0";
info.next = &hlsl_info;
info.source.code = ps_3_0_source;
info.source.size = ARRAY_SIZE(ps_3_0_source);
info.source_type = VKD3D_SHADER_SOURCE_HLSL;
info.target_type = VKD3D_SHADER_TARGET_D3D_BYTECODE;
info.log_level = VKD3D_SHADER_LOG_INFO;
rc = vkd3d_shader_compile(&info, &d3dbc, NULL);
ok(rc == VKD3D_OK, "Got rc %d.\n", rc);
combined_sampler_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO;
combined_sampler_info.next = NULL;
info.next = &combined_sampler_info;
info.source = d3dbc;
info.source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE;
info.target_type = VKD3D_SHADER_TARGET_NONE;
rc = vkd3d_shader_scan(&info, NULL);
ok(rc == VKD3D_OK, "Got rc %d.\n", rc);
ok(combined_sampler_info.combined_sampler_count == 2, "Got combined_sampler_count %u.\n",
combined_sampler_info.combined_sampler_count);
s = &combined_sampler_info.combined_samplers[0];
ok(s->resource_space == 0, "Got resource space %u.\n", s->resource_space);
ok(s->resource_index == 0, "Got resource index %u.\n", s->resource_index);
ok(s->sampler_space == 0, "Got sampler space %u.\n", s->sampler_space);
ok(s->sampler_index == 0, "Got sampler index %u.\n", s->sampler_index);
s = &combined_sampler_info.combined_samplers[1];
ok(s->resource_space == 0, "Got resource space %u.\n", s->resource_space);
ok(s->resource_index == 2, "Got resource index %u.\n", s->resource_index);
ok(s->sampler_space == 0, "Got sampler space %u.\n", s->sampler_space);
ok(s->sampler_index == 2, "Got sampler index %u.\n", s->sampler_index);
pfn_free_combined_sampler_info(&combined_sampler_info);
vkd3d_shader_free_shader_code(&d3dbc);
info.source.code = ps_5_1;
info.source.size = sizeof(ps_5_1);
info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF;
rc = vkd3d_shader_scan(&info, NULL);
ok(rc == VKD3D_OK, "Got rc %d.\n", rc);
ok(combined_sampler_info.combined_sampler_count == 3, "Got combined_sampler_count %u.\n",
combined_sampler_info.combined_sampler_count);
s = &combined_sampler_info.combined_samplers[0];
ok(s->resource_space == 4, "Got resource space %u.\n", s->resource_space);
ok(s->resource_index == 15, "Got resource index %u.\n", s->resource_index);
ok(s->sampler_space == 6, "Got sampler space %u.\n", s->sampler_space);
ok(s->sampler_index == 13, "Got sampler index %u.\n", s->sampler_index);
s = &combined_sampler_info.combined_samplers[1];
ok(s->resource_space == 5, "Got resource space %u.\n", s->resource_space);
ok(s->resource_index == 11, "Got resource index %u.\n", s->resource_index);
ok(s->sampler_space == 7, "Got sampler space %u.\n", s->sampler_space);
ok(s->sampler_index == 17, "Got sampler index %u.\n", s->sampler_index);
s = &combined_sampler_info.combined_samplers[2];
ok(s->resource_space == 4, "Got resource space %u.\n", s->resource_space);
ok(s->resource_index == 12, "Got resource index %u.\n", s->resource_index);
ok(s->sampler_space == 0, "Got sampler space %u.\n", s->sampler_space);
ok(s->sampler_index == VKD3D_SHADER_DUMMY_SAMPLER_INDEX, "Got sampler index %u.\n", s->sampler_index);
pfn_free_combined_sampler_info(&combined_sampler_info);
}
START_TEST(vkd3d_shader_api)
{
setlocale(LC_ALL, "");
@ -865,4 +991,5 @@ START_TEST(vkd3d_shader_api)
run_test(test_scan_signatures);
run_test(test_scan_descriptors);
run_test(test_build_varying_map);
run_test(test_scan_combined_resource_samplers);
}