[PATCH vkd3d 4/4] vkd3d-shader: Add support for retrieving the creator string from DXBC shaders.

Zebediah Figura zfigura at codeweavers.com
Tue Dec 28 16:20:20 CST 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 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




More information about the wine-devel mailing list