From: Zebediah Figura Subject: [PATCH vkd3d 4/4] vkd3d-shader: Add support for retrieving the creator string from DXBC shaders. Message-Id: <20211228222020.13814-4-zfigura@codeweavers.com> Date: Tue, 28 Dec 2021 16:20:20 -0600 In-Reply-To: <20211228222020.13814-1-zfigura@codeweavers.com> References: <20211228222020.13814-1-zfigura@codeweavers.com> Signed-off-by: Zebediah Figura --- include/vkd3d_shader.h | 4 + libs/vkd3d-shader/d3dbc.c | 7 +- libs/vkd3d-shader/dxbc.c | 159 +++++++++++++++-------- libs/vkd3d-shader/vkd3d_shader.map | 1 + libs/vkd3d-shader/vkd3d_shader_main.c | 20 ++- libs/vkd3d-shader/vkd3d_shader_private.h | 11 +- tests/vkd3d_shader_api.c | 1 + 7 files changed, 146 insertions(+), 57 deletions(-) diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 25abf217e..da926b620 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -1304,6 +1304,8 @@ struct vkd3d_shader_scan_function_info const void *next; struct vkd3d_shader_version version; + + const char *creator; }; /** @@ -1815,6 +1817,8 @@ VKD3D_SHADER_API void vkd3d_shader_free_shader_signature(struct vkd3d_shader_sig VKD3D_SHADER_API int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, char **messages); +VKD3D_SHADER_API void vkd3d_shader_free_scan_function_info(struct vkd3d_shader_scan_function_info *info); + #endif /* VKD3D_SHADER_NO_PROTOTYPES */ /** Type of vkd3d_shader_get_version(). */ diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index c5518752a..eabcc73e9 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -728,6 +728,10 @@ static void shader_sm1_validate_instruction(struct vkd3d_shader_sm1_parser *sm1, } } +static void shader_sm1_read_metadata(struct vkd3d_shader_parser *parser) +{ +} + static void shader_sm1_read_instruction(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *ins) { struct vkd3d_shader_sm1_parser *sm1 = vkd3d_shader_sm1_parser(parser); @@ -863,6 +867,7 @@ const struct vkd3d_shader_parser_ops shader_sm1_parser_ops = { .parser_reset = shader_sm1_reset, .parser_destroy = shader_sm1_destroy, + .parser_read_metadata = shader_sm1_read_metadata, .parser_read_instruction = shader_sm1_read_instruction, .parser_is_end = shader_sm1_is_end, }; @@ -922,7 +927,7 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, sm1->start = &code[1]; sm1->end = &code[token_count]; - vkd3d_shader_parser_init(&sm1->p, message_context, compile_info->source_name, &version, &shader_sm1_parser_ops); + vkd3d_shader_parser_init(&sm1->p, message_context, compile_info, &version, &shader_sm1_parser_ops); shader_desc = &sm1->p.shader_desc; shader_desc->byte_code = code; shader_desc->byte_code_size = code_size; diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 0b76a4a35..9144881e9 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -96,6 +96,7 @@ struct vkd3d_shader_sm4_parser struct list src_free; struct list src; struct vkd3d_shader_immediate_constant_buffer icb; + bool found_rdef; struct vkd3d_shader_parser p; }; @@ -175,11 +176,63 @@ static bool shader_is_sm_5_1(const struct vkd3d_shader_sm4_parser *sm4) return version->major >= 5 && version->minor >= 1; } +static int parse_dxbc(const char *data, size_t data_size, + struct vkd3d_shader_message_context *message_context, const char *source_name, + int (*chunk_handler)(const char *data, DWORD data_size, DWORD tag, void *ctx), void *ctx); static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, const uint32_t *end, enum vkd3d_data_type data_type, struct vkd3d_shader_src_param *src_param); static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, const uint32_t *end, enum vkd3d_data_type data_type, struct vkd3d_shader_dst_param *dst_param); +static bool require_space(size_t offset, size_t count, size_t size, size_t data_size) +{ + return !count || (data_size - offset) / count >= size; +} + +static void read_dword(const char **ptr, DWORD *d) +{ + memcpy(d, *ptr, sizeof(*d)); + *ptr += sizeof(*d); +} + +static void read_float(const char **ptr, float *f) +{ + STATIC_ASSERT(sizeof(float) == sizeof(DWORD)); + read_dword(ptr, (DWORD *)f); +} + +static void skip_dword_unknown(const char **ptr, unsigned int count) +{ + unsigned int i; + DWORD d; + + WARN("Skipping %u unknown DWORDs:\n", count); + for (i = 0; i < count; ++i) + { + read_dword(ptr, &d); + WARN("\t0x%08x\n", d); + } +} + +static const char *shader_get_string(const char *data, size_t data_size, DWORD offset) +{ + size_t len, max_len; + + if (offset >= data_size) + { + WARN("Invalid offset %#x (data size %#lx).\n", offset, (long)data_size); + return NULL; + } + + max_len = data_size - offset; + len = strnlen(data + offset, max_len); + + if (len == max_len) + return NULL; + + return data + offset; +} + static bool shader_sm4_read_register_space(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, const uint32_t *end, unsigned int *register_space) { @@ -1441,6 +1494,54 @@ static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_sh } } +static void shader_parse_rdef(uint32_t tag, const char *data, size_t data_size, struct vkd3d_shader_sm4_parser *sm4) +{ + DWORD cb_count, cb_offset, resource_count, resource_offset, target, flags, creator_offset; + const char *ptr = data; + + read_dword(&ptr, &cb_count); + read_dword(&ptr, &cb_offset); + read_dword(&ptr, &resource_count); + read_dword(&ptr, &resource_offset); + read_dword(&ptr, &target); + read_dword(&ptr, &flags); + read_dword(&ptr, &creator_offset); + + /* TODO: Parse RD11 chunks, resources, constant buffers. */ + + sm4->p.creator = shader_get_string(data, data_size, creator_offset); +} + +static int metadata_handler(const char *data, DWORD data_size, DWORD tag, void *ctx) +{ + struct vkd3d_shader_sm4_parser *sm4 = ctx; + + switch (tag) + { + case TAG_RDEF: + case TAG_RD11: + if (sm4->found_rdef) + FIXME("Multiple reflection chunks.\n"); + shader_parse_rdef(tag, data, data_size, sm4); + break; + + default: + TRACE("Skipping chunk %#x.\n", tag); + break; + } + + return VKD3D_OK; +} + +static void shader_sm4_read_metadata(struct vkd3d_shader_parser *parser) +{ + struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser); + + if (parse_dxbc(parser->shader->code, parser->shader->size, parser->message_context, + parser->location.source_name, metadata_handler, sm4)) + ERR("Failed to parse metadata.\n"); +} + static void shader_sm4_read_instruction(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *ins) { struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser); @@ -1582,12 +1683,13 @@ static const struct vkd3d_shader_parser_ops shader_sm4_parser_ops = { .parser_reset = shader_sm4_reset, .parser_destroy = shader_sm4_destroy, + .parser_read_metadata = shader_sm4_read_metadata, .parser_read_instruction = shader_sm4_read_instruction, .parser_is_end = shader_sm4_is_end, }; -static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t *byte_code, - size_t byte_code_size, const char *source_name, const struct vkd3d_shader_signature *output_signature, +static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t *byte_code, size_t byte_code_size, + const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_signature *output_signature, struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_version version; @@ -1646,7 +1748,7 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t version.major = VKD3D_SM4_VERSION_MAJOR(version_token); version.minor = VKD3D_SM4_VERSION_MINOR(version_token); - vkd3d_shader_parser_init(&sm4->p, message_context, source_name, &version, &shader_sm4_parser_ops); + vkd3d_shader_parser_init(&sm4->p, message_context, compile_info, &version, &shader_sm4_parser_ops); sm4->p.ptr = sm4->start; memset(sm4->output_map, 0xff, sizeof(sm4->output_map)); @@ -1669,55 +1771,6 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t return true; } -static bool require_space(size_t offset, size_t count, size_t size, size_t data_size) -{ - return !count || (data_size - offset) / count >= size; -} - -static void read_dword(const char **ptr, DWORD *d) -{ - memcpy(d, *ptr, sizeof(*d)); - *ptr += sizeof(*d); -} - -static void read_float(const char **ptr, float *f) -{ - STATIC_ASSERT(sizeof(float) == sizeof(DWORD)); - read_dword(ptr, (DWORD *)f); -} - -static void skip_dword_unknown(const char **ptr, unsigned int count) -{ - unsigned int i; - DWORD d; - - WARN("Skipping %u unknown DWORDs:\n", count); - for (i = 0; i < count; ++i) - { - read_dword(ptr, &d); - WARN("\t0x%08x\n", d); - } -} - -static const char *shader_get_string(const char *data, size_t data_size, DWORD offset) -{ - size_t len, max_len; - - if (offset >= data_size) - { - WARN("Invalid offset %#x (data size %#lx).\n", offset, (long)data_size); - return NULL; - } - - max_len = data_size - offset; - len = strnlen(data + offset, max_len); - - if (len == max_len) - return NULL; - - return data + offset; -} - static int parse_dxbc(const char *data, size_t data_size, struct vkd3d_shader_message_context *message_context, const char *source_name, int (*chunk_handler)(const char *data, DWORD data_size, DWORD tag, void *ctx), void *ctx) @@ -2050,7 +2103,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi } if (!shader_sm4_init(sm4, shader_desc->byte_code, shader_desc->byte_code_size, - compile_info->source_name, &shader_desc->output_signature, message_context)) + compile_info, &shader_desc->output_signature, message_context)) { WARN("Failed to initialise shader parser.\n"); free_shader_desc(shader_desc); diff --git a/libs/vkd3d-shader/vkd3d_shader.map b/libs/vkd3d-shader/vkd3d_shader.map index 2e49fe248..1127391cf 100644 --- a/libs/vkd3d-shader/vkd3d_shader.map +++ b/libs/vkd3d-shader/vkd3d_shader.map @@ -7,6 +7,7 @@ global: vkd3d_shader_free_messages; vkd3d_shader_free_root_signature; vkd3d_shader_free_scan_descriptor_info; + vkd3d_shader_free_scan_function_info; vkd3d_shader_free_shader_code; vkd3d_shader_free_shader_signature; vkd3d_shader_get_supported_source_types; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 7e82f18db..307ffce70 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -365,11 +365,12 @@ void vkd3d_shader_dump_shader(enum vkd3d_shader_source_type source_type, } void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, - struct vkd3d_shader_message_context *message_context, const char *source_name, + struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops) { + parser->shader = &compile_info->source; parser->message_context = message_context; - parser->location.source_name = source_name; + parser->location.source_name = compile_info->source_name; parser->location.line = 1; parser->location.column = 0; parser->shader_version = *version; @@ -983,7 +984,15 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info if (func_info) { + vkd3d_shader_parser_read_metadata(parser); + func_info->version = parser->shader_version; + func_info->creator = NULL; + if (parser->creator && !(func_info->creator = vkd3d_strdup(parser->creator))) + { + ret = VKD3D_ERROR_OUT_OF_MEMORY; + goto done; + } } ret = VKD3D_OK; @@ -1251,6 +1260,13 @@ void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_ vkd3d_free(scan_descriptor_info->descriptors); } +void vkd3d_shader_free_scan_function_info(struct vkd3d_shader_scan_function_info *info) +{ + TRACE("info %p.\n", info); + + vkd3d_free((char *)info->creator); +} + void vkd3d_shader_free_shader_code(struct vkd3d_shader_code *shader_code) { TRACE("shader_code %p.\n", shader_code); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c7ffa3c81..b4d856948 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -880,6 +880,7 @@ struct vkd3d_shader_location struct vkd3d_shader_parser { + const struct vkd3d_shader_code *shader; struct vkd3d_shader_message_context *message_context; struct vkd3d_shader_location location; bool failed; @@ -888,12 +889,15 @@ struct vkd3d_shader_parser struct vkd3d_shader_version shader_version; const uint32_t *ptr; const struct vkd3d_shader_parser_ops *ops; + + const char *creator; }; struct vkd3d_shader_parser_ops { void (*parser_reset)(struct vkd3d_shader_parser *parser); void (*parser_destroy)(struct vkd3d_shader_parser *parser); + void (*parser_read_metadata)(struct vkd3d_shader_parser *parser); void (*parser_read_instruction)(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *instruction); bool (*parser_is_end)(struct vkd3d_shader_parser *parser); }; @@ -901,7 +905,7 @@ struct vkd3d_shader_parser_ops void vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4); void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, - struct vkd3d_shader_message_context *message_context, const char *source_name, + struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops); void vkd3d_shader_parser_warning(struct vkd3d_shader_parser *parser, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4); @@ -916,6 +920,11 @@ static inline bool vkd3d_shader_parser_is_end(struct vkd3d_shader_parser *parser return parser->ops->parser_is_end(parser); } +static inline void vkd3d_shader_parser_read_metadata(struct vkd3d_shader_parser *parser) +{ + parser->ops->parser_read_metadata(parser); +} + static inline void vkd3d_shader_parser_read_instruction(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *instruction) { diff --git a/tests/vkd3d_shader_api.c b/tests/vkd3d_shader_api.c index 31eeb17f2..89455b627 100644 --- a/tests/vkd3d_shader_api.c +++ b/tests/vkd3d_shader_api.c @@ -356,6 +356,7 @@ static void test_scan_dxbc(void) ok(func_info.version.major == 4, "Got major version %u.\n", func_info.version.major); ok(func_info.version.minor == 1, "Got minor version %u.\n", func_info.version.minor); + vkd3d_shader_free_scan_function_info(&func_info); vkd3d_shader_free_shader_code(&dxbc); } -- 2.34.1