From: Zebediah Figura zfigura@codeweavers.com
--- include/private/vkd3d_memory.h | 9 + include/vkd3d_shader.h | 213 +++++++++++++++++++++++ libs/vkd3d-shader/dxbc.c | 178 +++++++++++++++++++ libs/vkd3d-shader/dxil.c | 1 + libs/vkd3d-shader/tpf.c | 1 + libs/vkd3d-shader/vkd3d_shader.map | 1 + libs/vkd3d-shader/vkd3d_shader_main.c | 37 ++++ libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 8 files changed, 442 insertions(+)
diff --git a/include/private/vkd3d_memory.h b/include/private/vkd3d_memory.h index 8a2edb100..d89f741b5 100644 --- a/include/private/vkd3d_memory.h +++ b/include/private/vkd3d_memory.h @@ -65,6 +65,15 @@ static inline char *vkd3d_strdup(const char *string) return ptr; }
+static inline void *vkd3d_memdup(const void *mem, size_t size) +{ + void *ptr; + + if ((ptr = vkd3d_malloc(size))) + memcpy(ptr, mem, size); + return ptr; +} + bool vkd3d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size);
#endif /* __VKD3D_MEMORY_H */ diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index a8cc3a336..32156c5ed 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -102,6 +102,11 @@ enum vkd3d_shader_structure_type * \since 1.10 */ VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO, + /** + * The structure is a vkd3d_shader_scan_d3d_buffer_info structure. + * \since 1.11 + */ + VKD3D_SHADER_STRUCTURE_TYPE_SCAN_D3D_BUFFER_INFO,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE), }; @@ -1922,6 +1927,210 @@ struct vkd3d_shader_varying_map_info unsigned int varying_count; };
+enum vkd3d_shader_d3d_type_kind +{ + VKD3D_SHADER_D3D_TYPE_KIND_SCALAR = 0, + VKD3D_SHADER_D3D_TYPE_KIND_VECTOR = 1, + VKD3D_SHADER_D3D_TYPE_KIND_MATRIX_ROW_MAJOR = 2, + VKD3D_SHADER_D3D_TYPE_KIND_MATRIX_COLUMN_MAJOR = 3, + VKD3D_SHADER_D3D_TYPE_KIND_OBJECT = 4, + VKD3D_SHADER_D3D_TYPE_KIND_STRUCT = 5, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_D3D_TYPE_KIND), +}; + +enum vkd3d_shader_d3d_base_type +{ + VKD3D_SHADER_D3D_BASE_TYPE_VOID, + VKD3D_SHADER_D3D_BASE_TYPE_BOOL, + VKD3D_SHADER_D3D_BASE_TYPE_INT, + VKD3D_SHADER_D3D_BASE_TYPE_FLOAT, + VKD3D_SHADER_D3D_BASE_TYPE_STRING, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE1D, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE2D, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE3D, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURECUBE, + VKD3D_SHADER_D3D_BASE_TYPE_SAMPLER, + VKD3D_SHADER_D3D_BASE_TYPE_SAMPLER1D, + VKD3D_SHADER_D3D_BASE_TYPE_SAMPLER2D, + VKD3D_SHADER_D3D_BASE_TYPE_SAMPLER3D, + VKD3D_SHADER_D3D_BASE_TYPE_SAMPLERCUBE, + VKD3D_SHADER_D3D_BASE_TYPE_PIXELSHADER, + VKD3D_SHADER_D3D_BASE_TYPE_VERTEXSHADER, + VKD3D_SHADER_D3D_BASE_TYPE_PIXELFRAGMENT, + VKD3D_SHADER_D3D_BASE_TYPE_VERTEXFRAGMENT, + VKD3D_SHADER_D3D_BASE_TYPE_UINT, + VKD3D_SHADER_D3D_BASE_TYPE_UINT8, + VKD3D_SHADER_D3D_BASE_TYPE_GEOMETRYSHADER, + VKD3D_SHADER_D3D_BASE_TYPE_RASTERIZER, + VKD3D_SHADER_D3D_BASE_TYPE_DEPTHSTENCIL, + VKD3D_SHADER_D3D_BASE_TYPE_BLEND, + VKD3D_SHADER_D3D_BASE_TYPE_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_CBUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_TBUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE1DARRAY, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE2DARRAY, + VKD3D_SHADER_D3D_BASE_TYPE_RENDERTARGETVIEW, + VKD3D_SHADER_D3D_BASE_TYPE_DEPTHSTENCILVIEW, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE2DMS, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURE2DMSARRAY, + VKD3D_SHADER_D3D_BASE_TYPE_TEXTURECUBEARRAY, + VKD3D_SHADER_D3D_BASE_TYPE_HULLSHADER, + VKD3D_SHADER_D3D_BASE_TYPE_DOMAINSHADER, + VKD3D_SHADER_D3D_BASE_TYPE_INTERFACE_POINTER, + VKD3D_SHADER_D3D_BASE_TYPE_COMPUTESHADER, + VKD3D_SHADER_D3D_BASE_TYPE_DOUBLE, + VKD3D_SHADER_D3D_BASE_TYPE_RWTEXTURE1D, + VKD3D_SHADER_D3D_BASE_TYPE_RWTEXTURE1DARRAY, + VKD3D_SHADER_D3D_BASE_TYPE_RWTEXTURE2D, + VKD3D_SHADER_D3D_BASE_TYPE_RWTEXTURE2DARRAY, + VKD3D_SHADER_D3D_BASE_TYPE_RWTEXTURE3D, + VKD3D_SHADER_D3D_BASE_TYPE_RWBUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_BYTEADDRESS_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_RWBYTEADDRESS_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_STRUCTURED_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_RWSTRUCTURED_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_APPEND_STRUCTURED_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_CONSUME_STRUCTURED_BUFFER, + VKD3D_SHADER_D3D_BASE_TYPE_MIN8FLOAT, + VKD3D_SHADER_D3D_BASE_TYPE_MIN10FLOAT, + VKD3D_SHADER_D3D_BASE_TYPE_MIN16FLOAT, + VKD3D_SHADER_D3D_BASE_TYPE_MIN12INT, + VKD3D_SHADER_D3D_BASE_TYPE_MIN16INT, + VKD3D_SHADER_D3D_BASE_TYPE_MIN16UINT, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_D3D_BASE_TYPE), +}; + +/** + * Information about a Direct3D type constructed from reflection data. + * + * Array types are represented by setting \ref element_count to the size of the + * array, and all other fields to those of the element type. + * + * This structure is used in struct vkd3d_shader_varying_map_info. + */ +struct vkd3d_shader_d3d_type +{ + /** Type kind, e.g. scalar, vector, struct, or object. */ + enum vkd3d_shader_d3d_type_kind kind; + /** Specific numeric or object type. */ + enum vkd3d_shader_d3d_base_type base_type; + /** Number of rows. */ + uint32_t row_count; + /** Number of columns. */ + uint32_t column_count; + /** Number of elements in an array, or 0 if this type is not an array. */ + uint32_t element_count; + /** Number of struct fields, or 0 if this type is not a struct. */ + uint32_t field_count; + /** Name of the type, or NULL if the type has no name. */ + const char *name; + /** + * Points to an array of \ref field_count fields, + * or NULL if this type is not a struct. + */ + const struct vkd3d_shader_d3d_field *fields; +}; + +struct vkd3d_shader_d3d_field +{ + const char *name; + /** Offset within the struct, in bytes. */ + uint32_t offset; + struct vkd3d_shader_d3d_type type; +}; + +enum vkd3d_shader_d3d_variable_flag +{ + VKD3D_SHADER_D3D_VARIABLE_USER_PACKED = 0x00000001, + VKD3D_SHADER_D3D_VARIABLE_USED = 0x00000002, +}; + +struct vkd3d_shader_d3d_variable +{ + /** Name of the variable. */ + const char *name; + /** Offset of this variable's numeric components, in bytes. */ + uint32_t offset; + /** Size of this variable's numeric components, in bytes. */ + uint32_t size; + /** + * A combination of zero or more elements of vkd3d_shader_d3d_variable_flag. + */ + uint32_t flags; + /** + * Base binding point of this variable's resource components, or ~0u + * if the variable has no resource components. + */ + uint32_t resource_binding; + /** Number of resource components associated with this variable. */ + uint32_t resource_count; + /** + * Base binding point of this variable's sampler components, or ~0u + * if the variable has no sampler components. + */ + uint32_t sampler_binding; + /** Number of sampler components associated with this variable. */ + uint32_t sampler_count; + /** + * If this is a legacy Direct3D shader, and the variable has numeric type + * (i.e. is not of type VKD3D_SHADER_D3D_TYPE_KIND_OBJECT), this field + * describes the register set to which this variable belongs. + * Otherwise, the contents of this field are undefined. + */ + enum vkd3d_shader_d3dbc_constant_register constant_register; + /** + * Default value of the variable, or NULL if the variable has no default + * value. + * If not NULL, this field points to an appropriately typed value + * of size \ref size. + */ + const void *default_value; + /** Type of the variable. */ + struct vkd3d_shader_d3d_type type; +}; + +enum vkd3d_shader_d3d_buffer_type +{ + VKD3D_SHADER_D3D_BUFFER_TYPE_CONSTANT = 0, + VKD3D_SHADER_D3D_BUFFER_TYPE_TEXTURE = 1, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_D3D_BUFFER_TYPE), +}; + +enum vkd3d_shader_d3d_buffer_flag +{ + VKD3D_SHADER_D3D_BUFFER_USER_PACKED = 0x00000001, +}; + +struct vkd3d_shader_d3d_buffer +{ + const char *name; + enum vkd3d_shader_d3d_buffer_type type; + /** + * A combination of zero or more elements of vkd3d_shader_d3d_buffer_flag. + */ + uint32_t flags; + + const struct vkd3d_shader_d3d_variable *variables; + unsigned int variable_count; + + /** Size of the buffer's numeric components, in bytes. */ + unsigned int size; +}; + +/** \since 1.11 */ +struct vkd3d_shader_scan_d3d_buffer_info +{ + enum vkd3d_shader_structure_type type; + const void *next; + + const struct vkd3d_shader_d3d_buffer *buffers; + unsigned int buffer_count; +}; + #ifdef LIBVKD3D_SHADER_SOURCE # define VKD3D_SHADER_API VKD3D_EXPORT #else @@ -2481,6 +2690,10 @@ VKD3D_SHADER_API void vkd3d_shader_build_varying_map(const struct vkd3d_shader_s VKD3D_SHADER_API void vkd3d_shader_free_scan_combined_resource_sampler_info( struct vkd3d_shader_scan_combined_resource_sampler_info *info);
+/** \since 1.11 */ +VKD3D_SHADER_API void vkd3d_shader_free_scan_d3d_buffer_info(struct vkd3d_shader_scan_d3d_buffer_info *info); + + #endif /* VKD3D_SHADER_NO_PROTOTYPES */
/** Type of vkd3d_shader_get_version(). */ diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 37ebc73c0..e628f01c2 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -20,6 +20,11 @@
#include "vkd3d_shader_private.h"
+#define DXBC_PROFILE_MAJOR_VERSION_SHIFT 8 +#define DXBC_PROFILE_MAJOR_VERSION_MASK (0xff << DXBC_PROFILE_MAJOR_VERSION_SHIFT) +#define DXBC_PROFILE_MINOR_VERSION_SHIFT 0 +#define DXBC_PROFILE_MINOR_VERSION_MASK (0xff << DXBC_PROFILE_MINOR_VERSION_SHIFT) + void dxbc_writer_init(struct dxbc_writer *dxbc) { memset(dxbc, 0, sizeof(*dxbc)); @@ -482,6 +487,174 @@ int shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, return ret; }
+static int parse_type(const struct vkd3d_shader_dxbc_section_desc *section, + uint32_t offset, struct vkd3d_shader_d3d_type *type, bool is_sm5) +{ + uint32_t temp, fields_offset, name_offset, field_type_offset; + const char *data = section->data.code; + const char *ptr = data + offset; + const char *name; + int ret; + + temp = read_u32(&ptr); + type->kind = temp & 0xffff; + type->base_type = temp >> 16; + temp = read_u32(&ptr); + type->row_count = temp & 0xffff; + type->column_count = temp >> 16; + temp = read_u32(&ptr); + type->element_count = temp & 0xffff; + type->field_count = temp >> 16; + fields_offset = read_u32(&ptr); + + if (is_sm5) + { + skip_dword_unknown(&ptr, 4); + name_offset = read_u32(&ptr); + + if ((name = shader_get_string(data, section->data.size, name_offset)) + && !(type->name = vkd3d_strdup(name))) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if (fields_offset) + { + struct vkd3d_shader_d3d_field *fields; + + if (!(fields = vkd3d_calloc(type->field_count, sizeof(*fields)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ptr = data + fields_offset; + + for (uint32_t i = 0; i < type->field_count; ++i) + { + struct vkd3d_shader_d3d_field *field = &fields[i]; + + name_offset = read_u32(&ptr); + field_type_offset = read_u32(&ptr); + field->offset = read_u32(&ptr); + + if ((name = shader_get_string(data, section->data.size, name_offset)) + && !(field->name = vkd3d_strdup(name))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if ((ret = parse_type(section, field_type_offset, &field->type, is_sm5)) < 0) + return ret; + } + + type->fields = fields; + } + + return VKD3D_OK; +} + +static int parse_variables(const struct vkd3d_shader_dxbc_section_desc *section, + uint32_t offset, struct vkd3d_shader_d3d_buffer *buffer, bool is_sm5) +{ + struct vkd3d_shader_d3d_variable *variables; + const char *data = section->data.code; + const char *ptr = data + offset; + int ret; + + if (!(variables = vkd3d_calloc(buffer->variable_count, sizeof(*variables)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + for (uint32_t i = 0; i < buffer->variable_count; ++i) + { + struct vkd3d_shader_d3d_variable *variable = &variables[i]; + uint32_t name_offset, type_offset, default_value_offset; + const char *name; + + name_offset = read_u32(&ptr); + variable->offset = read_u32(&ptr); + variable->size = read_u32(&ptr); + variable->flags = read_u32(&ptr); + type_offset = read_u32(&ptr); + default_value_offset = read_u32(&ptr); + + if ((name = shader_get_string(data, section->data.size, name_offset)) + && !(variable->name = vkd3d_strdup(name))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (default_value_offset + && !(variable->default_value = vkd3d_memdup(data + default_value_offset, variable->size))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (is_sm5) + { + variable->resource_binding = read_u32(&ptr); + variable->resource_count = read_u32(&ptr); + variable->sampler_binding = read_u32(&ptr); + variable->sampler_count = read_u32(&ptr); + } + + if ((ret = parse_type(section, type_offset, &variable->type, is_sm5))) + return ret; + } + + buffer->variables = variables; + + return VKD3D_OK; +} + +static int parse_rdef(const struct vkd3d_shader_dxbc_section_desc *section, + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_scan_d3d_buffer_info *buffer_info) +{ + uint32_t buffer_count, buffer_offset, profile; + const char *data = section->data.code; + const char *ptr = data; + bool is_sm5; + int ret; + + if (!buffer_info) + return VKD3D_OK; + + buffer_count = read_u32(&ptr); + buffer_offset = read_u32(&ptr); + /* Resource count and offset; not currently used. */ + read_u32(&ptr); + read_u32(&ptr); + profile = read_u32(&ptr); + + is_sm5 = ((profile >> DXBC_PROFILE_MAJOR_VERSION_SHIFT) & DXBC_PROFILE_MAJOR_VERSION_MASK) >= 5; + + if (buffer_count) + { + struct vkd3d_shader_d3d_buffer *buffers; + + if (!(buffers = vkd3d_calloc(buffer_count, sizeof(*buffers)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ptr = data + buffer_offset; + + for (uint32_t i = 0; i < buffer_count; ++i) + { + struct vkd3d_shader_d3d_buffer *buffer = &buffers[i]; + uint32_t name_offset, var_offset; + const char *name; + + name_offset = read_u32(&ptr); + buffer->variable_count = read_u32(&ptr); + var_offset = read_u32(&ptr); + buffer->size = read_u32(&ptr); + buffer->flags = read_u32(&ptr); + buffer->type = read_u32(&ptr); + + if ((name = shader_get_string(data, section->data.size, name_offset)) + && !(buffer->name = vkd3d_strdup(name))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if ((ret = parse_variables(section, var_offset, buffer, is_sm5))) + return ret; + } + + buffer_info->buffer_count = buffer_count; + buffer_info->buffers = buffers; + } + + return VKD3D_OK; +} + static int shdr_handler(const struct vkd3d_shader_dxbc_section_desc *section, struct vkd3d_shader_message_context *message_context, void *context) { @@ -538,6 +711,11 @@ static int shdr_handler(const struct vkd3d_shader_dxbc_section_desc *section, desc->byte_code_size = section->data.size; break;
+ case TAG_RDEF: + if ((ret = parse_rdef(section, message_context, desc->d3d_buffer_info)) < 0) + return ret; + break; + case TAG_AON9: TRACE("Skipping AON9 shader code chunk.\n"); break; diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 8a31d03c5..d4ed8e3b3 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -7290,6 +7290,7 @@ int vkd3d_shader_sm6_parser_create(const struct vkd3d_shader_compile_info *compi
shader_desc = &sm6->p.shader_desc; shader_desc->is_dxil = true; + shader_desc->d3d_buffer_info = vkd3d_find_struct(compile_info->next, SCAN_D3D_BUFFER_INFO); if ((ret = shader_extract_from_dxbc(&compile_info->source, message_context, compile_info->source_name, shader_desc)) < 0) { diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 50146c2c7..c7ad2287f 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2642,6 +2642,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi
shader_desc = &sm4->p.shader_desc; shader_desc->is_dxil = false; + shader_desc->d3d_buffer_info = vkd3d_find_struct(compile_info->next, SCAN_D3D_BUFFER_INFO); if ((ret = shader_extract_from_dxbc(&compile_info->source, message_context, compile_info->source_name, shader_desc)) < 0) { diff --git a/libs/vkd3d-shader/vkd3d_shader.map b/libs/vkd3d-shader/vkd3d_shader.map index 973f90779..8cb79bd92 100644 --- a/libs/vkd3d-shader/vkd3d_shader.map +++ b/libs/vkd3d-shader/vkd3d_shader.map @@ -9,6 +9,7 @@ global: vkd3d_shader_free_messages; vkd3d_shader_free_root_signature; vkd3d_shader_free_scan_combined_resource_sampler_info; + vkd3d_shader_free_scan_d3d_buffer_info; vkd3d_shader_free_scan_descriptor_info; vkd3d_shader_free_scan_signature_info; vkd3d_shader_free_shader_code; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index ac13be897..1d87f2499 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1762,6 +1762,43 @@ void vkd3d_shader_free_scan_signature_info(struct vkd3d_shader_scan_signature_in vkd3d_shader_free_shader_signature(&info->patch_constant); }
+static void free_d3d_type(const struct vkd3d_shader_d3d_type *type) +{ + for (uint32_t i = 0; i < type->field_count; ++i) + { + const struct vkd3d_shader_d3d_field *field = &type->fields[i]; + + free_d3d_type(&field->type); + vkd3d_free((void *)field->name); + } + vkd3d_free((void *)type->fields); + vkd3d_free((void *)type->name); +} + +void vkd3d_shader_free_scan_d3d_buffer_info(struct vkd3d_shader_scan_d3d_buffer_info *info) +{ + TRACE("info %p.\n", info); + + for (uint32_t i = 0; i < info->buffer_count; ++i) + { + const struct vkd3d_shader_d3d_buffer *buffer = &info->buffers[i]; + + for (uint32_t j = 0; j < buffer->variable_count; ++j) + { + const struct vkd3d_shader_d3d_variable *variable = &buffer->variables[j]; + + free_d3d_type(&variable->type); + vkd3d_free((void *)variable->default_value); + vkd3d_free((void *)variable->name); + } + + vkd3d_free((void *)buffer->variables); + vkd3d_free((void *)buffer->name); + } + + vkd3d_free((void *)info->buffers); +} + 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 288628845..20b1077a7 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1026,6 +1026,8 @@ struct vkd3d_shader_desc struct shader_signature output_signature; struct shader_signature patch_constant_signature;
+ struct vkd3d_shader_scan_d3d_buffer_info *d3d_buffer_info; + struct { uint32_t used, external;