-- v2: vkd3d-shader/dxil: Read the DXIL input and output signatures. vkd3d-shader/dxil: Read the DXIL metadata tables.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 3 ++- libs/vkd3d-shader/spirv.c | 11 +++++++---- libs/vkd3d-shader/tpf.c | 4 +++- libs/vkd3d-shader/vkd3d_shader_private.h | 5 ++++- 4 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 4582b22a7..9b3769e00 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -1646,7 +1646,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/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 6a9438b98..dec8189da 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -767,7 +767,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_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index af75ef3bd..ce2480372 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[]; };
From: Conor McCarthy cmccarthy@codeweavers.com
Null buffers are used as initialisers in DXIL shaders. --- libs/vkd3d-shader/d3d_asm.c | 1 + libs/vkd3d-shader/spirv.c | 1 + libs/vkd3d-shader/tpf.c | 1 + libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 4 files changed, 4 insertions(+)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 9b3769e00..3c4273b4e 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -1647,6 +1647,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, case VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER: vkd3d_string_buffer_printf(buffer, " {\n"); assert(ins->declaration.icb->component_count == VKD3D_VEC4_SIZE); + assert(!ins->declaration.icb->is_null); for (i = 0; i < ins->declaration.icb->element_count; ++i) { shader_print_hex_literal(compiler, " {", ins->declaration.icb->data[4 * i + 0], ""); diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index fe1a5997e..b9f6067c2 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5680,6 +5680,7 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi
assert(icb->data_type == VKD3D_DATA_FLOAT); assert(icb->component_count == VKD3D_VEC4_SIZE); + assert(!icb->is_null);
if (!(elements = vkd3d_calloc(icb->element_count, sizeof(*elements)))) return; diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index dec8189da..c5354777f 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -770,6 +770,7 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui icb->data_type = VKD3D_DATA_FLOAT; icb->component_count = VKD3D_VEC4_SIZE; icb->element_count = icb_size / VKD3D_VEC4_SIZE; + icb->is_null = false; 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_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index ce2480372..7714785b4 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -719,6 +719,7 @@ struct vkd3d_shader_immediate_constant_buffer /* total count is element_count * component_count */ unsigned int element_count; unsigned int component_count; + bool is_null; uint32_t data[]; };
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 93 +++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_main.c | 8 +- libs/vkd3d-shader/vkd3d_shader_private.h | 2 +- 3 files changed, 97 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index bb50ad62b..066af7d11 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,84 @@ 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 = operands ? type->u.array.count * size / sizeof(icb->data[0]) : 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 cache icb object.\n"); + vkd3d_free(icb); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory caching 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; + icb->is_null = !operands; + + if (!operands) + return VKD3D_OK; + + 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; @@ -1975,6 +2052,8 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const { case CST_CODE_NULL: /* Register constant data is already zero-filled. */ + if (sm6_type_is_array(type)) + register_allocate_constant_array(&dst->u.reg, type, NULL, sm6); break;
case CST_CODE_INTEGER: @@ -2017,7 +2096,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/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 7714785b4..c233cd32a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1105,7 +1105,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);
From: Conor McCarthy cmccarthy@codeweavers.com
These are needed for reading metadata. --- libs/vkd3d-shader/dxil.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 066af7d11..62fddab2b 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2155,6 +2155,7 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) { const struct dxil_block *block = &sm6->root_block; const struct dxil_record *record; + enum vkd3d_result ret; uint64_t version; size_t i;
@@ -2197,6 +2198,13 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) } }
+ for (i = 0; i < block->child_block_count; ++i) + { + if (block->child_blocks[i]->id == CONSTANTS_BLOCK && (ret = sm6_parser_constants_init(sm6, + block->child_blocks[i])) < 0) + return ret; + } + return VKD3D_OK; }
@@ -2769,6 +2777,8 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st switch (block->id) { case CONSTANTS_BLOCK: + if (level < 2) + break; function = &sm6->functions[sm6->function_count]; sm6->cur_max_value = function->value_count; return sm6_parser_constants_init(sm6, block);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 62fddab2b..1ae4c31ac 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -973,14 +973,18 @@ static const struct dxil_block *sm6_parser_get_level_one_block(const struct sm6_ return found; }
-static char *dxil_record_to_string(const struct dxil_record *record, unsigned int offset) +static char *dxil_record_to_string(const struct dxil_record *record, unsigned int offset, struct sm6_parser *sm6) { unsigned int i; char *str;
assert(offset <= record->operand_count); if (!(str = vkd3d_calloc(record->operand_count - offset + 1, 1))) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating a string of length %u.", record->operand_count - offset); return NULL; + }
for (i = offset; i < record->operand_count; ++i) str[i - offset] = record->operands[i]; @@ -1235,7 +1239,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) break;
case TYPE_CODE_STRUCT_NAME: - if (!(struct_name = dxil_record_to_string(record, 0))) + if (!(struct_name = dxil_record_to_string(record, 0, sm6))) { ERR("Failed to allocate struct name.\n"); return VKD3D_ERROR_OUT_OF_MEMORY; @@ -1459,7 +1463,7 @@ static enum vkd3d_result sm6_parser_symtab_init(struct sm6_parser *sm6)
symbol = &sm6->global_symbols[sm6->global_symbol_count]; symbol->id = record->operands[0]; - if (!(symbol->name = dxil_record_to_string(record, 1))) + if (!(symbol->name = dxil_record_to_string(record, 1, sm6))) { ERR("Failed to allocate symbol name.\n"); return VKD3D_ERROR_OUT_OF_MEMORY;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 379 ++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 2 files changed, 380 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 1ae4c31ac..051bf19ad 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -20,6 +20,7 @@
#define VKD3D_SM6_VERSION_MAJOR(version) (((version) >> 4) & 0xf) #define VKD3D_SM6_VERSION_MINOR(version) (((version) >> 0) & 0xf) +#define VKD3D_SM6_MAX_METADATA_TABLES 4
#define BITCODE_MAGIC VKD3D_MAKE_TAG('B', 'C', 0xc0, 0xde) #define DXIL_OP_MAX_OPERANDS 17 @@ -114,6 +115,19 @@ enum bitcode_function_code FUNC_CODE_INST_CMPXCHG = 46, };
+enum bitcode_metadata_code +{ + METADATA_STRING = 1, + METADATA_VALUE = 2, + METADATA_NODE = 3, + METADATA_NAME = 4, + METADATA_DISTINCT_NODE = 5, + METADATA_KIND = 6, + METADATA_LOCATION = 7, + METADATA_NAMED_NODE = 10, + METADATA_ATTACHMENT = 11, +}; + enum bitcode_type_code { TYPE_CODE_NUMENTRY = 1, @@ -278,6 +292,46 @@ struct dxil_block size_t record_count; };
+enum sm6_metadata_type +{ + VKD3D_METADATA_KIND, + VKD3D_METADATA_NODE, + VKD3D_METADATA_STRING, + VKD3D_METADATA_VALUE, +}; + +struct sm6_metadata_node +{ + bool is_distinct; + unsigned int operand_count; + struct sm6_metadata_value *operands[]; +}; + +struct sm6_metadata_kind +{ + uint64_t id; + char *name; +}; + +struct sm6_metadata_value +{ + enum sm6_metadata_type type; + const struct sm6_type *value_type; + union + { + char *string_value; + const struct sm6_value *value; + struct sm6_metadata_node *node; + struct sm6_metadata_kind kind; + } u; +}; + +struct sm6_named_metadata +{ + char *name; + struct sm6_metadata_value value; +}; + struct sm6_parser { const uint32_t *ptr, *start, *end; @@ -292,6 +346,7 @@ struct sm6_parser
struct sm6_type *types; size_t type_count; + struct sm6_type *metadata_type;
struct sm6_symbol *global_symbols; size_t global_symbol_count; @@ -302,6 +357,11 @@ struct sm6_parser struct sm6_function *functions; size_t function_count;
+ struct sm6_metadata_value *metadata_tables[VKD3D_SM6_MAX_METADATA_TABLES]; + unsigned int metadata_counts[VKD3D_SM6_MAX_METADATA_TABLES]; + struct sm6_named_metadata *named_metadata; + unsigned int named_metadata_count; + struct sm6_value *values; size_t value_count; size_t value_capacity; @@ -1173,6 +1233,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6)
case TYPE_CODE_METADATA: type->class = TYPE_CLASS_METADATA; + sm6->metadata_type = type; break;
case TYPE_CODE_NUMENTRY: @@ -1552,6 +1613,11 @@ static inline bool sm6_value_is_undef(const struct sm6_value *value) return sm6_value_is_register(value) && value->u.reg.type == VKD3DSPR_UNDEF; }
+static bool sm6_value_is_icb(const struct sm6_value *value) +{ + return sm6_value_is_register(value) && value->u.reg.type == VKD3DSPR_IMMCONSTBUFFER; +} + static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *value) { if (!sm6_value_is_constant(value)) @@ -1782,6 +1848,17 @@ static size_t sm6_parser_get_value_index(struct sm6_parser *sm6, uint64_t idx) return i; }
+static const struct sm6_value *sm6_parser_get_value_unsafe(struct sm6_parser *sm6, unsigned int idx) +{ + if (idx < sm6->value_count) + return &sm6->values[idx]; + + WARN("Invalid value index %u.\n", idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value index %u.", idx); + return NULL; +} + static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const struct dxil_record *record, const struct sm6_type *fwd_type, unsigned int *rec_idx) { @@ -2621,6 +2698,11 @@ static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record ins->handler_idx = VKD3DSIH_NOP; }
+static bool sm6_metadata_value_is_node(const struct sm6_metadata_value *m) +{ + return m && m->type == VKD3D_METADATA_NODE; +} + static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, struct sm6_function *function) { @@ -2816,6 +2898,276 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st return VKD3D_OK; }
+static bool sm6_parser_allocate_named_metadata(struct sm6_parser *sm6) +{ + struct dxil_block *block; + unsigned int i, j, count; + + for (i = 0, count = 0; i < sm6->root_block.child_block_count; ++i) + { + block = sm6->root_block.child_blocks[i]; + if (block->id != METADATA_BLOCK) + continue; + for (j = 0; j < block->record_count; ++j) + count += block->records[j]->code == METADATA_NAMED_NODE; + } + + if (!count) + return true; + + return !!(sm6->named_metadata = vkd3d_calloc(count, sizeof(*sm6->named_metadata))); +} + +static enum vkd3d_result metadata_value_create_node(struct sm6_metadata_value *m, struct sm6_metadata_value *table, + unsigned int table_idx, unsigned int count, const struct dxil_record *record, struct sm6_parser *sm6) +{ + struct sm6_metadata_node *node; + unsigned int i, offset; + + m->type = VKD3D_METADATA_NODE; + if (!(m->value_type = sm6->metadata_type)) + { + WARN("Metadata type not found.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "The type for metadata values was not found."); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!(node = vkd3d_malloc(offsetof(struct sm6_metadata_node, operands[record->operand_count])))) + { + ERR("Failed to allocate metadata node with %u operands.\n", record->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating a metadata node with %u operands.", record->operand_count); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + m->u.node = node; + + node->is_distinct = record->code == METADATA_DISTINCT_NODE; + + offset = record->code != METADATA_NAMED_NODE; + + for (i = 0; i < record->operand_count; ++i) + { + uint64_t ref; + + ref = record->operands[i] - offset; + if (record->operands[i] >= offset && ref >= count) + { + WARN("Invalid metadata index %"PRIu64".\n", ref); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "Metadata index %"PRIu64" is invalid.", ref); + vkd3d_free(node); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!node->is_distinct && ref == table_idx) + { + WARN("Metadata self-reference at index %u.\n", table_idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "Metadata index %u is self-referencing.", table_idx); + vkd3d_free(node); + return VKD3D_ERROR_INVALID_SHADER; + } + + node->operands[i] = (record->operands[i] >= offset) ? &table[ref] : NULL; + if (record->code == METADATA_NAMED_NODE && !sm6_metadata_value_is_node(node->operands[i])) + { + WARN("Named node operand is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "The operand of a metadata named node is not a node."); + vkd3d_free(node); + return VKD3D_ERROR_INVALID_SHADER; + } + } + + node->operand_count = record->operand_count; + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const struct dxil_block *block, + unsigned int idx) +{ + unsigned int i, count, table_idx, value_idx; + struct sm6_metadata_value *table, *m; + const struct dxil_record *record; + const struct sm6_value *value; + enum vkd3d_result ret; + char *name; + + for (i = 0, count = 0; i < block->record_count; ++i) + count += block->records[i]->code != METADATA_NAME; + + if (!(table = vkd3d_calloc(count, sizeof(*sm6->metadata_tables[0])))) + { + ERR("Failed to allocate metadata tables.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating metadata tables."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + sm6->metadata_tables[idx] = table; + + for (i = 0, name = NULL; i < block->record_count; ++i) + { + record = block->records[i]; + + table_idx = sm6->metadata_counts[idx]; + m = &table[table_idx]; + + if (name && record->code != METADATA_NAMED_NODE) + { + WARN("Name '%s' is not followed by a named node.\n", name); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "Metadata node name '%s' is not followed by a named node.", name); + vkd3d_free(name); + return VKD3D_ERROR_INVALID_SHADER; + } + + switch (record->code) + { + case METADATA_NAMED_NODE: + if (!name) + { + WARN("Named node has no name.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "A metadata named node has no name."); + return VKD3D_ERROR_INVALID_SHADER; + } + + m = &sm6->named_metadata[sm6->named_metadata_count].value; + sm6->named_metadata[sm6->named_metadata_count].name = name; + name = NULL; + + if ((ret = metadata_value_create_node(m, table, UINT_MAX, count, record, sm6)) < 0) + return ret; + ++sm6->named_metadata_count; + + continue; + + case METADATA_DISTINCT_NODE: + case METADATA_NODE: + if ((ret = metadata_value_create_node(m, table, table_idx, count, record, sm6)) < 0) + return ret; + break; + + case METADATA_KIND: + if (!dxil_record_validate_operand_min_count(record, 2, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + m->type = VKD3D_METADATA_KIND; + m->u.kind.id = record->operands[0]; + if (!(m->u.kind.name = dxil_record_to_string(record, 1, sm6))) + { + ERR("Failed to allocate name of a kind.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + break; + + case METADATA_NAME: + /* LLVM allows an empty string here. */ + if (!(name = dxil_record_to_string(record, 0, sm6))) + { + ERR("Failed to allocate name.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + continue; + + case METADATA_STRING: + /* LLVM allows an empty string here. */ + m->type = VKD3D_METADATA_STRING; + if (!(m->u.string_value = dxil_record_to_string(record, 0, sm6))) + { + ERR("Failed to allocate string.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + break; + + case METADATA_VALUE: + if (!dxil_record_validate_operand_count(record, 2, 2, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + m->type = VKD3D_METADATA_VALUE; + if (!(m->value_type = sm6_parser_get_type(sm6, record->operands[0]))) + return VKD3D_ERROR_INVALID_SHADER; + + if (record->operands[1] > UINT_MAX) + WARN("Truncating value index %"PRIu64".\n", record->operands[1]); + value_idx = record->operands[1]; + if (!(value = sm6_parser_get_value_unsafe(sm6, value_idx))) + return VKD3D_ERROR_INVALID_SHADER; + + if (!sm6_value_is_constant(value) && !sm6_value_is_undef(value) && !sm6_value_is_icb(value) + && !sm6_value_is_function_dcl(value)) + { + WARN("Value at index %u is not a constant or a function declaration.\n", value_idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "Metadata value at index %u is not a constant or a function declaration.", value_idx); + return VKD3D_ERROR_INVALID_SHADER; + } + m->u.value = value; + + if (value->type != m->value_type) + { + WARN("Type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "The type of a metadata value does not match its referenced value at index %u.", value_idx); + } + + break; + + default: + FIXME("Unhandled metadata type %u.\n", record->code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "Metadata type %u is unhandled.", record->code); + return VKD3D_ERROR_INVALID_SHADER; + } + ++sm6->metadata_counts[idx]; + } + + if (name) + { + WARN("Unused metadata name '%s'.\n", name); + vkd3d_free(name); + } + + return VKD3D_OK; +} + +static void sm6_metadata_value_destroy(struct sm6_metadata_value *m) +{ + switch (m->type) + { + case VKD3D_METADATA_NODE: + vkd3d_free(m->u.node); + break; + case VKD3D_METADATA_KIND: + vkd3d_free(m->u.kind.name); + break; + case VKD3D_METADATA_STRING: + vkd3d_free(m->u.string_value); + break; + default: + break; + } +} + +static void sm6_parser_metadata_cleanup(struct sm6_parser *sm6) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(sm6->metadata_tables); ++i) + { + for (j = 0; j < sm6->metadata_counts[i]; ++j) + sm6_metadata_value_destroy(&sm6->metadata_tables[i][j]); + vkd3d_free(sm6->metadata_tables[i]); + } + for (i = 0; i < sm6->named_metadata_count; ++i) + { + sm6_metadata_value_destroy(&sm6->named_metadata[i].value); + vkd3d_free(sm6->named_metadata[i].name); + } + vkd3d_free(sm6->named_metadata); +} + static void sm6_type_table_cleanup(struct sm6_type *types, size_t count) { size_t i; @@ -2879,6 +3231,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) sm6_type_table_cleanup(sm6->types, sm6->type_count); sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); sm6_functions_cleanup(sm6->functions, sm6->function_count); + sm6_parser_metadata_cleanup(sm6); vkd3d_free(sm6->values); free_shader_desc(&parser->shader_desc); vkd3d_free(sm6); @@ -2902,7 +3255,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t struct vkd3d_shader_version version; struct dxil_block *block; enum vkd3d_result ret; - unsigned int i; + unsigned int i, j;
count = byte_code_size / sizeof(*byte_code); if (count < 6) @@ -3089,6 +3442,30 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t return ret; }
+ if (!sm6_parser_allocate_named_metadata(sm6)) + { + ERR("Failed to allocate named metadata array.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0, j = 0; i < sm6->root_block.child_block_count; ++i) + { + block = sm6->root_block.child_blocks[i]; + if (block->id != METADATA_BLOCK) + continue; + + if (j == ARRAY_SIZE(sm6->metadata_tables)) + { + FIXME("Too many metadata tables.\n"); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA, + "A metadata table count greater than %zu is unsupported.", ARRAY_SIZE(sm6->metadata_tables)); + return VKD3D_ERROR_INVALID_SHADER; + } + + if ((ret = sm6_parser_metadata_init(sm6, block, j++)) < 0) + return ret; + } + sm6_parser_init_output_signature(sm6, output_signature); sm6_parser_init_input_signature(sm6, input_signature);
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c233cd32a..79e455ce5 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -176,12 +176,14 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE = 8011, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND = 8012, VKD3D_SHADER_ERROR_DXIL_UNHANDLED_INTRINSIC = 8013, + VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA = 8014,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH = 8302, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304, + VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH = 8305,
VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER = 9001,
From: Conor McCarthy cmccarthy@codeweavers.com
These can differ from the DXBC signatures by having multiple rows, and load/store instructions reference them by id instead of register index. --- libs/vkd3d-shader/dxbc.c | 2 + libs/vkd3d-shader/dxil.c | 410 ++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 5 + 3 files changed, 413 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index dbbf8a5c4..a9a7aefe8 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -435,6 +435,8 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s else e[i].min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE;
+ e[i].interpolation_mode = VKD3DSIM_NONE; + TRACE("Stream: %u, semantic: %s, semantic idx: %u, sysval_semantic %#x, " "type %u, register idx: %u, use_mask %#x, input_mask %#x, precision %u.\n", e[i].stream_index, debugstr_a(e[i].semantic_name), e[i].semantic_index, e[i].sysval_semantic, diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 051bf19ad..ef9d5f4d2 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -153,6 +153,66 @@ enum bitcode_value_symtab_code VST_CODE_BBENTRY = 2, };
+enum dxil_component_type +{ + COMPONENT_TYPE_INVALID = 0, + COMPONENT_TYPE_I1 = 1, + COMPONENT_TYPE_I16 = 2, + COMPONENT_TYPE_U16 = 3, + COMPONENT_TYPE_I32 = 4, + COMPONENT_TYPE_U32 = 5, + COMPONENT_TYPE_I64 = 6, + COMPONENT_TYPE_U64 = 7, + COMPONENT_TYPE_F16 = 8, + COMPONENT_TYPE_F32 = 9, + COMPONENT_TYPE_F64 = 10, + COMPONENT_TYPE_SNORMF16 = 11, + COMPONENT_TYPE_UNORMF16 = 12, + COMPONENT_TYPE_SNORMF32 = 13, + COMPONENT_TYPE_UNORMF32 = 14, + COMPONENT_TYPE_SNORMF64 = 15, + COMPONENT_TYPE_UNORMF64 = 16, + COMPONENT_TYPE_PACKEDS8X32 = 17, + COMPONENT_TYPE_PACKEDU8X32 = 18, +}; + +enum dxil_semantic_kind +{ + SEMANTIC_KIND_ARBITRARY = 0, + SEMANTIC_KIND_VERTEXID = 1, + SEMANTIC_KIND_INSTANCEID = 2, + SEMANTIC_KIND_POSITION = 3, + SEMANTIC_KIND_RTARRAYINDEX = 4, + SEMANTIC_KIND_VIEWPORTARRAYINDEX = 5, + SEMANTIC_KIND_CLIPDISTANCE = 6, + SEMANTIC_KIND_CULLDISTANCE = 7, + SEMANTIC_KIND_OUTPUTCONTROLPOINTID = 8, + SEMANTIC_KIND_DOMAINLOCATION = 9, + SEMANTIC_KIND_PRIMITIVEID = 10, + SEMANTIC_KIND_GSINSTANCEID = 11, + SEMANTIC_KIND_SAMPLEINDEX = 12, + SEMANTIC_KIND_ISFRONTFACE = 13, + SEMANTIC_KIND_COVERAGE = 14, + SEMANTIC_KIND_INNERCOVERAGE = 15, + SEMANTIC_KIND_TARGET = 16, + SEMANTIC_KIND_DEPTH = 17, + SEMANTIC_KIND_DEPTHLESSEQUAL = 18, + SEMANTIC_KIND_DEPTHGREATEREQUAL = 19, + SEMANTIC_KIND_STENCILREF = 20, + SEMANTIC_KIND_DISPATCHTHREADID = 21, + SEMANTIC_KIND_GROUPID = 22, + SEMANTIC_KIND_GROUPINDEX = 23, + SEMANTIC_KIND_GROUPTHREADID = 24, + SEMANTIC_KIND_TESSFACTOR = 25, + SEMANTIC_KIND_INSIDETESSFACTOR = 26, + SEMANTIC_KIND_VIEWID = 27, + SEMANTIC_KIND_BARYCENTRICS = 28, + SEMANTIC_KIND_SHADINGRATE = 29, + SEMANTIC_KIND_CULLPRIMITIVE = 30, + SEMANTIC_KIND_COUNT = 31, + SEMANTIC_KIND_INVALID = SEMANTIC_KIND_COUNT, +}; + enum dx_intrinsic_opcode { DX_LOAD_INPUT = 4, @@ -2348,8 +2408,7 @@ static void sm6_parser_emit_signature(struct sm6_parser *sm6, const struct shade param = &ins->declaration.dst; }
- /* TODO: set the interpolation mode when signatures are loaded from DXIL metadata. */ - ins->flags = (handler_idx == VKD3DSIH_DCL_INPUT_PS) ? VKD3DSIM_LINEAR_NOPERSPECTIVE : 0; + ins->flags = e->interpolation_mode; *param = params[i]; } } @@ -2703,6 +2762,30 @@ static bool sm6_metadata_value_is_node(const struct sm6_metadata_value *m) return m && m->type == VKD3D_METADATA_NODE; }
+static bool sm6_metadata_value_is_string(const struct sm6_metadata_value *m) +{ + return m && m->type == VKD3D_METADATA_STRING; +} + +static bool sm6_metadata_get_uint_value(const struct sm6_parser *sm6, + const struct sm6_metadata_value *m, unsigned int *u) +{ + const struct sm6_value *value; + + if (!m || m->type != VKD3D_METADATA_VALUE) + return false; + + value = m->u.value; + if (!sm6_value_is_constant(value)) + return false; + if (!sm6_type_is_integer(value->type)) + return false; + + *u = register_get_uint_value(&value->u.reg); + + return true; +} + static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, struct sm6_function *function) { @@ -3132,6 +3215,325 @@ static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const return VKD3D_OK; }
+static enum vkd3d_shader_component_type vkd3d_component_type_from_dxil_component_type(enum dxil_component_type type) +{ + switch (type) + { + case COMPONENT_TYPE_I1: + return VKD3D_SHADER_COMPONENT_BOOL; + case COMPONENT_TYPE_I16: + case COMPONENT_TYPE_I32: + return VKD3D_SHADER_COMPONENT_INT; + case COMPONENT_TYPE_U16: + case COMPONENT_TYPE_U32: + return VKD3D_SHADER_COMPONENT_UINT; + case COMPONENT_TYPE_F16: + case COMPONENT_TYPE_F32: + case COMPONENT_TYPE_SNORMF32: + case COMPONENT_TYPE_UNORMF32: + return VKD3D_SHADER_COMPONENT_FLOAT; + case COMPONENT_TYPE_F64: + case COMPONENT_TYPE_SNORMF64: + case COMPONENT_TYPE_UNORMF64: + return VKD3D_SHADER_COMPONENT_DOUBLE; + default: + FIXME("Unhandled component type %u.\n", type); + return VKD3D_SHADER_COMPONENT_UINT; + } +} + +static const enum vkd3d_shader_sysval_semantic sysval_semantic_table[] = +{ + [SEMANTIC_KIND_ARBITRARY] = VKD3D_SHADER_SV_NONE, + [SEMANTIC_KIND_POSITION] = VKD3D_SHADER_SV_POSITION, + [SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_NONE, +}; + +static enum vkd3d_shader_sysval_semantic sysval_semantic_from_dxil_semantic_kind(enum dxil_semantic_kind kind) +{ + if (kind < ARRAY_SIZE(sysval_semantic_table)) + { + return sysval_semantic_table[kind]; + } + else + { + return VKD3D_SHADER_SV_NONE; + } +} + +static const struct sm6_metadata_value *sm6_parser_find_named_metadata(struct sm6_parser *sm6, const char *name) +{ + const struct sm6_metadata_node *node; + unsigned int i; + + for (i = 0; i < sm6->named_metadata_count; ++i) + { + if (strcmp(sm6->named_metadata[i].name, name)) + continue; + + node = sm6->named_metadata[i].value.u.node; + if (!node->operand_count) + return NULL; + if (node->operand_count > 1) + { + FIXME("Ignoring %u extra operands for %s.\n", node->operand_count - 1, name); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for metadata node %s.", node->operand_count - 1, name); + } + return node->operands[0]; + } + + return NULL; +} + +static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const struct sm6_metadata_value *m, + struct shader_signature *s) +{ + unsigned int i, j, column_count, operand_count, index; + const struct sm6_metadata_node *node, *element_node; + struct signature_element *elements, *e; + unsigned int values[10]; + + if (!m) + return VKD3D_OK; + + if (!sm6_metadata_value_is_node(m)) + { + WARN("Signature element list is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element list is not a metadata node."); + return VKD3D_ERROR_INVALID_SHADER; + } + + node = m->u.node; + operand_count = node->operand_count; + + if (!(elements = vkd3d_calloc(operand_count, sizeof(*elements)))) + { + ERR("Failed to allocate %u signature elements.\n", operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating %u signature elements.", operand_count); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < operand_count; ++i) + { + m = node->operands[i]; + + if (!sm6_metadata_value_is_node(m)) + { + WARN("Signature element is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element is not a metadata node."); + return VKD3D_ERROR_INVALID_SHADER; + } + + element_node = m->u.node; + if (element_node->operand_count < 10) + { + WARN("Invalid operand count %u.\n", element_node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Invalid signature element operand count %u.", element_node->operand_count); + return VKD3D_ERROR_INVALID_SHADER; + } + if (element_node->operand_count > 11) + { + WARN("Ignoring %u extra operands.\n", element_node->operand_count - 11); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for a signature element.", element_node->operand_count - 11); + } + + for (j = 0; j < 10; ++j) + { + /* 1 is the semantic name, 4 is semantic index metadata. */ + if (j == 1 || j == 4) + continue; + if (!sm6_metadata_get_uint_value(sm6, element_node->operands[j], &values[j])) + { + WARN("Failed to load uint value at index %u.\n", j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element value at index %u is not an integer.", j); + return VKD3D_ERROR_INVALID_SHADER; + } + } + + e = &elements[i]; + + if (values[0] != i) + { + FIXME("Unsupported element id %u not equal to its index %u.\n", values[0], i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "A non-sequential and non-zero-based element id is not supported."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!sm6_metadata_value_is_string(element_node->operands[1])) + { + WARN("Element name is not a string.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element name is not a metadata string."); + return VKD3D_ERROR_INVALID_SHADER; + } + e->semantic_name = element_node->operands[1]->u.string_value; + + /* TODO: load from additional tag/value pairs. */ + e->stream_index = 0; + + e->component_type = vkd3d_component_type_from_dxil_component_type(values[2]); + switch (values[2]) + { + case COMPONENT_TYPE_F16: + e->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_FLOAT_16; + break; + case COMPONENT_TYPE_I16: + e->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_INT_16; + break; + case COMPONENT_TYPE_U16: + e->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_UINT_16; + break; + default: + e->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE; + break; + } + + j = values[3]; + e->sysval_semantic = sysval_semantic_from_dxil_semantic_kind(j); + if (j != SEMANTIC_KIND_ARBITRARY && j != SEMANTIC_KIND_TARGET && e->sysval_semantic == VKD3D_SHADER_SV_NONE) + { + WARN("Unhandled semantic kind %u.\n", j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "DXIL semantic kind %u is unhandled.", j); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* bool I/O for non-sysvals is invalid in SPIR-V, and DXIL reads/writes uint anyway. */ + if (e->component_type == VKD3D_SHADER_COMPONENT_BOOL && !e->sysval_semantic) + e->component_type = VKD3D_SHADER_COMPONENT_UINT; + + if ((e->interpolation_mode = values[5]) >= VKD3DSIM_COUNT) + { + WARN("Unhandled interpolation mode %u.\n", e->interpolation_mode); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Interpolation mode %u is unhandled.", e->interpolation_mode); + return VKD3D_ERROR_INVALID_SHADER; + } + + e->register_count = values[6]; + column_count = values[7]; + e->register_index = values[8]; + e->target_location = e->register_index; + if (e->register_index > MAX_REG_OUTPUT || e->register_count > MAX_REG_OUTPUT - e->register_index) + { + WARN("Invalid row start %u with row count %u.\n", e->register_index, e->register_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "A signature element starting row of %u with count %u is invalid.", + e->register_index, e->register_count); + return VKD3D_ERROR_INVALID_SHADER; + } + index = values[9]; + if (index >= VKD3D_VEC4_SIZE || column_count > VKD3D_VEC4_SIZE - index) + { + WARN("Invalid column start %u with count %u.\n", index, column_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "A signature element starting column %u with count %u is invalid.", index, column_count); + return VKD3D_ERROR_INVALID_SHADER; + } + + e->mask = vkd3d_write_mask_from_component_count(column_count) << index; + /* TODO: load from additional tag/value pairs. */ + e->used_mask = e->mask; + + m = element_node->operands[4]; + if (!sm6_metadata_value_is_node(m)) + { + WARN("Semantic index list is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element semantic index list is not a metadata node."); + return VKD3D_ERROR_INVALID_SHADER; + } + + element_node = m->u.node; + for (j = 0; j < element_node->operand_count; ++j) + { + if (!sm6_metadata_get_uint_value(sm6, element_node->operands[j], &index)) + { + WARN("Failed to get semantic index for row %u.\n", j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element semantic index for row %u is not an integer.", j); + } + else if (!j) + { + e->semantic_index = index; + } + else if (index != e->semantic_index + j) + { + WARN("Semantic index %u for row %u is not of an incrementing sequence.\n", index, j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element semantic index %u for row %u is not of an incrementing sequence.", index, j); + } + } + } + + vkd3d_free(s->elements); + s->elements = elements; + s->element_count = operand_count; + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, const struct sm6_metadata_value *m) +{ + enum vkd3d_result ret; + + if (!sm6_metadata_value_is_node(m)) + { + WARN("Signature table is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature table is not a metadata node."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (m->u.node->operand_count && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[0], + &sm6->p.shader_desc.input_signature)) < 0) + { + return ret; + } + if (m->u.node->operand_count > 1 && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[1], + &sm6->p.shader_desc.output_signature)) < 0) + { + return ret; + } + /* TODO: patch constant signature in operand 2. */ + + sm6_parser_init_input_signature(sm6, &sm6->p.shader_desc.input_signature); + sm6_parser_init_output_signature(sm6, &sm6->p.shader_desc.output_signature); + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) +{ + const struct sm6_metadata_value *m = sm6_parser_find_named_metadata(sm6, "dx.entryPoints"); + const struct sm6_metadata_node *entry_node = m ? m->u.node : NULL; + enum vkd3d_result ret; + + if (!entry_node || !entry_node->operand_count) + { + WARN("No entry point definition found.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ENTRY_POINT, + "No entry point definition found in the metadata."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (entry_node->operand_count >= 3 && (m = entry_node->operands[2]) + && (ret = sm6_parser_signatures_init(sm6, m)) < 0) + { + return ret; + } + + return VKD3D_OK; +} + static void sm6_metadata_value_destroy(struct sm6_metadata_value *m) { switch (m->type) @@ -3466,8 +3868,8 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t return ret; }
- sm6_parser_init_output_signature(sm6, output_signature); - sm6_parser_init_input_signature(sm6, input_signature); + if ((ret = sm6_parser_entry_point_init(sm6)) < 0) + return ret;
if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0) { diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 79e455ce5..8d99014cc 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -177,6 +177,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND = 8012, VKD3D_SHADER_ERROR_DXIL_UNHANDLED_INTRINSIC = 8013, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA = 8014, + VKD3D_SHADER_ERROR_DXIL_INVALID_ENTRY_POINT = 8015, + VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE = 8016,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, @@ -624,6 +626,8 @@ enum vkd3d_shader_interpolation_mode VKD3DSIM_LINEAR_NOPERSPECTIVE_CENTROID = 5, VKD3DSIM_LINEAR_SAMPLE = 6, VKD3DSIM_LINEAR_NOPERSPECTIVE_SAMPLE = 7, + + VKD3DSIM_COUNT = 8, };
enum vkd3d_shader_global_flags @@ -865,6 +869,7 @@ struct signature_element unsigned int mask; unsigned int used_mask; enum vkd3d_shader_minimum_precision min_precision; + enum vkd3d_shader_interpolation_mode interpolation_mode; /* Register index / location in the target shader. * If SIGNATURE_TARGET_LOCATION_UNUSED, this element should not be written. */ unsigned int target_location;
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
{ case CST_CODE_NULL: /* Register constant data is already zero-filled. */
if (sm6_type_is_array(type))
Maybe there should be a warning if the type is not an array, like in the `CST_CODE_DATA` case?
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
- size = max(size, sizeof(icb->data[0]));
- count = operands ? type->u.array.count * size / sizeof(icb->data[0]) : 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 cache icb object.\n");
vkd3d_free(icb);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory caching an immediate constant buffer object.");
Minor, but is "caching" really the right word here? I would have rather said "storing" or "recording". Or even nothing: out of memory errors appear somewhat randomly, I guess there is little value in knowing what precisely you were doing when available memory happened to finish.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
- 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))
Looking at `vkd3d_data_type_from_sm6_type()` it doesn't look like that any type with width smaller than 8 is possible. I guess that's in view of the eventual support of boolean as `i1` values?
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/spirv.c:
assert(icb->data_type == VKD3D_DATA_FLOAT); assert(icb->component_count == VKD3D_VEC4_SIZE);
- assert(!icb->is_null);
Is this eventually going to be solved? I.e., null ICBs are actually meant to be emitted, or they're just a thing internal to the compiler? If they are meant to be emitted, how hard would it be to do that immediately?
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
} }
- for (i = 0; i < block->child_block_count; ++i)
- {
if (block->child_blocks[i]->id == CONSTANTS_BLOCK && (ret = sm6_parser_constants_init(sm6,
block->child_blocks[i])) < 0)
Could this be splitted like this? ```c if (block->child_blocks[i]->id == CONSTANTS_BLOCK && (ret = sm6_parser_constants_init(sm6, block->child_blocks[i])) < 0) ```
It feels much easier to read to me.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
switch (block->id) { case CONSTANTS_BLOCK:
if (level < 2)
break;
I guess that what's happening here is that global constant blocks were already read as part of `sm6_parser_globals_init()`, so you mustn't do it again. If so, could you please write that in a comment?
Could the last two patches be splitted to be shorter? I haven't read in detail yet, but in `sm6_parser_metadata_init()` it seems that the various cases could be added incrementally. In the following commit I guess `sm6_parser_find_named_metadata()` could initially be a stub and implemented later in a few commits.
On Wed Sep 27 13:41:52 2023 +0000, Giovanni Mascellani wrote:
Maybe there should be a warning if the type is not an array, like in the `CST_CODE_DATA` case?
Scalars can be null too. I've added a comment.
On Wed Sep 27 13:41:53 2023 +0000, Giovanni Mascellani wrote:
Looking at `vkd3d_data_type_from_sm6_type()` it doesn't look like that any type with width smaller than 8 is possible. I guess that's in view of the eventual support of boolean as `i1` values?
Yes it will eventually return `VKD3D_DATA_BOOL` for `i1`.
On Wed Sep 27 13:41:54 2023 +0000, Giovanni Mascellani wrote:
Is this eventually going to be solved? I.e., null ICBs are actually meant to be emitted, or they're just a thing internal to the compiler? If they are meant to be emitted, how hard would it be to do that immediately?
In the backend they will only used as array variable initialisers, which aren't supported yet.
On Wed Sep 27 14:22:38 2023 +0000, Giovanni Mascellani wrote:
Could the last two patches be splitted to be shorter? I haven't read in detail yet, but in `sm6_parser_metadata_init()` it seems that the various cases could be added incrementally. In the following commit I guess `sm6_parser_find_named_metadata()` could initially be a stub and implemented later in a few commits.
Certainly for `sm6_parser_metadata_init()`, but testing each patch would be a problem unless the default case `continue`s, and then we check `failed` on return. Otherwise it may error out on a test shader before the new code is run. I'm not sure if it's worth messing with, but Henri may like to comment.
For the others, maybe it would be better if `sm6_parser_find_named_metadata()` and `sm6_parser_entry_point_init()` were added first, before `sm6_parser_signatures_init()`.