From c107ec03b833b287c0969081db29e437e59bb2d5 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 6 Feb 2024 15:11:47 +0100 Subject: [PATCH] vkd3d-shader/fx: Add initial support for writing buffers descriptions. Signed-off-by: Nikolay Sivov --- libs/vkd3d-shader/fx.c | 352 +++++++++++++++++++++++++++++-- libs/vkd3d-shader/hlsl.h | 8 + libs/vkd3d-shader/hlsl_codegen.c | 60 +++--- 3 files changed, 376 insertions(+), 44 deletions(-) diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index ac7ffae8..ea7fdf9f 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,14 @@ struct string_entry uint32_t offset; }; +struct type_entry +{ + struct list entry; + const char *name; + uint32_t elements_count; + 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); @@ -48,6 +61,7 @@ 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 +74,28 @@ struct fx_write_context struct vkd3d_bytecode_buffer structured; struct rb_tree strings; + struct list 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 +106,46 @@ 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; + unsigned int elements_count; + const char *name; + + if (type->class == HLSL_CLASS_ARRAY) + { + name = hlsl_get_multiarray_element_type(type)->name; + elements_count = hlsl_get_multiarray_size(type); + } + else + { + name = type->name; + elements_count = 0; + } + + LIST_FOR_EACH_ENTRY(type_entry, &fx->types, struct type_entry, entry) + { + if (strcmp(type_entry->name, name)) + continue; + + if (type_entry->elements_count != elements_count) + continue; + + 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 = name; + type_entry->elements_count = elements_count; + + list_add_tail(&fx->types, &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,13 +172,22 @@ static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_co } rb_init(&fx->strings, string_storage_compare); + list_init(&fx->types); } static int fx_write_context_cleanup(struct fx_write_context *fx) { + struct type_entry *type, *next_type; int status = fx->status; + rb_destroy(&fx->strings, string_storage_destroy, NULL); + LIST_FOR_EACH_ENTRY_SAFE(type, next_type, &fx->types, struct type_entry, entry) + { + list_remove(&type->entry); + vkd3d_free(type); + } + return status; } @@ -181,6 +255,156 @@ 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 get_fx_4_numeric_type_description(const struct hlsl_type *type, struct fx_write_context *fx) +{ + static const unsigned int NUMERIC_BASE_TYPE_SHIFT = 3; + static const unsigned int NUMERIC_ROWS_SHIFT = 8; + static const unsigned int NUMERIC_COLUMNS_SHIFT = 11; + static const unsigned int NUMERIC_COLUMN_MAJOR_MASK = 0x4000; + 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, + }; + uint32_t value = 0; + + switch (type->class) + { + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: + case HLSL_CLASS_MATRIX: + value |= 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: + value |= (numeric_base_type[type->base_type] << NUMERIC_BASE_TYPE_SHIFT); + break; + default: + FIXME("Unexpected base type %u.\n", type->base_type); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + return 0; + } + + value |= (type->dimy & 0x7) << NUMERIC_ROWS_SHIFT; + value |= (type->dimx & 0x7) << NUMERIC_COLUMNS_SHIFT; + if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR) + value |= NUMERIC_COLUMN_MAJOR_MASK; + + return value; +} + +static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + uint32_t name_offset, offset, size, stride, numeric_desc; + uint32_t elements_count = 0; + 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, + }; + + /* 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); + } + + name_offset = write_string(type->name, fx); + offset = put_u32_unaligned(buffer, name_offset); + + 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 = stride = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); + if (elements_count) + size *= elements_count; + stride = align(stride, 4 * sizeof(float)); + + put_u32_unaligned(buffer, elements_count); + put_u32_unaligned(buffer, size); /* Total size. */ + put_u32_unaligned(buffer, stride); /* 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 */ + { + numeric_desc = get_fx_4_numeric_type_description(type, fx); + put_u32_unaligned(buffer, numeric_desc); + } + + 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 +426,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 +583,121 @@ 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->extern_vars, struct hlsl_ir_var, extern_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; + struct hlsl_block block; + + hlsl_block_init(&block); + hlsl_prepend_global_uniform_copy(fx->ctx, &block); + hlsl_block_init(&block); + hlsl_calculate_buffer_offsets(fx->ctx); + + LIST_FOR_EACH_ENTRY(buffer, &fx->ctx->buffers, struct hlsl_buffer, entry) + { + if (!buffer->size) + 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 +705,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 +750,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. */ diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 50c22fa5..834add8d 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1148,6 +1148,11 @@ static inline unsigned int hlsl_sampler_dim_count(enum hlsl_sampler_dim dim) } } +static inline bool hlsl_var_has_buffer_offset_register_reservation(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var) +{ + return var->reg_reservation.reg_type == 'c' && var->buffer == ctx->globals_buffer; +} + char *hlsl_sprintf_alloc(struct hlsl_ctx *ctx, const char *fmt, ...) VKD3D_PRINTF_FUNC(2, 3); const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op); @@ -1316,6 +1321,9 @@ bool hlsl_type_is_resource(const struct hlsl_type *type); unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2); +void hlsl_calculate_buffer_offsets(struct hlsl_ctx *ctx); +void hlsl_prepend_global_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block); + const struct hlsl_type *hlsl_get_multiarray_element_type(const struct hlsl_type *type); unsigned int hlsl_get_multiarray_size(const struct hlsl_type *type); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 4121fadf..7da42779 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4335,7 +4335,7 @@ static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint3 return NULL; } -static void calculate_buffer_offset(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, bool register_reservation) +static void hlsl_calculate_buffer_offset(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, bool register_reservation) { unsigned int var_reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC]; enum hlsl_type_class var_class = var->data_type->class; @@ -4449,9 +4449,27 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) } } -static bool var_has_buffer_offset_register_reservation(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var) +void hlsl_calculate_buffer_offsets(struct hlsl_ctx *ctx) { - return var->reg_reservation.reg_type == 'c' && var->buffer == ctx->globals_buffer; + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) + continue; + + if (hlsl_var_has_buffer_offset_register_reservation(ctx, var)) + hlsl_calculate_buffer_offset(ctx, var, true); + } + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) + continue; + + if (!hlsl_var_has_buffer_offset_register_reservation(ctx, var)) + hlsl_calculate_buffer_offset(ctx, var, false); + } } static void allocate_buffers(struct hlsl_ctx *ctx) @@ -4469,24 +4487,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) var->buffer = ctx->params_buffer; } - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { - if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) - continue; - - if (var_has_buffer_offset_register_reservation(ctx, var)) - calculate_buffer_offset(ctx, var, true); - } - - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { - if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) - continue; - - if (!var_has_buffer_offset_register_reservation(ctx, var)) - calculate_buffer_offset(ctx, var, false); - } - + hlsl_calculate_buffer_offsets(ctx); validate_buffer_offsets(ctx); LIST_FOR_EACH_ENTRY(buffer, &ctx->buffers, struct hlsl_buffer, entry) @@ -4959,6 +4960,17 @@ static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *bod } } +void hlsl_prepend_global_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *body) +{ + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) + { + if (var->storage_modifiers & HLSL_STORAGE_UNIFORM) + prepend_uniform_copy(ctx, body, var); + } +} + int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out) { @@ -4987,11 +4999,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry lower_ir(ctx, lower_matrix_swizzles, body); lower_ir(ctx, lower_index_loads, body); - LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) - { - if (var->storage_modifiers & HLSL_STORAGE_UNIFORM) - prepend_uniform_copy(ctx, body, var); - } + hlsl_prepend_global_uniform_copy(ctx, body); for (i = 0; i < entry_func->parameters.count; ++i) {