From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/fx.c | 337 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 319 insertions(+), 18 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index ac7ffae8c..2930e6dc2 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -20,6 +20,11 @@
#include "hlsl.h"
+static inline size_t put_u32_unaligned(struct vkd3d_bytecode_buffer *buffer, uint32_t value) +{ + return bytecode_put_bytes_unaligned(buffer, &value, sizeof(value)); +} + struct string_entry { struct rb_entry entry; @@ -28,6 +33,13 @@ struct string_entry uint32_t offset; };
+struct type_entry +{ + struct rb_entry entry; + const char *name; + uint32_t offset; +}; + static int string_storage_compare(const void *key, const struct rb_entry *entry) { struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry); @@ -43,11 +55,27 @@ static void string_storage_destroy(struct rb_entry *entry, void *context) vkd3d_free(string_entry); }
+static int type_storage_compare(const void *key, const struct rb_entry *entry) +{ + struct type_entry *type_entry = RB_ENTRY_VALUE(entry, struct type_entry, entry); + const char *name = key; + + return strcmp(name, type_entry->name); +} + +static void type_storage_destroy(struct rb_entry *entry, void *context) +{ + struct type_entry *type_entry = RB_ENTRY_VALUE(entry, struct type_entry, entry); + + vkd3d_free(type_entry); +} + struct fx_write_context;
struct fx_write_context_ops { uint32_t (*write_string)(const char *string, struct fx_write_context *fx); + uint32_t (*write_type)(const struct hlsl_type *type, struct fx_write_context *fx); void (*write_technique)(struct hlsl_ir_var *var, struct fx_write_context *fx); void (*write_pass)(struct hlsl_ir_var *var, struct fx_write_context *fx); }; @@ -60,17 +88,28 @@ struct fx_write_context struct vkd3d_bytecode_buffer structured;
struct rb_tree strings; + struct rb_tree types;
unsigned int min_technique_version; unsigned int max_technique_version;
uint32_t technique_count; uint32_t group_count; + uint32_t buffer_count; + uint32_t numeric_variable_count; int status;
const struct fx_write_context_ops *ops; };
+static void set_status(struct fx_write_context *fx, int status) +{ + if (fx->status < 0) + return; + if (status < 0) + fx->status = status; +} + static uint32_t write_string(const char *string, struct fx_write_context *fx) { return fx->ops->write_string(string, fx); @@ -81,6 +120,28 @@ static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) fx->ops->write_pass(var, fx); }
+static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx) +{ + struct type_entry *type_entry; + struct rb_entry *entry; + + if ((entry = rb_get(&fx->types, type->name))) + { + type_entry = RB_ENTRY_VALUE(entry, struct type_entry, entry); + return type_entry->offset; + } + + if (!(type_entry = hlsl_alloc(fx->ctx, sizeof(*type_entry)))) + return 0; + + type_entry->offset = fx->ops->write_type(type, fx); + type_entry->name = type->name; + + rb_put(&fx->types, type->name, &type_entry->entry); + + return type_entry->offset; +} + static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops, struct fx_write_context *fx) { @@ -107,12 +168,15 @@ static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_co }
rb_init(&fx->strings, string_storage_compare); + rb_init(&fx->types, type_storage_compare); }
static int fx_write_context_cleanup(struct fx_write_context *fx) { int status = fx->status; + rb_destroy(&fx->strings, string_storage_destroy, NULL); + rb_destroy(&fx->types, type_storage_destroy, NULL);
return status; } @@ -181,6 +245,157 @@ static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx /* TODO: assignments */ }
+static uint32_t get_fx_4_type_size(const struct hlsl_type *type) +{ + uint32_t elements_count; + + elements_count = hlsl_get_multiarray_size(type); + type = hlsl_get_multiarray_element_type(type); + + return type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float) * elements_count; +} + +static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx) +{ + struct fx_4_numeric_type + { + uint32_t type_class : 3; + uint32_t base_type : 5; + uint32_t rows : 3; + uint32_t columns : 3; + uint32_t column_major : 1; + uint32_t unknown : 17; + }; + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + uint32_t name_offset, offset, size; + uint32_t elements_count = 0; + union + { + struct fx_4_numeric_type type; + uint32_t data; + } numeric_desc; + static const uint32_t variable_type[] = + { + [HLSL_CLASS_SCALAR] = 1, + [HLSL_CLASS_VECTOR] = 1, + [HLSL_CLASS_MATRIX] = 1, + [HLSL_CLASS_OBJECT] = 2, + [HLSL_CLASS_STRUCT] = 3, + }; + STATIC_ASSERT(sizeof(numeric_desc) == sizeof(uint32_t)); + + name_offset = write_string(type->name, fx); + offset = put_u32_unaligned(buffer, name_offset); + + /* Resolve arrays to element type and number of elements. */ + if (type->class == HLSL_CLASS_ARRAY) + { + elements_count = hlsl_get_multiarray_size(type); + type = hlsl_get_multiarray_element_type(type); + } + + switch (type->class) + { + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: + case HLSL_CLASS_MATRIX: + case HLSL_CLASS_OBJECT: + case HLSL_CLASS_STRUCT: + put_u32_unaligned(buffer, variable_type[type->class]); + break; + default: + FIXME("Writing type class %u is not implemented.\n", type->class); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + return 0; + } + + size = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); + + put_u32_unaligned(buffer, elements_count); + put_u32_unaligned(buffer, size); /* Total size. */ + put_u32_unaligned(buffer, align(size, 4 * sizeof(float))); /* Stride. */ + put_u32_unaligned(buffer, size); + + if (type->class == HLSL_CLASS_STRUCT) + { + size_t i; + + put_u32_unaligned(buffer, type->e.record.field_count); + for (i = 0; i < type->e.record.field_count; ++i) + { + const struct hlsl_struct_field *field = &type->e.record.fields[i]; + uint32_t semantic_offset, field_type_offset; + + name_offset = write_string(field->name, fx); + semantic_offset = write_string(field->semantic.name, fx); + field_type_offset = write_type(field->type, fx); + + put_u32_unaligned(buffer, name_offset); + put_u32_unaligned(buffer, semantic_offset); + put_u32_unaligned(buffer, field->reg_offset[HLSL_REGSET_NUMERIC]); + put_u32_unaligned(buffer, field_type_offset); + } + } + else if (type->class == HLSL_CLASS_OBJECT) + { + FIXME("Object types are not supported.\n"); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + return 0; + } + else /* Numeric type */ + { + static const uint32_t numeric_type_class[] = + { + [HLSL_CLASS_SCALAR] = 1, + [HLSL_CLASS_VECTOR] = 2, + [HLSL_CLASS_MATRIX] = 3, + }; + + static const uint32_t numeric_base_type[] = + { + [HLSL_TYPE_FLOAT] = 1, + [HLSL_TYPE_INT ] = 2, + [HLSL_TYPE_UINT ] = 3, + [HLSL_TYPE_BOOL ] = 4, + }; + + switch (type->class) + { + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: + case HLSL_CLASS_MATRIX: + numeric_desc.type.type_class = numeric_type_class[type->class]; + break; + default: + FIXME("Unexpected type class %u.\n", type->class); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + return 0; + } + + switch (type->base_type) + { + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_INT: + case HLSL_TYPE_UINT: + case HLSL_TYPE_BOOL: + numeric_desc.type.base_type = numeric_base_type[type->base_type]; + break; + default: + FIXME("Unexpected base type %u.\n", type->base_type); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + return 0; + } + + numeric_desc.type.rows = type->dimx; + numeric_desc.type.columns = type->dimy; + numeric_desc.type.column_major = !!(type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR); + numeric_desc.type.unknown = 0; + put_u32_unaligned(buffer, numeric_desc.data); + } + + return offset; +} + static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; @@ -202,14 +417,6 @@ static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_contex set_u32(buffer, count_offset, count); }
-static void set_status(struct fx_write_context *fx, int status) -{ - if (fx->status < 0) - return; - if (status < 0) - fx->status = status; -} - static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *fx) { struct hlsl_ir_var *var; @@ -367,21 +574,115 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) static const struct fx_write_context_ops fx_4_ops = { .write_string = write_fx_4_string, + .write_type = write_fx_4_type, .write_technique = write_fx_4_technique, .write_pass = write_fx_4_pass, };
+static void write_fx_4_variable(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->structured; + uint32_t semantic_offset, flags = 0; + uint32_t name_offset, type_offset; + enum fx_4_variable_flags + { + HAS_EXPLICIT_BIND_POINT = 0x4, + }; + + /* Explicit bind point. */ + if (var->reg_reservation.reg_type) + flags |= HAS_EXPLICIT_BIND_POINT; + + type_offset = write_type(var->data_type, fx); + name_offset = write_string(var->name, fx); + semantic_offset = write_string(var->semantic.name, fx); + + put_u32(buffer, name_offset); + put_u32(buffer, type_offset); + + semantic_offset = put_u32(buffer, semantic_offset); /* Semantic */ + put_u32(buffer, var->buffer_offset); /* Offset in the constant buffer */ + put_u32(buffer, 0); /* FIXME: default value offset */ + put_u32(buffer, flags); /* Flags */ + + put_u32(buffer, 0); /* Annotations count */ + /* FIXME: write annotations */ +} + +static void write_fx_4_buffer(struct hlsl_buffer *b, struct fx_write_context *fx) +{ + enum fx_4_buffer_flags + { + IS_TBUFFER = 0x1, + IS_SINGLE = 0x2, + }; + struct vkd3d_bytecode_buffer *buffer = &fx->structured; + uint32_t count = 0, bind_point = ~0u, flags = 0, size; + uint32_t name_offset, size_offset; + struct hlsl_ctx *ctx = fx->ctx; + struct hlsl_ir_var *var; + uint32_t count_offset; + + if (b->reservation.reg_type) + bind_point = b->reservation.reg_index; + if (b->type == HLSL_BUFFER_TEXTURE) + flags |= IS_TBUFFER; + /* FIXME: set 'single' flag for fx_5_0 */ + + name_offset = write_string(b->name, fx); + + put_u32(buffer, name_offset); /* Name */ + size_offset = put_u32(buffer, 0); /* Data size */ + put_u32(buffer, flags); /* Flags */ + count_offset = put_u32(buffer, 0); + put_u32(buffer, bind_point); /* Bind point */ + + put_u32(buffer, 0); /* Annotations count */ + /* FIXME: write annotations */ + + count = 0; + size = 0; + LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) + { + if (var->buffer != b) + continue; + + write_fx_4_variable(var, fx); + size += get_fx_4_type_size(var->data_type); + ++count; + } + + set_u32(buffer, count_offset, count); + set_u32(buffer, size_offset, align(size, 16)); + + fx->numeric_variable_count += count; +} + +static void write_buffers(struct fx_write_context *fx) +{ + struct hlsl_buffer *buffer; + + LIST_FOR_EACH_ENTRY(buffer, &fx->ctx->buffers, struct hlsl_buffer, entry) + { + if (buffer->empty) + continue; + + write_fx_4_buffer(buffer, fx); + ++fx->buffer_count; + } +} + static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { struct vkd3d_bytecode_buffer buffer = { 0 }; - struct fx_write_context fx; uint32_t size_offset, size; + struct fx_write_context fx;
fx_write_context_init(ctx, &fx_4_ops, &fx);
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
- /* TODO: buffers */ + write_buffers(&fx); /* TODO: objects */ /* TODO: shared buffers */ /* TODO: shared objects */ @@ -389,9 +690,9 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) write_techniques(ctx->globals, &fx);
put_u32(&buffer, ctx->profile->minor_version == 0 ? 0xfeff1001 : 0xfeff1011); /* Version. */ - put_u32(&buffer, 0); /* Buffer count. */ - put_u32(&buffer, 0); /* Variable count. */ - put_u32(&buffer, 0); /* Object count. */ + put_u32(&buffer, fx.buffer_count); /* Buffer count. */ + put_u32(&buffer, fx.numeric_variable_count); /* Numeric variable count. */ + put_u32(&buffer, 0); /* Object variable count. */ put_u32(&buffer, 0); /* Pool buffer count. */ put_u32(&buffer, 0); /* Pool variable count. */ put_u32(&buffer, 0); /* Pool object count. */ @@ -434,23 +735,23 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { struct vkd3d_bytecode_buffer buffer = { 0 }; - struct fx_write_context fx; uint32_t size_offset, size; + struct fx_write_context fx;
fx_write_context_init(ctx, &fx_4_ops, &fx);
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
- /* TODO: buffers */ + write_buffers(&fx); /* TODO: objects */ /* TODO: interface variables */
write_groups(&fx);
put_u32(&buffer, 0xfeff2001); /* Version. */ - put_u32(&buffer, 0); /* Buffer count. */ - put_u32(&buffer, 0); /* Variable count. */ - put_u32(&buffer, 0); /* Object count. */ + put_u32(&buffer, fx.buffer_count); /* Buffer count. */ + put_u32(&buffer, fx.numeric_variable_count); /* Numeric variable count. */ + put_u32(&buffer, 0); /* Object variable count. */ put_u32(&buffer, 0); /* Pool buffer count. */ put_u32(&buffer, 0); /* Pool variable count. */ put_u32(&buffer, 0); /* Pool object count. */