From 40a35105a5ad10c4f55237bf75cd0a8f8e645ab2 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 21 Feb 2024 15:11:16 +1100 Subject: [PATCH] Updated vkd3d to d9c68ee481367d90da949cbd41b09ceb4b6a3823. --- libs/vkd3d/libs/vkd3d-shader/dxil.c | 284 ++++++++++--- libs/vkd3d/libs/vkd3d-shader/fx.c | 379 ++++++++++++++++-- libs/vkd3d/libs/vkd3d-shader/hlsl.c | 20 +- libs/vkd3d/libs/vkd3d-shader/hlsl.h | 16 +- libs/vkd3d/libs/vkd3d-shader/hlsl.y | 130 +++--- libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 48 ++- libs/vkd3d/libs/vkd3d-shader/tpf.c | 8 + .../libs/vkd3d-shader/vkd3d_shader_main.c | 10 +- .../libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 9 files changed, 712 insertions(+), 184 deletions(-) diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 33d30aef08e..2ca3aa955e7 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -199,10 +199,12 @@ enum dxil_resource_kind RESOURCE_KIND_FEEDBACKTEXTURE2DARRAY = 18, }; -enum dxil_resource_type +enum dxil_resource_tag { - RESOURCE_TYPE_NON_RAW_STRUCTURED = 0, - RESOURCE_TYPE_RAW_STRUCTURED = 1, + RESOURCE_TAG_ELEMENT_TYPE = 0, + RESOURCE_TAG_ELEMENT_STRIDE = 1, + RESOURCE_TAG_SAMPLER_FEEDBACK_KIND = 2, + RESOURCE_TAG_ENABLE_ATOMIC_64 = 3, }; enum dxil_component_type @@ -381,6 +383,8 @@ enum dx_intrinsic_opcode DX_TEXTURE_LOAD = 66, DX_TEXTURE_STORE = 67, DX_BUFFER_LOAD = 68, + DX_ATOMIC_BINOP = 78, + DX_ATOMIC_CMP_XCHG = 79, DX_DERIV_COARSEX = 83, DX_DERIV_COARSEY = 84, DX_DERIV_FINEX = 85, @@ -438,6 +442,20 @@ enum dxil_predicate ICMP_SLE = 41, }; +enum dxil_atomic_binop_code +{ + ATOMIC_BINOP_ADD, + ATOMIC_BINOP_AND, + ATOMIC_BINOP_OR, + ATOMIC_BINOP_XOR, + ATOMIC_BINOP_IMIN, + ATOMIC_BINOP_IMAX, + ATOMIC_BINOP_UMIN, + ATOMIC_BINOP_UMAX, + ATOMIC_BINOP_XCHG, + ATOMIC_BINOP_INVALID, +}; + struct sm6_pointer_info { const struct sm6_type *type; @@ -2275,7 +2293,7 @@ static void src_param_init_from_value(struct vkd3d_shader_src_param *param, cons static void src_param_init_vector_from_reg(struct vkd3d_shader_src_param *param, const struct vkd3d_shader_register *reg) { - param->swizzle = VKD3D_SHADER_NO_SWIZZLE; + param->swizzle = (reg->dimension == VSIR_DIMENSION_VEC4) ? VKD3D_SHADER_NO_SWIZZLE : VKD3D_SHADER_SWIZZLE(X, X, X, X); param->modifiers = VKD3DSPSM_NONE; param->reg = *reg; } @@ -3823,6 +3841,105 @@ static void sm6_parser_emit_dx_binary(struct sm6_parser *sm6, enum dx_intrinsic_ instruction_dst_param_init_ssa_scalar(ins, sm6); } +static enum vkd3d_shader_opcode map_dx_atomic_binop(const struct sm6_value *operand, struct sm6_parser *sm6) +{ + uint64_t code = sm6_value_get_constant_uint(operand); + + switch (code) + { + case ATOMIC_BINOP_ADD: + return VKD3DSIH_IMM_ATOMIC_IADD; + case ATOMIC_BINOP_AND: + return VKD3DSIH_IMM_ATOMIC_AND; + case ATOMIC_BINOP_IMAX: + return VKD3DSIH_IMM_ATOMIC_IMAX; + case ATOMIC_BINOP_IMIN: + return VKD3DSIH_IMM_ATOMIC_IMIN; + case ATOMIC_BINOP_OR: + return VKD3DSIH_IMM_ATOMIC_OR; + case ATOMIC_BINOP_UMAX: + return VKD3DSIH_IMM_ATOMIC_UMAX; + case ATOMIC_BINOP_UMIN: + return VKD3DSIH_IMM_ATOMIC_UMIN; + case ATOMIC_BINOP_XCHG: + return VKD3DSIH_IMM_ATOMIC_EXCH; + case ATOMIC_BINOP_XOR: + return VKD3DSIH_IMM_ATOMIC_XOR; + /* DXIL currently doesn't use SUB and NAND. */ + default: + FIXME("Unhandled atomic binop %"PRIu64".\n", code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Operation %"PRIu64" for an atomic binop instruction is unhandled.", code); + return VKD3DSIH_INVALID; + } +} + +static void sm6_parser_emit_dx_atomic_binop(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + struct sm6_value *dst = sm6_parser_get_current_value(sm6); + enum vkd3d_shader_resource_type resource_type; + bool is_cmp_xchg = op == DX_ATOMIC_CMP_XCHG; + unsigned int i, coord_idx, coord_count = 1; + struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_src_param *src_params; + enum vkd3d_shader_opcode handler_idx; + struct vkd3d_shader_instruction *ins; + const struct sm6_value *resource; + struct vkd3d_shader_register reg; + + resource = operands[0]; + if (!sm6_value_validate_is_handle(resource, sm6)) + return; + + if (is_cmp_xchg) + handler_idx = VKD3DSIH_IMM_ATOMIC_CMP_EXCH; + else if ((handler_idx = map_dx_atomic_binop(operands[1], sm6)) == VKD3DSIH_INVALID) + return; + + coord_idx = 2 - is_cmp_xchg; + resource_type = resource->u.handle.d->resource_type; + if (resource_type != VKD3D_SHADER_RESOURCE_BUFFER || resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER) + { + coord_count = 2 + (resource_type != VKD3D_SHADER_RESOURCE_BUFFER); + if (!sm6_parser_emit_coordinate_construct(sm6, &operands[coord_idx], coord_count, NULL, state, ®)) + return; + } + else + { + reg = operands[coord_idx]->u.reg; + } + + for (i = coord_idx + coord_count; i < coord_idx + 3; ++i) + { + if (!operands[i]->is_undefined) + { + WARN("Ignoring unexpected operand.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring an unexpected defined operand value for atomic instruction %u.", handler_idx); + break; + } + } + + ins = state->ins; + vsir_instruction_init(ins, &sm6->p.location, handler_idx); + + if (!(src_params = instruction_src_params_alloc(ins, 2 + is_cmp_xchg, sm6))) + return; + src_param_init_vector_from_reg(&src_params[0], ®); + if (is_cmp_xchg) + src_param_init_from_value(&src_params[1], operands[4]); + src_param_init_from_value(&src_params[1 + is_cmp_xchg], operands[5]); + + dst_params = instruction_dst_params_alloc(ins, 2, sm6); + dst_param_init(&dst_params[0]); + register_init_ssa_scalar(&dst_params[0].reg, dst->type, dst, sm6); + dst_param_init(&dst_params[1]); + dst_params[1].reg = resource->u.handle.reg; + + dst->u.reg = dst_params[0].reg; +} + static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { @@ -4357,6 +4474,8 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_ACOS ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_ASIN ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_ATAN ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_ATOMIC_BINOP ] = {"o", "HciiiR", sm6_parser_emit_dx_atomic_binop}, + [DX_ATOMIC_CMP_XCHG ] = {"o", "HiiiRR", sm6_parser_emit_dx_atomic_binop}, [DX_BFREV ] = {"m", "R", sm6_parser_emit_dx_unary}, [DX_BUFFER_LOAD ] = {"o", "Hii", sm6_parser_emit_dx_buffer_load}, [DX_CBUFFER_LOAD_LEGACY ] = {"o", "Hi", sm6_parser_emit_dx_cbuffer_load}, @@ -6556,15 +6675,97 @@ static enum vkd3d_data_type vkd3d_data_type_from_dxil_component_type(enum dxil_c return data_type; } +struct resource_additional_values +{ + enum vkd3d_data_type data_type; + unsigned int byte_stride; +}; + +static bool resources_load_additional_values(struct resource_additional_values *info, + const struct sm6_metadata_node *node, enum dxil_resource_kind kind, struct sm6_parser *sm6) +{ + unsigned int i, operand_count, tag, value; + + info->data_type = VKD3D_DATA_UNUSED; + info->byte_stride = 0; + + if (node->operand_count & 1) + { + WARN("Operand count is not even.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Operand count for resource descriptor tag/value pairs is not even."); + } + operand_count = node->operand_count & ~1u; + + for (i = 0; i < operand_count; i += 2) + { + if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &tag) + || !sm6_metadata_get_uint_value(sm6, node->operands[i + 1], &value)) + { + WARN("Failed to load tag/value pair at index %u.\n", i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource descriptor tag/value pair at index %u is not an integer pair.", i); + return false; + } + + switch (tag) + { + case RESOURCE_TAG_ELEMENT_TYPE: + if (value && kind != RESOURCE_KIND_TYPEDBUFFER && !resource_kind_is_texture(kind)) + { + WARN("Invalid type %u for an untyped resource.\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "An untyped resource has type %u.", value); + return false; + } + info->data_type = vkd3d_data_type_from_dxil_component_type(value, sm6); + break; + + case RESOURCE_TAG_ELEMENT_STRIDE: + if (value && kind != RESOURCE_KIND_STRUCTUREDBUFFER) + { + WARN("Invalid stride %u for an unstructured resource.\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "An unstructured resource has a byte stride."); + return false; + } + info->byte_stride = value; + break; + + case RESOURCE_TAG_SAMPLER_FEEDBACK_KIND: + /* MinMip = 0, MipRegionUsed = 1 */ + FIXME("Unhandled sampler feedback kind %u.\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Sampler feedback kind %u is unhandled.", value); + break; + + case RESOURCE_TAG_ENABLE_ATOMIC_64: + if (value) + { + FIXME("Unsupported 64-bit atomic ops.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "64-bit atomic ops on resources are not supported."); + } + break; + + default: + FIXME("Unhandled tag %u, value %u.\n", tag, value); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Tag %u for resource descriptor additional value %u is unhandled.", tag, value); + break; + } + } + + return true; +} + static struct vkd3d_shader_resource *sm6_parser_resources_load_common_info(struct sm6_parser *sm6, const struct sm6_metadata_value *type_value, bool is_uav, enum dxil_resource_kind kind, const struct sm6_metadata_value *m, struct vkd3d_shader_instruction *ins) { + struct resource_additional_values resource_values; enum vkd3d_shader_resource_type resource_type; - enum dxil_resource_type dxil_resource_type; - const struct sm6_metadata_node *node; - enum vkd3d_data_type data_type; - unsigned int i, values[2]; + unsigned int i; if (!(resource_type = shader_resource_type_from_dxil_resource_kind(kind))) { @@ -6590,72 +6791,37 @@ static struct vkd3d_shader_resource *sm6_parser_resources_load_common_info(struc return NULL; } - node = m->u.node; - - if (node->operand_count < 2) - { - WARN("Invalid operand count %u.\n", node->operand_count); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, - "Invalid operand count %u for a resource descriptor.", node->operand_count); + if (!resources_load_additional_values(&resource_values, m->u.node, kind, sm6)) return NULL; - } - if (node->operand_count > 2) - { - WARN("Ignoring %u extra operands.\n", node->operand_count - 2); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, - "Ignoring %u extra operands for a resource descriptor.", node->operand_count - 2); - } - - for (i = 0; i < 2; ++i) - { - if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &values[i])) - { - WARN("Failed to load uint value at index %u.\n", i); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, - "A resource descriptor operand metadata value is not an integer."); - return NULL; - } - } - if ((dxil_resource_type = values[0]) == RESOURCE_TYPE_NON_RAW_STRUCTURED) + if (kind == RESOURCE_KIND_TYPEDBUFFER || resource_kind_is_texture(kind)) { - if (kind != RESOURCE_KIND_TYPEDBUFFER && !resource_kind_is_texture(kind)) + if (resource_values.data_type == VKD3D_DATA_UNUSED) { - WARN("Unhandled resource kind %u.\n", kind); + WARN("No data type defined.\n"); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, - "Resource kind %u for a typed resource is unhandled.", kind); - return NULL; + "A typed resource has no data type."); } - data_type = vkd3d_data_type_from_dxil_component_type(values[1], sm6); ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_TYPED : VKD3DSIH_DCL; for (i = 0; i < VKD3D_VEC4_SIZE; ++i) - ins->declaration.semantic.resource_data_type[i] = data_type; + ins->declaration.semantic.resource_data_type[i] = resource_values.data_type; ins->declaration.semantic.resource_type = resource_type; ins->declaration.semantic.resource.reg.write_mask = VKD3DSP_WRITEMASK_ALL; return &ins->declaration.semantic.resource; } - else if (dxil_resource_type == RESOURCE_TYPE_RAW_STRUCTURED) + else if (kind == RESOURCE_KIND_RAWBUFFER) { - if (kind == RESOURCE_KIND_RAWBUFFER) - { - ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_RAW : VKD3DSIH_DCL_RESOURCE_RAW; - ins->declaration.raw_resource.resource.reg.write_mask = 0; - - return &ins->declaration.raw_resource.resource; - } - - if (kind != RESOURCE_KIND_STRUCTUREDBUFFER) - { - WARN("Unhandled resource kind %u.\n", kind); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, - "Resource kind %u for a raw or structured buffer is unhandled.", kind); - return NULL; - } + ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_RAW : VKD3DSIH_DCL_RESOURCE_RAW; + ins->declaration.raw_resource.resource.reg.write_mask = 0; + return &ins->declaration.raw_resource.resource; + } + else if (kind == RESOURCE_KIND_STRUCTUREDBUFFER) + { ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_STRUCTURED : VKD3DSIH_DCL_RESOURCE_STRUCTURED; - ins->declaration.structured_resource.byte_stride = values[1]; + ins->declaration.structured_resource.byte_stride = resource_values.byte_stride; ins->declaration.structured_resource.resource.reg.write_mask = 0; /* TODO: 16-bit resources. */ @@ -6671,9 +6837,9 @@ static struct vkd3d_shader_resource *sm6_parser_resources_load_common_info(struc } else { - FIXME("Unhandled resource type %u.\n", dxil_resource_type); + FIXME("Unhandled resource kind %u.\n", kind); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, - "Resource type %u is unhandled.", dxil_resource_type); + "Resource kind %u is unhandled.", kind); } return NULL; diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c index e1459f76c14..11dee4ba9d7 100644 --- a/libs/vkd3d/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d/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; } @@ -145,7 +219,7 @@ static uint32_t write_fx_4_string(const char *string, struct fx_write_context *f if (!(string_entry = hlsl_alloc(fx->ctx, sizeof(*string_entry)))) return 0; - string_entry->offset = put_string(&fx->unstructured, string); + string_entry->offset = bytecode_put_bytes_unaligned(&fx->unstructured, string, strlen(string) + 1); string_entry->string = string; rb_put(&fx->strings, string, &string_entry->entry); @@ -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; @@ -227,10 +443,10 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context * set_status(fx, fx->structured.status); } -static void write_group(struct hlsl_scope *scope, const char *name, struct fx_write_context *fx) +static void write_group(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; - uint32_t name_offset = write_string(name, fx); + uint32_t name_offset = write_string(var ? var->name : NULL, fx); uint32_t count_offset, count; put_u32(buffer, name_offset); @@ -238,14 +454,15 @@ static void write_group(struct hlsl_scope *scope, const char *name, struct fx_wr put_u32(buffer, 0); /* Annotation count */ count = fx->technique_count; - write_techniques(scope, fx); + write_techniques(var ? var->scope : fx->ctx->globals, fx); set_u32(buffer, count_offset, fx->technique_count - count); ++fx->group_count; } -static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx) +static void write_groups(struct fx_write_context *fx) { + struct hlsl_scope *scope = fx->ctx->globals; bool needs_default_group = false; struct hlsl_ir_var *var; @@ -259,13 +476,13 @@ static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx) } if (needs_default_group) - write_group(scope, NULL, fx); + write_group(NULL, fx); LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) { const struct hlsl_type *type = var->data_type; if (type->base_type == HLSL_TYPE_EFFECT_GROUP) - write_group(var->scope, var->name, fx); + write_group(var, fx); } } @@ -366,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; + uint32_t size_offset; 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 */ @@ -388,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. */ @@ -407,11 +724,10 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) put_u32(&buffer, 0); /* Shader count. */ put_u32(&buffer, 0); /* Inline shader count. */ - size = align(fx.unstructured.size, 4); - set_u32(&buffer, size_offset, size); + set_u32(&buffer, size_offset, fx.unstructured.size); bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size); - bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size); + bytecode_put_bytes_unaligned(&buffer, fx.structured.data, fx.structured.size); vkd3d_free(fx.unstructured.data); vkd3d_free(fx.structured.data); @@ -434,22 +750,22 @@ 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; + uint32_t size_offset; 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(ctx->globals, &fx); + 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. */ @@ -471,11 +787,10 @@ static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) put_u32(&buffer, 0); /* Interface variable element count. */ put_u32(&buffer, 0); /* Class instance elements count. */ - size = align(fx.unstructured.size, 4); - set_u32(&buffer, size_offset, size); + set_u32(&buffer, size_offset, fx.unstructured.size); bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size); - bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size); + bytecode_put_bytes_unaligned(&buffer, fx.structured.data, fx.structured.size); vkd3d_free(fx.unstructured.data); vkd3d_free(fx.structured.data); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c index 3d068ac6d3b..edd99238d59 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c @@ -1554,6 +1554,15 @@ bool hlsl_index_is_resource_access(struct hlsl_ir_index *index) return index->val.node->data_type->class == HLSL_CLASS_OBJECT; } +bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index) +{ + if (hlsl_index_is_resource_access(index)) + return true; + if (index->val.node->type == HLSL_IR_INDEX) + return hlsl_index_chain_has_resource_access(hlsl_ir_index(index->val.node)); + return false; +} + struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc) { @@ -2192,9 +2201,16 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru return string; } - assert(type->sampler_dim < ARRAY_SIZE(dimensions)); assert(type->e.resource_format->base_type < ARRAY_SIZE(base_types)); - vkd3d_string_buffer_printf(string, "Texture%s", dimensions[type->sampler_dim]); + if (type->sampler_dim == HLSL_SAMPLER_DIM_BUFFER) + { + vkd3d_string_buffer_printf(string, "Buffer"); + } + else + { + assert(type->sampler_dim < ARRAY_SIZE(dimensions)); + vkd3d_string_buffer_printf(string, "Texture%s", dimensions[type->sampler_dim]); + } if ((inner_string = hlsl_type_to_string(ctx, type->e.resource_format))) { vkd3d_string_buffer_printf(string, "<%s>", inner_string->buffer); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h index 974a5dd7aee..91500ed8b8b 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h @@ -104,7 +104,7 @@ enum hlsl_base_type enum hlsl_sampler_dim { - HLSL_SAMPLER_DIM_GENERIC, + HLSL_SAMPLER_DIM_GENERIC = 0, HLSL_SAMPLER_DIM_COMPARISON, HLSL_SAMPLER_DIM_1D, HLSL_SAMPLER_DIM_2D, @@ -116,10 +116,10 @@ enum hlsl_sampler_dim HLSL_SAMPLER_DIM_2DMS, HLSL_SAMPLER_DIM_2DMSARRAY, HLSL_SAMPLER_DIM_CUBEARRAY, - HLSL_SAMPLER_DIM_LAST_TEXTURE = HLSL_SAMPLER_DIM_CUBEARRAY, HLSL_SAMPLER_DIM_BUFFER, HLSL_SAMPLER_DIM_STRUCTURED_BUFFER, HLSL_SAMPLER_DIM_MAX = HLSL_SAMPLER_DIM_STRUCTURED_BUFFER, + /* NOTE: Remember to update object_methods[] in hlsl.y if this enum is modified. */ }; enum hlsl_regset @@ -149,7 +149,8 @@ struct hlsl_type enum hlsl_base_type base_type; /* If base_type is HLSL_TYPE_SAMPLER, then sampler_dim is <= HLSL_SAMPLER_DIM_LAST_SAMPLER. - * If base_type is HLSL_TYPE_TEXTURE, then sampler_dim is <= HLSL_SAMPLER_DIM_LAST_TEXTURE. + * If base_type is HLSL_TYPE_TEXTURE, then sampler_dim can be any value of the enum except + * HLSL_SAMPLER_DIM_GENERIC and HLSL_SAMPLER_DIM_COMPARISON. * If base_type is HLSL_TYPE_UAV, then sampler_dim must be one of HLSL_SAMPLER_DIM_1D, * HLSL_SAMPLER_DIM_2D, HLSL_SAMPLER_DIM_3D, HLSL_SAMPLER_DIM_1DARRAY, HLSL_SAMPLER_DIM_2DARRAY, * HLSL_SAMPLER_DIM_BUFFER, or HLSL_SAMPLER_DIM_STRUCTURED_BUFFER. @@ -1147,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); @@ -1252,6 +1258,7 @@ bool hlsl_new_store_component(struct hlsl_ctx *ctx, struct hlsl_block *block, bool hlsl_index_is_noncontiguous(struct hlsl_ir_index *index); bool hlsl_index_is_resource_access(struct hlsl_ir_index *index); +bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index); struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); @@ -1315,6 +1322,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/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index 37a372893df..000e14b6de9 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -1915,7 +1915,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo } } - if (lhs->type == HLSL_IR_INDEX && hlsl_index_is_resource_access(hlsl_ir_index(lhs))) + if (lhs->type == HLSL_IR_INDEX && hlsl_index_chain_has_resource_access(hlsl_ir_index(lhs))) { struct hlsl_ir_node *coords = hlsl_ir_index(lhs)->idx.node; struct hlsl_deref resource_deref; @@ -1923,6 +1923,12 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo struct hlsl_ir_node *store; unsigned int dim_count; + if (!hlsl_index_is_resource_access(hlsl_ir_index(lhs))) + { + hlsl_fixme(ctx, &lhs->loc, "Non-direct structured resource store."); + return NULL; + } + if (!hlsl_init_deref_from_index_chain(ctx, &resource_deref, hlsl_ir_index(lhs)->val.node)) return NULL; @@ -4229,6 +4235,7 @@ static unsigned int hlsl_offset_dim_count(enum hlsl_sampler_dim dim) return 3; case HLSL_SAMPLER_DIM_CUBE: case HLSL_SAMPLER_DIM_CUBEARRAY: + case HLSL_SAMPLER_DIM_BUFFER: /* Offset parameters not supported for these types. */ return 0; default: @@ -4252,28 +4259,31 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { const struct hlsl_type *object_type = object->data_type; - const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); - const unsigned int offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); struct hlsl_resource_load_params load_params = {.type = HLSL_RESOURCE_LOAD}; + unsigned int sampler_dim, offset_dim; struct hlsl_ir_node *load; bool multisampled; - if (object_type->sampler_dim == HLSL_SAMPLER_DIM_CUBE - || object_type->sampler_dim == HLSL_SAMPLER_DIM_CUBEARRAY) + if (object_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) { - return raise_invalid_method_object_type(ctx, object_type, name, loc); + hlsl_fixme(ctx, loc, "Method '%s' for structured buffers.", name); + return false; } + sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); + multisampled = object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY; - if (params->args_count < 1 + multisampled || params->args_count > 3 + multisampled) + if (params->args_count < 1 + multisampled || params->args_count > 2 + multisampled + !!offset_dim) { hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, "Wrong number of arguments to method 'Load': expected between %u and %u, but got %u.", - 1 + multisampled, 3 + multisampled, params->args_count); + 1 + multisampled, 2 + multisampled + !!offset_dim, params->args_count); return false; } + if (multisampled) { if (!(load_params.sample_index = add_implicit_conversion(ctx, block, params->args[1], @@ -4281,14 +4291,14 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, return false; } - assert(offset_dim); - if (params->args_count > 1 + multisampled) + if (!!offset_dim && params->args_count > 1 + multisampled) { if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[1 + multisampled], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } - if (params->args_count > 2 + multisampled) + + if (params->args_count > 1 + multisampled + !!offset_dim) { hlsl_fixme(ctx, loc, "Tiled resource status argument."); } @@ -4311,17 +4321,13 @@ static bool add_sample_method_call(struct hlsl_ctx *ctx, struct hlsl_block *bloc const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { const struct hlsl_type *object_type = object->data_type; - const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); - const unsigned int offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); struct hlsl_resource_load_params load_params = {.type = HLSL_RESOURCE_SAMPLE}; + unsigned int sampler_dim, offset_dim; const struct hlsl_type *sampler_type; struct hlsl_ir_node *load; - if (object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS - || object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY) - { - return raise_invalid_method_object_type(ctx, object_type, name, loc); - } + sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); if (params->args_count < 2 || params->args_count > 4 + !!offset_dim) { @@ -4375,17 +4381,13 @@ static bool add_sample_cmp_method_call(struct hlsl_ctx *ctx, struct hlsl_block * const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { const struct hlsl_type *object_type = object->data_type; - const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); - const unsigned int offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); struct hlsl_resource_load_params load_params = { 0 }; + unsigned int sampler_dim, offset_dim; const struct hlsl_type *sampler_type; struct hlsl_ir_node *load; - if (object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS - || object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY) - { - return raise_invalid_method_object_type(ctx, object_type, name, loc); - } + sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); if (!strcmp(name, "SampleCmpLevelZero")) load_params.type = HLSL_RESOURCE_SAMPLE_CMP_LZ; @@ -4449,20 +4451,14 @@ static bool add_gather_method_call(struct hlsl_ctx *ctx, struct hlsl_block *bloc const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { const struct hlsl_type *object_type = object->data_type; - const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); - const unsigned int offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); struct hlsl_resource_load_params load_params = {0}; + unsigned int sampler_dim, offset_dim; const struct hlsl_type *sampler_type; struct hlsl_ir_node *load; unsigned int read_channel; - if (object_type->sampler_dim != HLSL_SAMPLER_DIM_2D - && object_type->sampler_dim != HLSL_SAMPLER_DIM_2DARRAY - && object_type->sampler_dim != HLSL_SAMPLER_DIM_CUBE - && object_type->sampler_dim != HLSL_SAMPLER_DIM_CUBEARRAY) - { - return raise_invalid_method_object_type(ctx, object_type, name, loc); - } + sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); if (!strcmp(name, "GatherGreen")) { @@ -4613,12 +4609,14 @@ static bool add_getdimensions_method_call(struct hlsl_ctx *ctx, struct hlsl_bloc { HLSL_SAMPLER_DIM_CUBEARRAY, 5, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT, ARG_LEVEL_COUNT } }, { HLSL_SAMPLER_DIM_2DMS, 3, { ARG_WIDTH, ARG_HEIGHT, ARG_SAMPLE_COUNT } }, { HLSL_SAMPLER_DIM_2DMSARRAY, 4, { ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT, ARG_SAMPLE_COUNT } }, + { HLSL_SAMPLER_DIM_BUFFER, 1, { ARG_WIDTH} }, }; const struct overload *o = NULL; - if (object_type->sampler_dim > HLSL_SAMPLER_DIM_LAST_TEXTURE) + if (object_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) { - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "GetDimensions() is not defined for this type."); + hlsl_fixme(ctx, loc, "Method '%s' for structured buffers.", name); + return false; } uint_type = hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT); @@ -4732,16 +4730,12 @@ static bool add_sample_lod_method_call(struct hlsl_ctx *ctx, struct hlsl_block * { const struct hlsl_type *object_type = object->data_type; struct hlsl_resource_load_params load_params = { 0 }; - const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); - const unsigned int offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); + unsigned int sampler_dim, offset_dim; const struct hlsl_type *sampler_type; struct hlsl_ir_node *load; - if (object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS - || object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY) - { - return raise_invalid_method_object_type(ctx, object_type, name, loc); - } + sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); if (!strcmp(name, "SampleLevel")) load_params.type = HLSL_RESOURCE_SAMPLE_LOD; @@ -4802,16 +4796,12 @@ static bool add_sample_grad_method_call(struct hlsl_ctx *ctx, struct hlsl_block { const struct hlsl_type *object_type = object->data_type; struct hlsl_resource_load_params load_params = { 0 }; - const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); - const unsigned int offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); + unsigned int sampler_dim, offset_dim; const struct hlsl_type *sampler_type; struct hlsl_ir_node *load; - if (object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS - || object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY) - { - return raise_invalid_method_object_type(ctx, object_type, name, loc); - } + sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + offset_dim = hlsl_offset_dim_count(object_type->sampler_dim); load_params.type = HLSL_RESOURCE_SAMPLE_GRAD; @@ -4873,25 +4863,27 @@ static const struct method_function const char *name; bool (*handler)(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc); + bool valid_dims[HLSL_SAMPLER_DIM_MAX + 1]; } object_methods[] = { - { "Gather", add_gather_method_call }, - { "GatherAlpha", add_gather_method_call }, - { "GatherBlue", add_gather_method_call }, - { "GatherGreen", add_gather_method_call }, - { "GatherRed", add_gather_method_call }, + /* g c 1d 2d 3d cube 1darr 2darr 2dms 2dmsarr cubearr buff sbuff*/ + { "Gather", add_gather_method_call, {0,0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}}, + { "GatherAlpha", add_gather_method_call, {0,0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}}, + { "GatherBlue", add_gather_method_call, {0,0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}}, + { "GatherGreen", add_gather_method_call, {0,0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}}, + { "GatherRed", add_gather_method_call, {0,0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}}, - { "GetDimensions", add_getdimensions_method_call }, + { "GetDimensions", add_getdimensions_method_call, {0,0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, - { "Load", add_load_method_call }, + { "Load", add_load_method_call, {0,0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1}}, - { "Sample", add_sample_method_call }, - { "SampleBias", add_sample_lod_method_call }, - { "SampleCmp", add_sample_cmp_method_call }, - { "SampleCmpLevelZero", add_sample_cmp_method_call }, - { "SampleGrad", add_sample_grad_method_call }, - { "SampleLevel", add_sample_lod_method_call }, + { "Sample", add_sample_method_call, {0,0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0}}, + { "SampleBias", add_sample_lod_method_call, {0,0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0}}, + { "SampleCmp", add_sample_cmp_method_call, {0,0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0}}, + { "SampleCmpLevelZero", add_sample_cmp_method_call, {0,0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0}}, + { "SampleGrad", add_sample_grad_method_call, {0,0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0}}, + { "SampleLevel", add_sample_lod_method_call, {0,0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0}}, }; static int object_method_function_name_compare(const void *a, const void *b) @@ -4919,8 +4911,10 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, stru return false; } - if ((method = bsearch(name, object_methods, ARRAY_SIZE(object_methods), - sizeof(*method), object_method_function_name_compare))) + method = bsearch(name, object_methods, ARRAY_SIZE(object_methods), sizeof(*method), + object_method_function_name_compare); + + if (method && method->valid_dims[object_type->sampler_dim]) { return method->handler(ctx, block, object, name, params, loc); } @@ -6037,7 +6031,11 @@ parameter: } texture_type: - KW_TEXTURE1D + KW_BUFFER + { + $$ = HLSL_SAMPLER_DIM_BUFFER; + } + | KW_TEXTURE1D { $$ = HLSL_SAMPLER_DIM_1D; } diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c index 4121fadf333..7da427796e7 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/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,24 +4449,17 @@ 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; -} - -static void allocate_buffers(struct hlsl_ctx *ctx) -{ - struct hlsl_buffer *buffer; struct hlsl_ir_var *var; - uint32_t index = 0; 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->is_param) - var->buffer = ctx->params_buffer; + 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) @@ -4474,19 +4467,27 @@ static void allocate_buffers(struct hlsl_ctx *ctx) 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); + 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) +{ + struct hlsl_buffer *buffer; + struct hlsl_ir_var *var; + uint32_t index = 0; 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); + if (var->is_param) + var->buffer = ctx->params_buffer; } + 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) { diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index f70606e6f22..492e5ec027d 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -2810,6 +2810,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant {"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, + {"sv_primitiveid", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_PRIMITIVE_ID}, {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_IS_FRONT_FACE}, {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_VIEWPORT_ARRAY_INDEX}, @@ -4764,6 +4765,13 @@ static void write_sm4_resinfo(const struct tpf_writer *tpf, const struct hlsl_ir const struct hlsl_ir_node *dst = &load->node; struct sm4_instruction instr; + if (resource->data_type->sampler_dim == HLSL_SAMPLER_DIM_BUFFER + || resource->data_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) + { + hlsl_fixme(tpf->ctx, &load->node.loc, "resinfo for buffers."); + return; + } + assert(dst->data_type->base_type == HLSL_TYPE_UINT || dst->data_type->base_type == HLSL_TYPE_FLOAT); memset(&instr, 0, sizeof(instr)); diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index 1557fb3ea7f..b2f7b17eb73 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -366,9 +366,9 @@ size_t bytecode_align(struct vkd3d_bytecode_buffer *buffer) return aligned_size; } -size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size) +size_t bytecode_put_bytes_unaligned(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size) { - size_t offset = bytecode_align(buffer); + size_t offset = buffer->size; if (buffer->status) return offset; @@ -383,6 +383,12 @@ size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *byte return offset; } +size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size) +{ + bytecode_align(buffer); + return bytecode_put_bytes_unaligned(buffer, bytes, size); +} + size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size) { size_t offset = bytecode_align(buffer); diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index acfd39b7643..910d34a7d13 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1418,6 +1418,7 @@ struct vkd3d_bytecode_buffer /* Align to the next 4-byte offset, and return that offset. */ size_t bytecode_align(struct vkd3d_bytecode_buffer *buffer); size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size); +size_t bytecode_put_bytes_unaligned(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size); size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size); void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value); void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length); -- 2.43.0