-- v10: vkd3d-shader: Clone descriptor scan info from struct vkd3d_shader_desc. vkd3d-shader/dxil: Read CBV descriptors. vkd3d-shader/dxil: Validate the descriptor list metadata nodes. vkd3d-shader/spirv: Align constant buffer sizes to 16 bytes.
From: Conor McCarthy cmccarthy@codeweavers.com
DXIL constant buffer sizes can be 32-bit scalar aligned. --- libs/vkd3d-shader/spirv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index bd9e7a33..2dab97cc 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5639,7 +5639,8 @@ static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, reg.idx[1].offset = range->first; reg.idx[2].offset = range->last;
- size = size_in_bytes / (VKD3D_VEC4_SIZE * sizeof(uint32_t)); + size = align(size_in_bytes, VKD3D_VEC4_SIZE * sizeof(uint32_t)); + size /= VKD3D_VEC4_SIZE * sizeof(uint32_t);
if ((push_cb = spirv_compiler_find_push_constant_buffer(compiler, range))) {
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 41 ++++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 42 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 06faddac..4bfebea2 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -25,6 +25,7 @@
#define BITCODE_MAGIC VKD3D_MAKE_TAG('B', 'C', 0xc0, 0xde) #define DXIL_OP_MAX_OPERANDS 17 +static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4;
static const unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64};
@@ -3374,6 +3375,43 @@ static const struct sm6_metadata_value *sm6_parser_find_named_metadata(struct sm return NULL; }
+static enum vkd3d_result sm6_parser_resources_init(struct sm6_parser *sm6) +{ + const struct sm6_metadata_value *m = sm6_parser_find_named_metadata(sm6, "dx.resources"); + enum vkd3d_shader_descriptor_type type; + const struct sm6_metadata_node *node; + + if (!m) + return VKD3D_OK; + + node = m->u.node; + if (node->operand_count != SHADER_DESCRIPTOR_TYPE_COUNT) + { + WARN("Unexpected descriptor type count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Descriptor type count %u is invalid.", node->operand_count); + return VKD3D_ERROR_INVALID_SHADER; + } + + for (type = 0; type < SHADER_DESCRIPTOR_TYPE_COUNT; ++type) + { + if (!(m = node->operands[type])) + continue; + + if (!sm6_metadata_value_is_node(m)) + { + WARN("Resource list is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource list is not a metadata node."); + return VKD3D_ERROR_INVALID_SHADER; + } + + FIXME("Descriptor info is unhandled.\n"); + } + + return VKD3D_OK; +} + static void signature_element_read_additional_element_values(struct signature_element *e, const struct sm6_metadata_node *node, struct sm6_parser *sm6) { @@ -4176,6 +4214,9 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t if ((ret = sm6_parser_entry_point_init(sm6)) < 0) return ret;
+ if ((ret = sm6_parser_resources_init(sm6)) < 0) + return ret; + if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0) { if (ret == VKD3D_ERROR_OUT_OF_MEMORY) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 85041f2a..cd5cc593 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -180,6 +180,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXIL_INVALID_ENTRY_POINT = 8015, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE = 8016, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES = 8017, + VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES = 8018,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxbc.c | 1 + libs/vkd3d-shader/dxil.c | 158 ++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 3 + 3 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index a9a7aefe..6f47560f 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -550,6 +550,7 @@ void free_shader_desc(struct vkd3d_shader_desc *desc) shader_signature_cleanup(&desc->input_signature); shader_signature_cleanup(&desc->output_signature); shader_signature_cleanup(&desc->patch_constant_signature); + vkd3d_free(desc->descriptors); }
int shader_extract_from_dxbc(const struct vkd3d_shader_code *dxbc, diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 4bfebea2..4d127515 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2821,6 +2821,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_value(const struct sm6_metadata_value *m) +{ + return m && m->type == VKD3D_METADATA_VALUE; +} + static bool sm6_metadata_value_is_string(const struct sm6_metadata_value *m) { return m && m->type == VKD3D_METADATA_STRING; @@ -3375,11 +3380,161 @@ static const struct sm6_metadata_value *sm6_parser_find_named_metadata(struct sm return NULL; }
+static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6, + const struct sm6_metadata_node *node, struct vkd3d_shader_register_range *range) +{ + unsigned int size; + + if (!sm6_metadata_value_is_value(node->operands[1])) + { + WARN("Resource data type is not a value.\n"); + return false; + } + if (!sm6_type_is_pointer(node->operands[1]->value_type)) + { + WARN("Resource type is not a pointer.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Resource metadata value type is not a pointer."); + } + + if (!sm6_metadata_get_uint_value(sm6, node->operands[3], &range->space)) + { + WARN("Failed to load register space.\n"); + return false; + } + if (!sm6_metadata_get_uint_value(sm6, node->operands[4], &range->first)) + { + WARN("Failed to load register first.\n"); + return false; + } + if (!sm6_metadata_get_uint_value(sm6, node->operands[5], &size)) + { + WARN("Failed to load register range size.\n"); + return false; + } + if (!size || (size != UINT_MAX && !vkd3d_bound_range(range->first, size, UINT_MAX))) + { + WARN("Invalid register range, first %u, size %u.\n", range->first, size); + return false; + } + range->last = (size == UINT_MAX) ? UINT_MAX : range->first + size - 1; + + return true; +} + +static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, + const struct sm6_metadata_node *node, struct vkd3d_shader_descriptor_info1 *d) +{ + if (node->operand_count < 7) + { + WARN("Invalid operand count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Invalid operand count %u for a CBV descriptor.", node->operand_count); + return VKD3D_ERROR_INVALID_SHADER; + } + if (node->operand_count > 7 && node->operands[7]) + { + WARN("Ignoring %u extra operands.\n", node->operand_count - 7); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for a CBV descriptor.", node->operand_count - 7); + } + + d->resource_type = VKD3D_SHADER_RESOURCE_BUFFER; + d->resource_data_type = VKD3D_SHADER_RESOURCE_DATA_UINT; + + if (!sm6_metadata_get_uint_value(sm6, node->operands[6], &d->buffer_size)) + { + WARN("Failed to load buffer size.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Constant buffer size metadata value is not an integer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, + enum vkd3d_shader_descriptor_type type, const struct sm6_metadata_node *descriptor_node, + size_t *descriptor_capacity) +{ + struct vkd3d_shader_desc *desc = &sm6->p.shader_desc; + struct vkd3d_shader_register_range range; + struct vkd3d_shader_descriptor_info1 *d; + const struct sm6_metadata_node *node; + const struct sm6_metadata_value *m; + enum vkd3d_result ret; + unsigned int i; + + for (i = 0; i < descriptor_node->operand_count; ++i) + { + m = descriptor_node->operands[i]; + if (!sm6_metadata_value_is_node(m)) + { + WARN("Resource descriptor is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource descriptor is not a metadata node."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!vkd3d_array_reserve((void **)&desc->descriptors, descriptor_capacity, + desc->descriptor_count + 1, sizeof(*desc->descriptors))) + { + ERR("Failed to allocate descriptor array.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating the descriptor array."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + d = &desc->descriptors[desc->descriptor_count]; + memset(d, 0, sizeof(*d)); + d->type = type; + + node = m->u.node; + + switch (type) + { + case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: + if ((ret = sm6_parser_resources_load_cbv(sm6, node, d)) < 0) + return ret; + break; + default: + FIXME("Unsupported descriptor type %u.\n", type); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource descriptor type %u is unsupported.", type); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!sm6_metadata_get_uint_value(sm6, node->operands[0], &d->register_id)) + { + WARN("Failed to load resource id.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource id metadata value is not an integer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!sm6_parser_resources_load_register_range(sm6, node, &range)) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource register range is invalid."); + return VKD3D_ERROR_INVALID_SHADER; + } + d->register_space = range.space; + d->register_index = range.first; + d->count = (range.last == UINT_MAX) ? UINT_MAX : range.last - range.first + 1; + + ++desc->descriptor_count; + } + + return VKD3D_OK; +} + static enum vkd3d_result sm6_parser_resources_init(struct sm6_parser *sm6) { const struct sm6_metadata_value *m = sm6_parser_find_named_metadata(sm6, "dx.resources"); enum vkd3d_shader_descriptor_type type; const struct sm6_metadata_node *node; + size_t descriptor_capacity = 0; + enum vkd3d_result ret;
if (!m) return VKD3D_OK; @@ -3406,7 +3561,8 @@ static enum vkd3d_result sm6_parser_resources_init(struct sm6_parser *sm6) return VKD3D_ERROR_INVALID_SHADER; }
- FIXME("Descriptor info is unhandled.\n"); + if ((ret = sm6_parser_descriptor_type_init(sm6, type, m->u.node, &descriptor_capacity)) < 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 cd5cc593..1305e4af 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -932,6 +932,9 @@ struct vkd3d_shader_desc { uint32_t used, external; } flat_constant_count[3]; + + struct vkd3d_shader_descriptor_info1 *descriptors; + size_t descriptor_count; };
struct vkd3d_shader_register_semantic
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/vkd3d_shader_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 052edeb5..310932d9 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1150,6 +1150,22 @@ static enum vkd3d_result convert_descriptor_info(struct vkd3d_shader_scan_descri return VKD3D_OK; }
+static bool clone_descriptor_info1_safe(struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info, + struct vkd3d_shader_descriptor_info1 *descriptors, unsigned int descriptor_count) +{ + if (!scan_descriptor_info || !descriptor_count) + return true; + + if (!(scan_descriptor_info->descriptors = vkd3d_calloc(descriptor_count, + sizeof(*scan_descriptor_info->descriptors)))) + return false; + memcpy(scan_descriptor_info->descriptors, descriptors, + descriptor_count * sizeof(*scan_descriptor_info->descriptors)); + scan_descriptor_info->descriptor_count = descriptor_count; + + return true; +} + static void vkd3d_shader_free_scan_descriptor_info1(struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info) { TRACE("scan_descriptor_info %p.\n", scan_descriptor_info); @@ -1179,6 +1195,8 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info { descriptor_info1 = &local_descriptor_info1; } + clone_descriptor_info1_safe(descriptor_info1, parser->shader_desc.descriptors, parser->shader_desc.descriptor_count); + signature_info = vkd3d_find_struct(compile_info->next, SCAN_SIGNATURE_INFO);
vkd3d_shader_scan_context_init(&context, compile_info, descriptor_info1, message_context);
@@ -932,6 +932,9 @@ struct vkd3d_shader_desc { uint32_t used, external; } flat_constant_count[3]; + + struct vkd3d_shader_descriptor_info1 *descriptors; + size_t descriptor_count; }; struct vkd3d_shader_register_semantic
I distinctly remember discussing this change before.
In any case, I don't think it's desirable to maintain two different ways of representing descriptor declarations on the IR level in parallel. If vkd3d_shader_descriptor_info1 is the way we're going, we should adjust the tpf parser to produce them, and the d3d-asm backend to consume them.
If vkd3d_shader_descriptor_info1 is the way we're going,
And having given it some thought, I'm not quite convinced that this is what we should do. In particular, using vkd3d_shader_descriptor_info1 implies making vkd3d_shader_uav_flags visible as part of vkd3d_shader_descriptor_info_flag, as can be seen in !416 in particular. And while the two flags introduced by that MR seem innocuous enough, it does make it hard for me to see how this approach could be made to scale to DCL_* instructions in general.