-- v2: vkd3d-shader/dxil: Handle multi-row signature elements. vkd3d-shader/dxil: Handle signature element additional tag/value pairs. vkd3d-shader/dxil: Read the DXIL input and output signatures. vkd3d-shader/dxil: Validate the entry point info.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 112 +++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 2 files changed, 105 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 9e591af25..fdcb84013 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -358,6 +358,8 @@ struct sm6_parser struct sm6_symbol *global_symbols; size_t global_symbol_count;
+ const char *entry_point; + struct vkd3d_shader_dst_param *output_params; struct vkd3d_shader_dst_param *input_params;
@@ -2710,6 +2712,11 @@ 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 enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, struct sm6_function *function) { @@ -3135,6 +3142,77 @@ static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const return VKD3D_OK; }
+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_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; + const struct sm6_value *value; + + if (!entry_node || entry_node->operand_count < 2 || !(m = entry_node->operands[0])) + { + 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 (m->type != VKD3D_METADATA_VALUE) + { + WARN("Entry point definition is not a value.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ENTRY_POINT, + "Entry point definition is not a metadata value."); + return VKD3D_ERROR_INVALID_SHADER; + } + + value = m->u.value; + if (!sm6_value_is_function_dcl(value)) + { + WARN("Entry point value is not a function definition.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ENTRY_POINT, + "Entry point metadata value does not contain a function definition."); + return VKD3D_ERROR_INVALID_SHADER; + } + + sm6->entry_point = value->u.function.name; + if (!sm6_metadata_value_is_string(entry_node->operands[1]) + || ascii_strcasecmp(sm6->entry_point, entry_node->operands[1]->u.string_value)) + { + WARN("Entry point function name %s mismatch.\n", sm6->entry_point); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH, + "Entry point function name %s does not match the name in metadata.", sm6->entry_point); + } + + 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 void sm6_metadata_value_destroy(struct sm6_metadata_value *m) { switch (m->type) @@ -3245,6 +3323,15 @@ static const struct vkd3d_shader_parser_ops sm6_parser_ops = .parser_destroy = sm6_parser_destroy, };
+static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6, const char *name) +{ + size_t i; + for (i = 0; i < sm6->function_count; ++i) + if (!ascii_strcasecmp(sm6->functions[i].declaration->u.function.name, name)) + return &sm6->functions[i]; + return NULL; +} + static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t *byte_code, size_t byte_code_size, const char *source_name, struct vkd3d_shader_message_context *message_context) { @@ -3257,6 +3344,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t enum bitcode_block_abbreviation abbr; struct vkd3d_shader_version version; struct dxil_block *block; + struct sm6_function *fn; enum vkd3d_result ret; unsigned int i, j;
@@ -3469,8 +3557,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) { @@ -3494,14 +3582,20 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
sm6->p.shader_desc.ssa_count = sm6->ssa_next_id;
- for (i = 0; i < sm6->function_count; ++i) + if (!(fn = sm6_parser_get_function(sm6, sm6->entry_point))) { - if (!sm6_block_emit_instructions(sm6->functions[i].blocks[0], sm6)) - { - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory emitting shader instructions."); - return VKD3D_ERROR_OUT_OF_MEMORY; - } + WARN("Failed to find entry point %s.\n", sm6->entry_point); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ENTRY_POINT, + "The definition of the entry point function '%s' was not found.", sm6->entry_point); + return VKD3D_ERROR_INVALID_SHADER; + } + + assert(sm6->function_count == 1); + if (!sm6_block_emit_instructions(fn->blocks[0], sm6)) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory emitting shader instructions."); + return VKD3D_ERROR_OUT_OF_MEMORY; }
dxil_block_destroy(&sm6->root_block); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 060647a68..a0140c674 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -177,6 +177,7 @@ 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_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, @@ -184,6 +185,7 @@ enum vkd3d_shader_error VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH = 8305, + VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH = 8306,
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 | 358 ++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 4 + 3 files changed, 360 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 fdcb84013..48fbcaf13 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -154,6 +154,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, @@ -2357,8 +2417,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]; } } @@ -2717,6 +2776,25 @@ 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) { @@ -3142,6 +3220,67 @@ 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 enum vkd3d_shader_minimum_precision minimum_precision_from_dxil_component_type(enum dxil_component_type type) +{ + switch (type) + { + case COMPONENT_TYPE_F16: + return VKD3D_SHADER_MINIMUM_PRECISION_FLOAT_16; + case COMPONENT_TYPE_I16: + return VKD3D_SHADER_MINIMUM_PRECISION_INT_16; + case COMPONENT_TYPE_U16: + return VKD3D_SHADER_MINIMUM_PRECISION_UINT_16; + default: + return VKD3D_SHADER_MINIMUM_PRECISION_NONE; + } +} + +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; @@ -3167,11 +3306,219 @@ static const struct sm6_metadata_value *sm6_parser_find_named_metadata(struct sm 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]); + e->min_precision = minimum_precision_from_dxil_component_type(values[2]); + + 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; + } + + 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; const struct sm6_value *value; + enum vkd3d_result ret;
if (!entry_node || entry_node->operand_count < 2 || !(m = entry_node->operands[0])) { @@ -3207,8 +3554,11 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) "Entry point function name %s does not match the name in metadata.", sm6->entry_point); }
- sm6_parser_init_input_signature(sm6, &sm6->p.shader_desc.input_signature); - sm6_parser_init_output_signature(sm6, &sm6->p.shader_desc.output_signature); + if (entry_node->operand_count >= 3 && (m = entry_node->operands[2]) + && (ret = sm6_parser_signatures_init(sm6, m)) < 0) + { + return ret; + }
return VKD3D_OK; } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index a0140c674..b5171ba66 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -178,6 +178,7 @@ enum vkd3d_shader_error 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, @@ -627,6 +628,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 @@ -867,6 +870,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;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 84 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 48fbcaf13..7e3a1257b 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -214,6 +214,14 @@ enum dxil_semantic_kind SEMANTIC_KIND_INVALID = SEMANTIC_KIND_COUNT, };
+enum dxil_element_additional_tag +{ + ADDITIONAL_TAG_STREAM_INDEX = 0, + ADDITIONAL_TAG_GLOBAL_SYMBOL = 1, /* not used */ + ADDITIONAL_TAG_RELADDR_MASK = 2, + ADDITIONAL_TAG_USED_MASK = 3, +}; + enum dx_intrinsic_opcode { DX_LOAD_INPUT = 4, @@ -3306,6 +3314,76 @@ static const struct sm6_metadata_value *sm6_parser_find_named_metadata(struct sm return NULL; }
+static void signature_element_read_additional_element_values(struct signature_element *e, + const struct sm6_metadata_node *node, struct sm6_parser *sm6) +{ + unsigned int i, operand_count, value; + enum dxil_element_additional_tag tag; + + if (node->operand_count < 11 || !node->operands[10]) + return; + + if (!sm6_metadata_value_is_node(node->operands[10])) + { + WARN("Additional values list is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element additional values list is not a metadata node."); + return; + } + + node = node->operands[10]->u.node; + 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 signature element additional 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 extract tag/value pair.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element tag/value pair at index %u is not an integer pair.", i); + continue; + } + + switch (tag) + { + case ADDITIONAL_TAG_STREAM_INDEX: + e->stream_index = value; + break; + case ADDITIONAL_TAG_RELADDR_MASK: + /* A mask of components accessed via relative addressing. Seems to replace TPF 'dcl_index_range'. */ + if (value > VKD3DSP_WRITEMASK_ALL) + { + WARN("Invalid relative addressed mask %#x.\n", value); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MASK, + "Mask %#x of relative-addressed components is invalid.", value); + } + break; + case ADDITIONAL_TAG_USED_MASK: + if (value > VKD3DSP_WRITEMASK_ALL) + { + WARN("Invalid used mask %#x.\n", value); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MASK, + "Mask %#x of used components is invalid.", value); + value &= VKD3DSP_WRITEMASK_ALL; + } + e->used_mask = value; + break; + default: + FIXME("Unhandled tag %u, value %u.\n", tag, value); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Tag %#x for signature element additional value %#x is unhandled.", tag, value); + break; + } + } +} + static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const struct sm6_metadata_value *m, struct shader_signature *s) { @@ -3396,9 +3474,6 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const } 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]); e->min_precision = minimum_precision_from_dxil_component_type(values[2]);
@@ -3442,9 +3517,10 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const }
e->mask = vkd3d_write_mask_from_component_count(column_count) << index; - /* TODO: load from additional tag/value pairs. */ e->used_mask = e->mask;
+ signature_element_read_additional_element_values(e, element_node, sm6); + m = element_node->operands[4]; if (!sm6_metadata_value_is_node(m)) { diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index b5171ba66..2c84cb104 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -187,6 +187,7 @@ enum vkd3d_shader_error VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH = 8305, VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH = 8306, + VKD3D_SHADER_WARNING_DXIL_INVALID_MASK = 8307,
VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER = 9001,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 15 ++++++++++++--- tests/hlsl/entry-point-semantics.shader_test | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 7e3a1257b..47b261949 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2384,7 +2384,7 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade { struct vkd3d_shader_dst_param *param; const struct signature_element *e; - unsigned int i; + unsigned int i, count;
for (i = 0; i < s->element_count; ++i) { @@ -2392,8 +2392,11 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade
param = ¶ms[i]; dst_param_io_init(param, e, reg_type); - param->reg.idx[0].offset = i; - param->reg.idx_count = 1; + count = 0; + if (e->register_count > 1) + param->reg.idx[count++].offset = 0; + param->reg.idx[count++].offset = i; + param->reg.idx_count = count; } }
@@ -2427,6 +2430,12 @@ static void sm6_parser_emit_signature(struct sm6_parser *sm6, const struct shade
ins->flags = e->interpolation_mode; *param = params[i]; + + if (e->register_count > 1) + { + param->reg.idx[0].rel_addr = NULL; + param->reg.idx[0].offset = e->register_count; + } } }
diff --git a/tests/hlsl/entry-point-semantics.shader_test b/tests/hlsl/entry-point-semantics.shader_test index 6d355ab5c..d177b0376 100644 --- a/tests/hlsl/entry-point-semantics.shader_test +++ b/tests/hlsl/entry-point-semantics.shader_test @@ -84,7 +84,7 @@ float4 main(in apple a) : sv_target
[test] draw quad -todo(sm>=6) probe (0, 0) rgba (10.0, 20.0, 30.0, 40.0) +probe (0, 0) rgba (10.0, 20.0, 30.0, 40.0)
% Arrays of matrices get successive indexes. @@ -101,7 +101,12 @@ float4 main(in apple a) : sv_target
[test] draw quad -todo(sm>=6) probe (0, 0) rgba (10.0, 11.0, 30.0, 31.0) +probe (0, 0) rgba (10.0, 11.0, 30.0, 31.0) + + +% dxcompiler emits correct array addressing. +[require] +shader model < 6.0
% Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct @@ -145,6 +150,10 @@ draw quad todo(sm>=6) probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0)
+[require] +% reset requirements + + [pixel shader fail] struct apple { @@ -201,7 +210,7 @@ float4 main(in float4 tex0 : TEXCOORD0, in float4 tex1 : TEXCOORD1) : sv_target
[test] draw quad -todo(sm>=6) probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0) +probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0)
% Output semantics cannot be mapped to more than one value. @@ -272,7 +281,7 @@ float4 main(in float4 a : TEXCOORD0, in float3 b : TEXCOORD1) : sv_target
[test] draw quad -todo(sm>=6) probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0) +probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0)
% In SM4, duplicated input semantics can only have different types if they have the same layout and
This merge request was approved by Giovanni Mascellani.
This merge request was approved by Henri Verbeet.