From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 3 +- libs/vkd3d-shader/dxil.c | 96 +++++++++++++++++++++++- libs/vkd3d-shader/spirv.c | 11 ++- libs/vkd3d-shader/tpf.c | 4 +- libs/vkd3d-shader/vkd3d_shader_main.c | 8 +- libs/vkd3d-shader/vkd3d_shader_private.h | 7 +- 6 files changed, 115 insertions(+), 14 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 6a3513a28..3c38ceaec 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -1647,7 +1647,8 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
case VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER: vkd3d_string_buffer_printf(buffer, " {\n"); - for (i = 0; i < ins->declaration.icb->vec4_count; ++i) + assert(ins->declaration.icb->component_count == VKD3D_VEC4_SIZE); + for (i = 0; i < ins->declaration.icb->element_count; ++i) { shader_print_hex_literal(compiler, " {", ins->declaration.icb->data[4 * i + 0], ""); shader_print_hex_literal(compiler, ", ", ins->declaration.icb->data[4 * i + 1], ""); diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index bb50ad62b..e85cb8cbe 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -1324,6 +1324,11 @@ static bool sm6_type_is_numeric_aggregate(const struct sm6_type *type) } }
+static bool sm6_type_is_array(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_ARRAY; +} + static inline bool sm6_type_is_struct(const struct sm6_type *type) { return type->class == TYPE_CLASS_STRUCT; @@ -1916,12 +1921,80 @@ static inline double bitcast_uint64_to_double(uint64_t value) return u.double_value; }
+static enum vkd3d_result register_allocate_constant_array(struct vkd3d_shader_register *reg, const struct sm6_type *type, + const uint64_t *operands, struct sm6_parser *sm6) +{ + struct vkd3d_shader_immediate_constant_buffer *icb; + const struct sm6_type *elem_type; + unsigned int i, size, count; + + elem_type = type->u.array.elem_type; + /* Multidimensional arrays are emitted in flattened form. */ + if (elem_type->class != TYPE_CLASS_INTEGER && elem_type->class != TYPE_CLASS_FLOAT) + { + FIXME("Unhandled element type %u for data array.\n", elem_type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The element data type for an immediate constant buffer is not scalar integer or floating point."); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* Arrays of bool are not used in DXIL. dxc will emit an array of int32 instead if necessary. */ + if (!(size = elem_type->u.width / 8u)) + { + WARN("Invalid data type width %u.\n", elem_type->u.width); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "An immediate constant buffer is declared with boolean elements."); + return VKD3D_ERROR_INVALID_SHADER; + } + size = max(size, sizeof(icb->data[0])); + count = type->u.array.count * size / sizeof(icb->data[0]); + + if (!(icb = vkd3d_malloc(offsetof(struct vkd3d_shader_immediate_constant_buffer, data[count])))) + { + ERR("Failed to allocate buffer, count %u.\n", count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating an immediate constant buffer of count %u.", count); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + if ((reg->idx[0].offset = shader_instruction_array_add_icb(&sm6->p.instructions, icb)) == UINT_MAX) + { + ERR("Failed to store icb object.\n"); + vkd3d_free(icb); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory storing an immediate constant buffer object."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + reg->type = VKD3DSPR_IMMCONSTBUFFER; + reg->idx_count = 1; + + icb->data_type = vkd3d_data_type_from_sm6_type(elem_type); + icb->element_count = type->u.array.count; + icb->component_count = 1; + + count = type->u.array.count; + if (size > sizeof(icb->data[0])) + { + uint64_t *data = (uint64_t *)icb->data; + for (i = 0; i < count; ++i) + data[i] = operands[i]; + } + else + { + for (i = 0; i < count; ++i) + icb->data[i] = operands[i]; + } + + return VKD3D_OK; +} + static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) { enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; const struct sm6_type *type, *elem_type; enum vkd3d_data_type reg_data_type; const struct dxil_record *record; + enum vkd3d_result ret; struct sm6_value *dst; size_t i, value_idx; uint64_t value; @@ -1974,7 +2047,14 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const switch (record->code) { case CST_CODE_NULL: - /* Register constant data is already zero-filled. */ + if (sm6_type_is_array(type)) + { + FIXME("Constant null arrays are not supported.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constant null arrays are not supported."); + return VKD3D_ERROR_INVALID_SHADER; + } + /* For non-aggregates, register constant data is already zero-filled. */ break;
case CST_CODE_INTEGER: @@ -2017,7 +2097,19 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const break;
case CST_CODE_DATA: - WARN("Unhandled constant array.\n"); + if (!sm6_type_is_array(type)) + { + WARN("Invalid type %u for data constant idx %zu.\n", type->class, value_idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The type of a constant array is not an array type."); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!dxil_record_validate_operand_count(record, type->u.array.count, type->u.array.count, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + if ((ret = register_allocate_constant_array(&dst->u.reg, type, record->operands, sm6)) < 0) + return ret; + break;
case CST_CODE_UNDEF: diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 07e276c57..fe1a5997e 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5678,15 +5678,18 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi struct vkd3d_symbol reg_symbol; unsigned int i;
- if (!(elements = vkd3d_calloc(icb->vec4_count, sizeof(*elements)))) + assert(icb->data_type == VKD3D_DATA_FLOAT); + assert(icb->component_count == VKD3D_VEC4_SIZE); + + if (!(elements = vkd3d_calloc(icb->element_count, sizeof(*elements)))) return; - for (i = 0; i < icb->vec4_count; ++i) + for (i = 0; i < icb->element_count; ++i) elements[i] = spirv_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &icb->data[4 * i]); type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE); - length_id = spirv_compiler_get_constant_uint(compiler, icb->vec4_count); + length_id = spirv_compiler_get_constant_uint(compiler, icb->element_count); type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); - const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, icb->vec4_count); + const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, icb->element_count); ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id); icb_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, ptr_type_id, SpvStorageClassPrivate, const_id); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 63771736e..263e91e99 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -781,7 +781,9 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui ins->handler_idx = VKD3DSIH_INVALID; return; } - icb->vec4_count = icb_size / 4; + icb->data_type = VKD3D_DATA_FLOAT; + icb->component_count = VKD3D_VEC4_SIZE; + icb->element_count = icb_size / VKD3D_VEC4_SIZE; memcpy(icb->data, tokens, sizeof(*tokens) * icb_size); shader_instruction_array_add_icb(&priv->p.instructions, icb); ins->declaration.icb = icb; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index a427d996b..13922424a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1837,14 +1837,14 @@ bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *ins return true; }
-bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, +unsigned int shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_immediate_constant_buffer *icb) { if (!vkd3d_array_reserve((void **)&instructions->icbs, &instructions->icb_capacity, instructions->icb_count + 1, sizeof(*instructions->icbs))) - return false; - instructions->icbs[instructions->icb_count++] = icb; - return true; + return UINT_MAX; + instructions->icbs[instructions->icb_count] = icb; + return instructions->icb_count++; }
static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index af75ef3bd..01d5c5cb2 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -715,7 +715,10 @@ struct vkd3d_shader_version
struct vkd3d_shader_immediate_constant_buffer { - unsigned int vec4_count; + enum vkd3d_data_type data_type; + /* total count is element_count * component_count */ + unsigned int element_count; + unsigned int component_count; uint32_t data[]; };
@@ -1101,7 +1104,7 @@ struct vkd3d_shader_instruction_array
bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve); bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve); -bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, +unsigned int shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_immediate_constant_buffer *icb); bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, unsigned int dst, unsigned int src);