vkd3d-shader: Introduce an API to retrieve all signatures from DXBC shaders.

This commit is contained in:
Zebediah Figura 2023-02-23 16:21:18 -06:00 committed by Alexandre Julliard
parent 7b9eb8d189
commit 20190a1388
Notes: Alexandre Julliard 2023-06-27 23:33:23 +02: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/200
4 changed files with 335 additions and 38 deletions

View File

@ -85,6 +85,11 @@ enum vkd3d_shader_structure_type
* \since 1.3
*/
VKD3D_SHADER_STRUCTURE_TYPE_DESCRIPTOR_OFFSET_INFO,
/**
* The structure is a vkd3d_shader_scan_signature_info structure.
* \since 1.9
*/
VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE),
};
@ -1551,6 +1556,44 @@ static inline uint32_t vkd3d_shader_create_swizzle(enum vkd3d_shader_swizzle_com
| ((w & VKD3D_SHADER_SWIZZLE_MASK) << VKD3D_SHADER_SWIZZLE_SHIFT(3));
}
/**
* A chained structure containing descriptions of shader inputs and outputs.
*
* This structure is currently implemented only for DXBC source types. For DXBC
* shaders, the returned information is parsed directly from the signatures
* embedded in the DXBC shader. For all other shader types, the structure is
* zeroed.
*
* All members (except for \ref type and \ref next) are output-only.
*
* This structure is passed to vkd3d_shader_scan() and extends
* vkd3d_shader_compile_info.
*
* Members of this structure are allocated by vkd3d-shader and should be freed
* with vkd3d_shader_free_scan_signature_info() when no longer needed.
*
* All signatures may contain pointers into the input shader, and should only
* be accessed while the input shader remains valid.
*
* \since 1.9
*/
struct vkd3d_shader_scan_signature_info
{
/** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO. */
enum vkd3d_shader_structure_type type;
/** Optional pointer to a structure containing further parameters. */
const void *next;
/** The shader input varyings. */
struct vkd3d_shader_signature input;
/** The shader output varyings. */
struct vkd3d_shader_signature output;
/** The shader patch constant varyings. */
struct vkd3d_shader_signature patch_constant;
};
#ifdef LIBVKD3D_SHADER_SOURCE
# define VKD3D_SHADER_API VKD3D_EXPORT
#else
@ -1625,6 +1668,7 @@ VKD3D_SHADER_API const enum vkd3d_shader_target_type *vkd3d_shader_get_supported
* following chained structures:
* - vkd3d_shader_interface_info
* - vkd3d_shader_scan_descriptor_info
* - vkd3d_shader_scan_signature_info
* - vkd3d_shader_spirv_domain_shader_target_info
* - vkd3d_shader_spirv_target_info
* - vkd3d_shader_transform_feedback_info
@ -1811,6 +1855,7 @@ VKD3D_SHADER_API int vkd3d_shader_convert_root_signature(struct vkd3d_shader_ver
* \n
* The DXBC_TPF scanner supports the following chained structures:
* - vkd3d_shader_scan_descriptor_info
* - vkd3d_shader_scan_signature_info
* \n
* Although the \a compile_info parameter is read-only, chained structures
* passed to this function need not be, and may serve as output parameters,
@ -1847,12 +1892,18 @@ VKD3D_SHADER_API void vkd3d_shader_free_scan_descriptor_info(
struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info);
/**
* Read the input signature of a compiled shader, returning a structural
* Read the input signature of a compiled DXBC shader, returning a structural
* description which can be easily parsed by C code.
*
* This function parses a compiled shader. To parse a standalone root signature,
* use vkd3d_shader_parse_root_signature().
*
* This function only parses DXBC shaders, and only retrieves the input
* signature. To retrieve signatures from other shader types, or other signature
* types, use vkd3d_shader_scan() and struct vkd3d_shader_scan_signature_info.
* This function returns the same input signature that is returned in
* struct vkd3d_shader_scan_signature_info.
*
* \param dxbc Compiled byte code, in DXBC format.
*
* \param signature Output location in which the parsed root signature will be
@ -2042,6 +2093,19 @@ VKD3D_SHADER_API int vkd3d_shader_parse_dxbc(const struct vkd3d_shader_code *dxb
VKD3D_SHADER_API int vkd3d_shader_serialize_dxbc(size_t section_count,
const struct vkd3d_shader_dxbc_section_desc *sections, struct vkd3d_shader_code *dxbc, char **messages);
/**
* Free members of struct vkd3d_shader_scan_signature_info allocated by
* vkd3d_shader_scan().
*
* This function may free members of vkd3d_shader_scan_signature_info, but
* does not free the structure itself.
*
* \param info Scan information to free.
*
* \since 1.9
*/
VKD3D_SHADER_API void vkd3d_shader_free_scan_signature_info(struct vkd3d_shader_scan_signature_info *info);
#endif /* VKD3D_SHADER_NO_PROTOTYPES */
/** Type of vkd3d_shader_get_version(). */
@ -2107,6 +2171,9 @@ typedef int (*PFN_vkd3d_shader_parse_dxbc)(const struct vkd3d_shader_code *dxbc,
typedef int (*PFN_vkd3d_shader_serialize_dxbc)(size_t section_count,
const struct vkd3d_shader_dxbc_section_desc *sections, struct vkd3d_shader_code *dxbc, char **messages);
/** 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);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -8,6 +8,7 @@ global:
vkd3d_shader_free_messages;
vkd3d_shader_free_root_signature;
vkd3d_shader_free_scan_descriptor_info;
vkd3d_shader_free_scan_signature_info;
vkd3d_shader_free_shader_code;
vkd3d_shader_free_shader_signature;
vkd3d_shader_get_supported_source_types;

View File

@ -440,6 +440,18 @@ void vkd3d_shader_dump_shader(enum vkd3d_shader_source_type source_type,
shader_get_source_type_suffix(source_type), shader->code, shader->size);
}
static void init_scan_signature_info(const struct vkd3d_shader_compile_info *info)
{
struct vkd3d_shader_scan_signature_info *signature_info;
if ((signature_info = vkd3d_find_struct(info->next, SCAN_SIGNATURE_INFO)))
{
memset(&signature_info->input, 0, sizeof(signature_info->input));
memset(&signature_info->output, 0, sizeof(signature_info->output));
memset(&signature_info->patch_constant, 0, sizeof(signature_info->patch_constant));
}
}
bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser,
struct vkd3d_shader_message_context *message_context, const char *source_name,
const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops,
@ -526,6 +538,43 @@ void vkd3d_shader_free_messages(char *messages)
vkd3d_free(messages);
}
static bool vkd3d_shader_signature_from_shader_signature(struct vkd3d_shader_signature *signature,
const struct shader_signature *src)
{
unsigned int i;
signature->element_count = src->element_count;
if (!src->elements)
{
assert(!signature->element_count);
signature->elements = NULL;
return true;
}
if (!(signature->elements = vkd3d_calloc(signature->element_count, sizeof(*signature->elements))))
return false;
for (i = 0; i < signature->element_count; ++i)
{
struct vkd3d_shader_signature_element *d = &signature->elements[i];
struct signature_element *e = &src->elements[i];
d->semantic_name = e->semantic_name;
d->semantic_index = e->semantic_index;
d->stream_index = e->stream_index;
d->sysval_semantic = e->sysval_semantic;
d->component_type = e->component_type;
d->register_index = e->register_index;
if (e->register_count > 1)
FIXME("Arrayed elements are not supported yet.\n");
d->mask = e->mask;
d->used_mask = e->used_mask;
d->min_precision = e->min_precision;
}
return true;
}
struct vkd3d_shader_scan_context
{
struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info;
@ -1070,6 +1119,7 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser *parser)
{
struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info;
struct vkd3d_shader_scan_signature_info *signature_info;
struct vkd3d_shader_instruction *instruction;
struct vkd3d_shader_scan_context context;
int ret = VKD3D_OK;
@ -1080,6 +1130,7 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
scan_descriptor_info->descriptors = NULL;
scan_descriptor_info->descriptor_count = 0;
}
signature_info = vkd3d_find_struct(compile_info->next, SCAN_SIGNATURE_INFO);
vkd3d_shader_scan_context_init(&context, compile_info, scan_descriptor_info, message_context);
@ -1099,6 +1150,21 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
}
}
if (!ret && signature_info)
{
if (!vkd3d_shader_signature_from_shader_signature(&signature_info->input, &parser->shader_desc.input_signature)
|| !vkd3d_shader_signature_from_shader_signature(&signature_info->output,
&parser->shader_desc.output_signature)
|| !vkd3d_shader_signature_from_shader_signature(&signature_info->patch_constant,
&parser->shader_desc.patch_constant_signature))
{
vkd3d_shader_free_scan_signature_info(signature_info);
if (scan_descriptor_info)
vkd3d_shader_free_scan_descriptor_info(scan_descriptor_info);
ret = VKD3D_ERROR_OUT_OF_MEMORY;
}
}
vkd3d_shader_scan_context_cleanup(&context);
return ret;
}
@ -1152,6 +1218,8 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char
if ((ret = vkd3d_shader_validate_compile_info(compile_info, false)) < 0)
return ret;
init_scan_signature_info(compile_info);
vkd3d_shader_message_context_init(&message_context, compile_info->log_level);
switch (compile_info->source_type)
@ -1305,6 +1373,8 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
if ((ret = vkd3d_shader_validate_compile_info(compile_info, true)) < 0)
return ret;
init_scan_signature_info(compile_info);
vkd3d_shader_message_context_init(&message_context, compile_info->log_level);
switch (compile_info->source_type)
@ -1339,6 +1409,15 @@ void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_
vkd3d_free(scan_descriptor_info->descriptors);
}
void vkd3d_shader_free_scan_signature_info(struct vkd3d_shader_scan_signature_info *info)
{
TRACE("info %p.\n", info);
vkd3d_shader_free_shader_signature(&info->input);
vkd3d_shader_free_shader_signature(&info->output);
vkd3d_shader_free_shader_signature(&info->patch_constant);
}
void vkd3d_shader_free_shader_code(struct vkd3d_shader_code *shader_code)
{
TRACE("shader_code %p.\n", shader_code);
@ -1401,43 +1480,6 @@ void vkd3d_shader_free_root_signature(struct vkd3d_shader_versioned_root_signatu
desc->version = 0;
}
static bool vkd3d_shader_signature_from_shader_signature(struct vkd3d_shader_signature *signature,
const struct shader_signature *src)
{
unsigned int i;
signature->element_count = src->element_count;
if (!src->elements)
{
assert(!signature->element_count);
signature->elements = NULL;
return true;
}
if (!(signature->elements = vkd3d_calloc(signature->element_count, sizeof(*signature->elements))))
return false;
for (i = 0; i < signature->element_count; ++i)
{
struct vkd3d_shader_signature_element *d = &signature->elements[i];
struct signature_element *e = &src->elements[i];
d->semantic_name = e->semantic_name;
d->semantic_index = e->semantic_index;
d->stream_index = e->stream_index;
d->sysval_semantic = e->sysval_semantic;
d->component_type = e->component_type;
d->register_index = e->register_index;
if (e->register_count > 1)
FIXME("Arrayed elements are not supported yet.\n");
d->mask = e->mask;
d->used_mask = e->used_mask;
d->min_precision = e->min_precision;
}
return true;
}
void shader_signature_cleanup(struct shader_signature *signature)
{
vkd3d_free(signature->elements);

View File

@ -401,6 +401,192 @@ static void test_dxbc(void)
vkd3d_shader_free_shader_code(&dxbc);
}
static void check_signature_element(const struct vkd3d_shader_signature_element *element,
const struct vkd3d_shader_signature_element *expect)
{
ok(!strcmp(element->semantic_name, expect->semantic_name), "Got semantic name %s.\n", element->semantic_name);
ok(element->semantic_index == expect->semantic_index, "Got semantic index %u.\n", element->semantic_index);
ok(element->stream_index == expect->stream_index, "Got stream index %u.\n", element->stream_index);
ok(element->sysval_semantic == expect->sysval_semantic, "Got sysval semantic %#x.\n", element->sysval_semantic);
ok(element->component_type == expect->component_type, "Got component type %#x.\n", element->component_type);
ok(element->register_index == expect->register_index, "Got register index %u.\n", element->register_index);
ok(element->mask == expect->mask, "Got mask %#x.\n", element->mask);
todo_if (expect->used_mask != expect->mask)
ok(element->used_mask == expect->used_mask, "Got used mask %#x.\n", element->used_mask);
ok(element->min_precision == expect->min_precision, "Got minimum precision %#x.\n", element->min_precision);
}
static void test_scan_signatures(void)
{
struct vkd3d_shader_scan_signature_info signature_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO};
struct vkd3d_shader_hlsl_source_info hlsl_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO};
struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO};
struct vkd3d_shader_code dxbc;
size_t i, j;
int rc;
static const char vs1_source[] =
"void main(\n"
" in float4 a : apple,\n"
" out float4 b : banana2,\n"
" inout float4 c : color,\n"
" inout float4 d : depth,\n"
" inout float4 e : sv_position,\n"
" in uint3 f : fruit,\n"
" inout bool2 g : grape,\n"
" in int h : honeydew,\n"
" in uint i : sv_vertexid)\n"
"{\n"
" b.yw = a.xz;\n"
"}";
static const struct vkd3d_shader_signature_element vs1_inputs[] =
{
{"apple", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 0, 0xf, 0x5},
{"color", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 1, 0xf, 0xf},
{"depth", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 2, 0xf, 0xf},
{"sv_position", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 3, 0xf, 0xf},
{"fruit", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_UINT, 4, 0x7},
{"grape", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_UINT, 5, 0x3, 0x3},
{"honeydew", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_INT, 6, 0x1},
{"sv_vertexid", 0, 0, VKD3D_SHADER_SV_VERTEX_ID, VKD3D_SHADER_COMPONENT_UINT, 7, 0x1},
};
static const struct vkd3d_shader_signature_element vs1_outputs[] =
{
{"banana", 2, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 0, 0xf, 0xa},
{"color", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 1, 0xf, 0xf},
{"depth", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 2, 0xf, 0xf},
{"sv_position", 0, 0, VKD3D_SHADER_SV_POSITION, VKD3D_SHADER_COMPONENT_FLOAT, 3, 0xf, 0xf},
{"grape", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_UINT, 4, 0x3, 0x3},
};
static const char vs2_source[] =
"void main(inout float4 pos : position)\n"
"{\n"
"}";
static const struct vkd3d_shader_signature_element vs2_inputs[] =
{
{"position", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 0, 0xf, 0xf},
};
static const struct vkd3d_shader_signature_element vs2_outputs[] =
{
{"position", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 0, 0xf, 0xf},
};
static const char ps1_source[] =
"void main(\n"
" in float2 a : apple,\n"
" out float4 b : sv_target2,\n"
" out float c : sv_depth,\n"
" in float4 d : position,\n"
" in float4 e : sv_position)\n"
"{\n"
" b = d;\n"
" c = 0;\n"
"}";
static const struct vkd3d_shader_signature_element ps1_inputs[] =
{
{"apple", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 0, 0x3},
{"position", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 1, 0xf, 0xf},
{"sv_position", 0, 0, VKD3D_SHADER_SV_POSITION, VKD3D_SHADER_COMPONENT_FLOAT, 2, 0xf},
};
static const struct vkd3d_shader_signature_element ps1_outputs[] =
{
{"sv_target", 2, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, 2, 0xf, 0xf},
{"sv_depth", 0, 0, VKD3D_SHADER_SV_NONE, VKD3D_SHADER_COMPONENT_FLOAT, ~0u, 0x1, 0x1},
};
static const char cs1_source[] =
"[numthreads(1, 1, 1)]\n"
"void main(\n"
" in uint a : sv_dispatchthreadid,\n"
" in uint b : sv_groupid,\n"
" in uint c : sv_groupthreadid)\n"
"{\n"
"}";
static const struct
{
const char *source;
const char *profile;
const struct vkd3d_shader_signature_element *inputs;
size_t input_count;
const struct vkd3d_shader_signature_element *outputs;
size_t output_count;
const struct vkd3d_shader_signature_element *patch_constants;
size_t patch_constant_count;
}
tests[] =
{
{vs1_source, "vs_4_0", vs1_inputs, ARRAY_SIZE(vs1_inputs), vs1_outputs, ARRAY_SIZE(vs1_outputs)},
{vs2_source, "vs_4_0", vs2_inputs, ARRAY_SIZE(vs2_inputs), vs2_outputs, ARRAY_SIZE(vs2_outputs)},
{ps1_source, "ps_4_0", ps1_inputs, ARRAY_SIZE(ps1_inputs), ps1_outputs, ARRAY_SIZE(ps1_outputs)},
{cs1_source, "cs_5_0", NULL, 0, NULL, 0},
};
for (i = 0; i < ARRAY_SIZE(tests); ++i)
{
vkd3d_test_push_context("test %u", i);
compile_info.source.code = tests[i].source;
compile_info.source.size = strlen(tests[i].source);
compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL;
compile_info.target_type = VKD3D_SHADER_TARGET_DXBC_TPF;
compile_info.log_level = VKD3D_SHADER_LOG_INFO;
compile_info.next = &hlsl_info;
hlsl_info.profile = tests[i].profile;
rc = vkd3d_shader_compile(&compile_info, &dxbc, NULL);
ok(rc == VKD3D_OK, "Got unexpected error code %d.\n", rc);
compile_info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF;
compile_info.source = dxbc;
compile_info.next = &signature_info;
rc = vkd3d_shader_scan(&compile_info, NULL);
ok(rc == VKD3D_OK, "Got unexpected error code %d.\n", rc);
ok(signature_info.input.element_count == tests[i].input_count,
"Got input count %u.\n", signature_info.input.element_count);
for (j = 0; j < signature_info.input.element_count; ++j)
{
vkd3d_test_push_context("input %u", j);
check_signature_element(&signature_info.input.elements[j], &tests[i].inputs[j]);
vkd3d_test_pop_context();
}
ok(signature_info.output.element_count == tests[i].output_count,
"Got output count %u.\n", signature_info.output.element_count);
for (j = 0; j < signature_info.output.element_count; ++j)
{
vkd3d_test_push_context("output %u", j);
check_signature_element(&signature_info.output.elements[j], &tests[i].outputs[j]);
vkd3d_test_pop_context();
}
ok(signature_info.patch_constant.element_count == tests[i].patch_constant_count,
"Got patch constant count %u.\n", signature_info.patch_constant.element_count);
for (j = 0; j < signature_info.patch_constant.element_count; ++j)
{
vkd3d_test_push_context("patch constant %u", j);
check_signature_element(&signature_info.patch_constant.elements[j], &tests[i].patch_constants[j]);
vkd3d_test_pop_context();
}
vkd3d_shader_free_scan_signature_info(&signature_info);
vkd3d_shader_free_shader_code(&dxbc);
vkd3d_test_pop_context();
}
}
START_TEST(vkd3d_shader_api)
{
setlocale(LC_ALL, "");
@ -410,4 +596,5 @@ START_TEST(vkd3d_shader_api)
run_test(test_version);
run_test(test_d3dbc);
run_test(test_dxbc);
run_test(test_scan_signatures);
}