From: Henri Verbeet hverbeet@codeweavers.com
--- include/vkd3d_shader.h | 83 ++++++++++++++++++++++ libs/vkd3d-shader/dxbc.c | 89 +++++++++++++++++++++--- libs/vkd3d-shader/vkd3d_shader.map | 2 + libs/vkd3d-shader/vkd3d_shader_private.h | 7 +- 4 files changed, 165 insertions(+), 16 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 86ffb9d5..e6f47a73 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -1472,6 +1472,42 @@ enum vkd3d_shader_swizzle_component VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SWIZZLE_COMPONENT), };
+/** + * A description of a DXBC section. + * + * \since 1.7 + */ +struct vkd3d_shader_dxbc_section_desc +{ + /** The section tag. */ + uint32_t tag; + /** The contents of the section. */ + struct vkd3d_shader_code data; +}; + +/** + * A description of a DXBC blob, as returned by vkd3d_shader_parse_dxbc(). + * + * \since 1.7 + */ +struct vkd3d_shader_dxbc_desc +{ + /** The DXBC tag. This should always be "DXBC". */ + uint32_t tag; + /** A checksum of the DXBC contents. */ + uint32_t checksum[4]; + /** + * The DXBC version. The only supported DXBC version in this version of + * vkd3d-shader is 1. */ + uint32_t version; + /** The total size of the DXBC blob. */ + uint32_t size; + /** The number of sections contained in the DXBC. */ + uint32_t section_count; + /** Descriptions of the sections contained in the DXBC. */ + struct vkd3d_shader_dxbc_section_desc *sections; +}; + /** * A mask selecting one component from a vkd3d-shader swizzle. The component has * type \ref vkd3d_shader_swizzle_component. @@ -1865,6 +1901,47 @@ VKD3D_SHADER_API int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_i */ VKD3D_SHADER_API void vkd3d_shader_set_log_callback(PFN_vkd3d_log callback);
+/** + * Free the contents of a vkd3d_shader_dxbc_desc structure allocated by + * another vkd3d-shader function, such as vkd3d_shader_parse_dxbc(). + * + * This function may free the \ref vkd3d_shader_dxbc_desc.sections member, but + * does not free the structure itself. + * + * \param dxbc The vkd3d_shader_dxbc_desc structure to free. + * + * \since 1.7 + */ +VKD3D_SHADER_API void vkd3d_shader_free_dxbc(struct vkd3d_shader_dxbc_desc *dxbc); + +/** + * Parse a DXBC blob contained in a vkd3d_shader_code structure. + * + * \param dxbc A vkd3d_shader_code structure containing the DXBC blob to parse. + * + * \param flags A set of flags modifying the behaviour of the function. No + * flags are defined for this version of vkd3d-shader, and this parameter + * should be set to 0. + * + * \param desc A vkd3d_shader_dxbc_desc structure describing the contents of + * the DXBC blob. This structure may contain pointers into the input blob; its + * contents are only valid while the input blob is valid. The contents of this + * structure should be freed with vkd3d_shader_free_dxbc() when no longer + * needed. + * + * \param messages Optional output location for error or informational messages + * produced by the parser. + * \n + * This parameter behaves identically to the \a messages parameter of + * vkd3d_shader_compile(). + * + * \return A member of \ref vkd3d_result. + * + * \since 1.7 + */ +VKD3D_SHADER_API int vkd3d_shader_parse_dxbc(const struct vkd3d_shader_code *dxbc, + uint32_t flags, struct vkd3d_shader_dxbc_desc *desc, char **messages); + #endif /* VKD3D_SHADER_NO_PROTOTYPES */
/** Type of vkd3d_shader_get_version(). */ @@ -1921,6 +1998,12 @@ typedef void (*PFN_vkd3d_shader_preprocess)(struct vkd3d_shader_compile_info *co /** Type of vkd3d_shader_set_log_callback(). \since 1.4 */ typedef void (*PFN_vkd3d_shader_set_log_callback)(PFN_vkd3d_log callback);
+/** Type of vkd3d_shader_free_dxbc(). \since 1.7 */ +typedef void (*PFN_vkd3d_shader_free_dxbc)(struct vkd3d_shader_dxbc_desc *dxbc); +/** Type of vkd3d_shader_parse_dxbc(). \since 1.7 */ +typedef int (*PFN_vkd3d_shader_parse_dxbc)(const struct vkd3d_shader_code *dxbc, + uint32_t flags, struct vkd3d_shader_dxbc_desc *desc, char **messages); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 72f67ef1..8dfb9408 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -1725,20 +1725,19 @@ static const char *shader_get_string(const char *data, size_t data_size, DWORD o return data + offset; }
-static int for_each_dxbc_section(const struct vkd3d_shader_code *dxbc, - struct vkd3d_shader_message_context *message_context, const char *source_name, - int (*section_handler)(const struct vkd3d_shader_dxbc_section_desc *section, void *ctx), void *ctx) +static int parse_dxbc(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context, + const char *source_name, struct vkd3d_shader_dxbc_desc *desc) { const struct vkd3d_shader_location location = {.source_name = source_name}; + struct vkd3d_shader_dxbc_section_desc *sections, *section; uint32_t checksum[4], calculated_checksum[4]; const char *data = dxbc->code; size_t data_size = dxbc->size; const char *ptr = data; - int ret = VKD3D_OK; uint32_t chunk_count; uint32_t total_size; - unsigned int i; uint32_t version; + unsigned int i; uint32_t tag;
if (data_size < VKD3D_DXBC_HEADER_SIZE) @@ -1792,9 +1791,14 @@ static int for_each_dxbc_section(const struct vkd3d_shader_code *dxbc, read_dword(&ptr, &chunk_count); TRACE("chunk count: %#x\n", chunk_count);
+ if (!(sections = vkd3d_calloc(chunk_count, sizeof(*sections)))) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXBC_OUT_OF_MEMORY, "Out of memory."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + for (i = 0; i < chunk_count; ++i) { - struct vkd3d_shader_dxbc_section_desc section; uint32_t chunk_tag, chunk_size; const char *chunk_ptr; uint32_t chunk_offset; @@ -1807,6 +1811,7 @@ static int for_each_dxbc_section(const struct vkd3d_shader_code *dxbc, WARN("Invalid chunk offset %#x (data size %zu).\n", chunk_offset, data_size); vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_OFFSET, "DXBC chunk %u has invalid offset %#x (data size %#zx).", i, chunk_offset, data_size); + vkd3d_free(sections); return VKD3D_ERROR_INVALID_ARGUMENT; }
@@ -1822,16 +1827,80 @@ static int for_each_dxbc_section(const struct vkd3d_shader_code *dxbc, vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_SIZE, "DXBC chunk %u has invalid size %#x (data size %#zx, chunk offset %#x).", i, chunk_offset, data_size, chunk_offset); + vkd3d_free(sections); return VKD3D_ERROR_INVALID_ARGUMENT; }
- section.tag = chunk_tag; - section.data.code = chunk_ptr; - section.data.size = chunk_size; - if ((ret = section_handler(§ion, ctx)) < 0) + section = §ions[i]; + section->tag = chunk_tag; + section->data.code = chunk_ptr; + section->data.size = chunk_size; + } + + desc->tag = tag; + memcpy(desc->checksum, checksum, sizeof(checksum)); + desc->version = version; + desc->size = total_size; + desc->section_count = chunk_count; + desc->sections = sections; + + return VKD3D_OK; +} + +void vkd3d_shader_free_dxbc(struct vkd3d_shader_dxbc_desc *dxbc) +{ + TRACE("dxbc %p.\n", dxbc); + + vkd3d_free(dxbc->sections); +} + +static int for_each_dxbc_section(const struct vkd3d_shader_code *dxbc, + struct vkd3d_shader_message_context *message_context, const char *source_name, + int (*section_handler)(const struct vkd3d_shader_dxbc_section_desc *section, void *ctx), void *ctx) +{ + struct vkd3d_shader_dxbc_desc desc; + unsigned int i; + int ret; + + if ((ret = parse_dxbc(dxbc, message_context, source_name, &desc)) < 0) + return ret; + + for (i = 0; i < desc.section_count; ++i) + { + if ((ret = section_handler(&desc.sections[i], ctx)) < 0) break; }
+ vkd3d_shader_free_dxbc(&desc); + + return ret; +} + +int vkd3d_shader_parse_dxbc(const struct vkd3d_shader_code *dxbc, + uint32_t flags, struct vkd3d_shader_dxbc_desc *desc, char **messages) +{ + struct vkd3d_shader_message_context message_context; + int ret; + + TRACE("dxbc {%p, %zu}, flags %#x, desc %p, messages %p.\n", dxbc->code, dxbc->size, flags, desc, messages); + + if (messages) + *messages = NULL; + vkd3d_shader_message_context_init(&message_context, VKD3D_SHADER_LOG_INFO); + + ret = parse_dxbc(dxbc, &message_context, NULL, desc); + + vkd3d_shader_message_context_trace_messages(&message_context); + if (!vkd3d_shader_message_context_copy_messages(&message_context, messages) && ret >= 0) + { + vkd3d_shader_free_dxbc(desc); + ret = VKD3D_ERROR_OUT_OF_MEMORY; + } + vkd3d_shader_message_context_cleanup(&message_context); + + if (ret < 0) + memset(desc, 0, sizeof(*desc)); + return ret; }
diff --git a/libs/vkd3d-shader/vkd3d_shader.map b/libs/vkd3d-shader/vkd3d_shader.map index cac96972..096cb848 100644 --- a/libs/vkd3d-shader/vkd3d_shader.map +++ b/libs/vkd3d-shader/vkd3d_shader.map @@ -4,6 +4,7 @@ global: vkd3d_shader_compile; vkd3d_shader_convert_root_signature; vkd3d_shader_find_signature_element; + vkd3d_shader_free_dxbc; vkd3d_shader_free_messages; vkd3d_shader_free_root_signature; vkd3d_shader_free_scan_descriptor_info; @@ -12,6 +13,7 @@ global: vkd3d_shader_get_supported_source_types; vkd3d_shader_get_supported_target_types; vkd3d_shader_get_version; + vkd3d_shader_parse_dxbc; vkd3d_shader_parse_input_signature; vkd3d_shader_parse_root_signature; vkd3d_shader_preprocess; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index e7d05848..78a48e55 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -68,6 +68,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXBC_INVALID_VERSION = 4, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_OFFSET = 5, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_SIZE = 6, + VKD3D_SHADER_ERROR_DXBC_OUT_OF_MEMORY = 7,
VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF = 1000, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_RANGE = 1001, @@ -1308,12 +1309,6 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain, #define TAG_SHEX VKD3D_MAKE_TAG('S', 'H', 'E', 'X') #define TAG_TEXT VKD3D_MAKE_TAG('T', 'E', 'X', 'T')
-struct vkd3d_shader_dxbc_section_desc -{ - uint32_t tag; - struct vkd3d_shader_code data; -}; - #define DXBC_MAX_SECTION_COUNT 5
struct dxbc_writer