From: Conor McCarthy cmccarthy@codeweavers.com
A register count is required for Shader Model 6 signatures, including those normalised from earlier models. --- libs/vkd3d-shader/dxbc.c | 17 ++++--- libs/vkd3d-shader/ir.c | 8 +-- libs/vkd3d-shader/spirv.c | 62 ++++++++++++------------ libs/vkd3d-shader/tpf.c | 4 +- libs/vkd3d-shader/vkd3d_shader_main.c | 49 ++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 32 ++++++++++-- 6 files changed, 121 insertions(+), 51 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index e5bc67d9..db36928e 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -328,10 +328,10 @@ int vkd3d_shader_parse_dxbc(const struct vkd3d_shader_code *dxbc, }
static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *section, - struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_signature *s) + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_sm6_signature *s) { + struct vkd3d_shader_sm6_signature_element *e; bool has_stream_index, has_min_precision; - struct vkd3d_shader_signature_element *e; const char *data = section->data.code; uint32_t count, header_size; const char *ptr = data; @@ -395,6 +395,7 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s read_dword(&ptr, &e[i].sysval_semantic); read_dword(&ptr, &e[i].component_type); read_dword(&ptr, &e[i].register_index); + e[i].register_count = 1; read_dword(&ptr, &mask); e[i].mask = mask & 0xff; e[i].used_mask = (mask >> 8) & 0xff; @@ -429,7 +430,7 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s static int isgn_handler(const struct vkd3d_shader_dxbc_section_desc *section, struct vkd3d_shader_message_context *message_context, void *ctx) { - struct vkd3d_shader_signature *is = ctx; + struct vkd3d_shader_sm6_signature *is = ctx;
if (section->tag != TAG_ISGN) return VKD3D_OK; @@ -437,13 +438,13 @@ static int isgn_handler(const struct vkd3d_shader_dxbc_section_desc *section, if (is->elements) { FIXME("Multiple input signatures.\n"); - vkd3d_shader_free_shader_signature(is); + vkd3d_shader_sm6_free_shader_signature(is); } return shader_parse_signature(section, message_context, is); }
int shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, - struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_signature *signature) + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_sm6_signature *signature) { int ret;
@@ -522,9 +523,9 @@ static int shdr_handler(const struct vkd3d_shader_dxbc_section_desc *section,
void free_shader_desc(struct vkd3d_shader_desc *desc) { - vkd3d_shader_free_shader_signature(&desc->input_signature); - vkd3d_shader_free_shader_signature(&desc->output_signature); - vkd3d_shader_free_shader_signature(&desc->patch_constant_signature); + vkd3d_shader_sm6_free_shader_signature(&desc->input_signature); + vkd3d_shader_sm6_free_shader_signature(&desc->output_signature); + vkd3d_shader_sm6_free_shader_signature(&desc->patch_constant_signature); }
int shader_extract_from_dxbc(const struct vkd3d_shader_code *dxbc, diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 11ba7563..86a47833 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -320,7 +320,7 @@ static bool shader_dst_param_normalise_outpointid(struct vkd3d_shader_dst_param }
static void shader_dst_param_io_init(struct vkd3d_shader_dst_param *param, - const struct vkd3d_shader_signature_element *e, enum vkd3d_shader_register_type reg_type) + const struct vkd3d_shader_sm6_signature_element *e, enum vkd3d_shader_register_type reg_type) { param->write_mask = e->mask; param->modifiers = 0; @@ -329,9 +329,9 @@ static void shader_dst_param_io_init(struct vkd3d_shader_dst_param *param, }
static enum vkd3d_result shader_normaliser_emit_hs_input(struct vkd3d_shader_normaliser *normaliser, - const struct vkd3d_shader_signature *s, unsigned int input_control_point_count, unsigned int dst) + const struct vkd3d_shader_sm6_signature *s, unsigned int input_control_point_count, unsigned int dst) { - const struct vkd3d_shader_signature_element *e; + const struct vkd3d_shader_sm6_signature_element *e; struct vkd3d_shader_instruction *ins; struct vkd3d_shader_dst_param *param; unsigned int i, count; @@ -380,7 +380,7 @@ static enum vkd3d_result shader_normaliser_emit_hs_input(struct vkd3d_shader_nor }
enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struct vkd3d_shader_normaliser *normaliser, - const struct vkd3d_shader_signature *input_signature) + const struct vkd3d_shader_sm6_signature *input_signature) { struct vkd3d_shader_instruction_array *instructions = &normaliser->instructions; unsigned int input_control_point_count; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index ec4e1d1d..2834d307 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2243,9 +2243,9 @@ struct spirv_compiler const struct vkd3d_shader_spirv_target_info *spirv_target_info;
bool after_declarations_section; - const struct vkd3d_shader_signature *input_signature; - const struct vkd3d_shader_signature *output_signature; - const struct vkd3d_shader_signature *patch_constant_signature; + const struct vkd3d_shader_sm6_signature *input_signature; + const struct vkd3d_shader_sm6_signature *output_signature; + const struct vkd3d_shader_sm6_signature *patch_constant_signature; const struct vkd3d_shader_transform_feedback_info *xfb_info; struct vkd3d_shader_output_info { @@ -2329,8 +2329,8 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info, struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location) { - const struct vkd3d_shader_signature *patch_constant_signature = &shader_desc->patch_constant_signature; - const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature; + const struct vkd3d_shader_sm6_signature *patch_constant_signature = &shader_desc->patch_constant_signature; + const struct vkd3d_shader_sm6_signature *output_signature = &shader_desc->output_signature; const struct vkd3d_shader_interface_info *shader_interface; const struct vkd3d_shader_descriptor_offset_info *offset_info; const struct vkd3d_shader_spirv_target_info *target_info; @@ -4258,8 +4258,8 @@ static const struct vkd3d_spirv_builtin *vkd3d_get_spirv_builtin(const struct sp return NULL; }
-static const struct vkd3d_shader_signature_element *vkd3d_find_signature_element_for_reg( - const struct vkd3d_shader_signature *signature, unsigned int *signature_element_index, +static const struct vkd3d_shader_sm6_signature_element *vkd3d_find_signature_element_for_reg( + const struct vkd3d_shader_sm6_signature *signature, unsigned int *signature_element_index, unsigned int reg_idx, DWORD write_mask) { unsigned int signature_idx; @@ -4342,7 +4342,7 @@ static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( }
static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, - uint32_t id, unsigned int component_count, const struct vkd3d_shader_signature_element *signature_element) + uint32_t id, unsigned int component_count, const struct vkd3d_shader_sm6_signature_element *signature_element) { const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info; const struct vkd3d_shader_transform_feedback_element *xfb_element; @@ -4423,7 +4423,7 @@ static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *comp return id; }
-static bool needs_private_io_variable(const struct vkd3d_shader_signature *signature, +static bool needs_private_io_variable(const struct vkd3d_shader_sm6_signature *signature, unsigned int reg_idx, const struct vkd3d_spirv_builtin *builtin, unsigned int *component_count, unsigned int *out_write_mask) { @@ -4443,7 +4443,7 @@ static bool needs_private_io_variable(const struct vkd3d_shader_signature *signa
for (i = 0, count = 0; i < signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *current = &signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *current = &signature->elements[i];
if (current->register_index != reg_idx) continue; @@ -4477,9 +4477,9 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval, enum vkd3d_shader_interpolation_mode interpolation_mode) { + const struct vkd3d_shader_sm6_signature_element *signature_element; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature_element *signature_element; - const struct vkd3d_shader_signature *shader_signature; + const struct vkd3d_shader_sm6_signature *shader_signature; const struct vkd3d_shader_register *reg = &dst->reg; unsigned int component_idx, input_component_count; enum vkd3d_shader_component_type component_type; @@ -4786,7 +4786,7 @@ static bool is_dual_source_blending(const struct spirv_compiler *compiler) return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->dual_source_blending; }
-static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signature_element *e, +static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_sm6_signature_element *e, uint32_t *mask) { if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE) @@ -4799,9 +4799,9 @@ static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signa }
static uint32_t calculate_sysval_array_mask(struct spirv_compiler *compiler, - const struct vkd3d_shader_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval) + const struct vkd3d_shader_sm6_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval) { - const struct vkd3d_shader_signature_element *e; + const struct vkd3d_shader_sm6_signature_element *e; const struct vkd3d_spirv_builtin *sig_builtin; const struct vkd3d_spirv_builtin *builtin; uint32_t signature_idx, mask = 0; @@ -4829,7 +4829,7 @@ static uint32_t calculate_sysval_array_mask(struct spirv_compiler *compiler, /* Emits arrayed SPIR-V built-in variables. */ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *output_signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *output_signature = compiler->output_signature; uint32_t clip_distance_mask = 0, clip_distance_id = 0; uint32_t cull_distance_mask = 0, cull_distance_id = 0; const struct vkd3d_spirv_builtin *builtin; @@ -4837,7 +4837,7 @@ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *
for (i = 0; i < output_signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *e = &output_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *e = &output_signature->elements[i];
switch (e->sysval_semantic) { @@ -4872,7 +4872,7 @@ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *
for (i = 0; i < output_signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *e = &output_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *e = &output_signature->elements[i];
switch (e->sysval_semantic) { @@ -4955,9 +4955,9 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval) { + const struct vkd3d_shader_sm6_signature_element *signature_element; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature_element *signature_element; - const struct vkd3d_shader_signature *shader_signature; + const struct vkd3d_shader_sm6_signature *shader_signature; const struct vkd3d_shader_register *reg = &dst->reg; unsigned int component_idx, output_component_count; enum vkd3d_shader_component_type component_type; @@ -5123,7 +5123,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *compiler, - const struct vkd3d_shader_signature_element *e) + const struct vkd3d_shader_sm6_signature_element *e) { enum vkd3d_shader_input_sysval_semantic sysval; const struct vkd3d_spirv_builtin *builtin; @@ -5142,14 +5142,14 @@ static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *com }
static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compiler, - const struct vkd3d_shader_signature *signature, const struct vkd3d_shader_signature_element *output, + const struct vkd3d_shader_sm6_signature *signature, const struct vkd3d_shader_sm6_signature_element *output, const struct vkd3d_shader_output_info *output_info, uint32_t output_index_id, uint32_t val_id, unsigned int write_mask) { unsigned int dst_write_mask, use_mask, uninit_mask, swizzle, mask; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id; - const struct vkd3d_shader_signature_element *element; + const struct vkd3d_shader_sm6_signature_element *element; unsigned int i, index, array_idx; uint32_t output_id;
@@ -5238,7 +5238,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * uint32_t param_type_id[MAX_REG_OUTPUT + 1], param_id[MAX_REG_OUTPUT + 1] = {0}; uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature *signature; + const struct vkd3d_shader_sm6_signature *signature; uint32_t output_index_id = 0; bool is_patch_constant; unsigned int i, count; @@ -5323,7 +5323,7 @@ static void spirv_compiler_emit_hull_shader_builtins(struct spirv_compiler *comp
static void spirv_compiler_emit_hull_shader_patch_constants(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *signature = compiler->patch_constant_signature; + const struct vkd3d_shader_sm6_signature *signature = compiler->patch_constant_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t register_count = 0; unsigned int signature_idx; @@ -6446,7 +6446,7 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile
static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *signature = compiler->output_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_symbol reg_symbol, *symbol; struct vkd3d_shader_register reg; @@ -6485,7 +6485,7 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler)
for (i = 0; i < signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *e = &signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *e = &signature->elements[i];
reg.type = VKD3DSPR_OUTPUT; reg.idx[0].offset = e->register_index; @@ -6548,8 +6548,8 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *output_signature = compiler->output_signature; - const struct vkd3d_shader_signature *input_signature = compiler->input_signature; + const struct vkd3d_shader_sm6_signature *output_signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *input_signature = compiler->input_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; enum vkd3d_shader_component_type component_type; struct vkd3d_shader_src_param invocation; @@ -6580,8 +6580,8 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile assert(input_signature->element_count == output_signature->element_count); for (i = 0; i < output_signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *output = &output_signature->elements[i]; - const struct vkd3d_shader_signature_element *input = &input_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *output = &output_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *input = &input_signature->elements[i];
assert(input->mask == output->mask); assert(input->component_type == output->component_type); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index e76cf8c9..e7517177 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2060,7 +2060,7 @@ static const struct vkd3d_shader_parser_ops shader_sm4_parser_ops = };
static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t *byte_code, - size_t byte_code_size, const char *source_name, const struct vkd3d_shader_signature *output_signature, + size_t byte_code_size, const char *source_name, const struct vkd3d_shader_sm6_signature *output_signature, struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_version version; @@ -2128,7 +2128,7 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t memset(sm4->output_map, 0xff, sizeof(sm4->output_map)); for (i = 0; i < output_signature->element_count; ++i) { - struct vkd3d_shader_signature_element *e = &output_signature->elements[i]; + struct vkd3d_shader_sm6_signature_element *e = &output_signature->elements[i];
if (version.type == VKD3D_SHADER_TYPE_PIXEL && ascii_strcasecmp(e->semantic_name, "SV_Target")) diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 8728f974..a15cd2d0 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1401,10 +1401,53 @@ void vkd3d_shader_free_root_signature(struct vkd3d_shader_versioned_root_signatu desc->version = 0; }
+static bool shader_signature_from_shader_sm6_signature(struct vkd3d_shader_signature *signature, + const struct vkd3d_shader_sm6_signature *src) +{ + unsigned int i; + + signature->element_count = src->element_count; + if (!src->elements) + { + signature->elements = NULL; + return true; + } + + if (!(signature->elements = vkd3d_malloc(signature->element_count * sizeof(*signature->elements)))) + return false; + + for (i = 0; i < signature->element_count; ++i) + { + struct vkd3d_shader_sm6_signature_element *e = &src->elements[i]; + struct vkd3d_shader_signature_element *d = &signature->elements[i]; + + d->semantic_name = e->semantic_name; + d->semantic_index = e->semantic_index; + d->stream_index = e->stream_index; + d->sysval_semantic = e->sysval_semantic; + d->component_type = e->component_type; + d->register_index = e->register_index; + if (e->register_count > 1) + FIXME("Arrayed elements are not supported yet.\n"); + d->mask = e->mask; + d->used_mask = e->used_mask; + d->min_precision = e->min_precision; + } + + return true; +} + +void vkd3d_shader_sm6_free_shader_signature(struct vkd3d_shader_sm6_signature *signature) +{ + vkd3d_free(signature->elements); + signature->elements = NULL; +} + int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_signature *signature, char **messages) { struct vkd3d_shader_message_context message_context; + struct vkd3d_shader_sm6_signature sm6_signature; int ret;
TRACE("dxbc {%p, %zu}, signature %p, messages %p.\n", dxbc->code, dxbc->size, signature, messages); @@ -1413,13 +1456,17 @@ int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, *messages = NULL; vkd3d_shader_message_context_init(&message_context, VKD3D_SHADER_LOG_INFO);
- ret = shader_parse_input_signature(dxbc, &message_context, signature); + ret = shader_parse_input_signature(dxbc, &message_context, &sm6_signature); vkd3d_shader_message_context_trace_messages(&message_context); if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) ret = VKD3D_ERROR_OUT_OF_MEMORY;
vkd3d_shader_message_context_cleanup(&message_context);
+ if (!shader_signature_from_shader_sm6_signature(signature, &sm6_signature)) + ret = VKD3D_ERROR_OUT_OF_MEMORY; + + vkd3d_shader_sm6_free_shader_signature(&sm6_signature); return ret; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 469139b5..6cea8552 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -774,13 +774,35 @@ enum vkd3d_shader_input_sysval_semantic VKD3D_SIV_LINE_DENSITY_TESS_FACTOR = 22, };
+struct vkd3d_shader_sm6_signature_element +{ + const char *semantic_name; + unsigned int semantic_index; + unsigned int stream_index; + enum vkd3d_shader_sysval_semantic sysval_semantic; + enum vkd3d_shader_component_type component_type; + unsigned int register_index; + unsigned int register_count; + unsigned int mask; + unsigned int used_mask; + enum vkd3d_shader_minimum_precision min_precision; +}; + +struct vkd3d_shader_sm6_signature +{ + struct vkd3d_shader_sm6_signature_element *elements; + unsigned int element_count; +}; + +void vkd3d_shader_sm6_free_shader_signature(struct vkd3d_shader_sm6_signature *signature); + struct vkd3d_shader_desc { const uint32_t *byte_code; size_t byte_code_size; - struct vkd3d_shader_signature input_signature; - struct vkd3d_shader_signature output_signature; - struct vkd3d_shader_signature patch_constant_signature; + struct vkd3d_shader_sm6_signature input_signature; + struct vkd3d_shader_sm6_signature output_signature; + struct vkd3d_shader_sm6_signature patch_constant_signature; };
struct vkd3d_shader_register_semantic @@ -1135,7 +1157,7 @@ void free_shader_desc(struct vkd3d_shader_desc *desc); int shader_extract_from_dxbc(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context, const char *source_name, struct vkd3d_shader_desc *desc); int shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, - struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_signature *signature); + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_sm6_signature *signature);
struct vkd3d_glsl_generator;
@@ -1349,7 +1371,7 @@ void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser, struct vkd3d_shader_instruction_array *instructions); enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shader_normaliser *normaliser); enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struct vkd3d_shader_normaliser *normaliser, - const struct vkd3d_shader_signature *input_signature); + const struct vkd3d_shader_sm6_signature *input_signature); void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser);
#endif /* __VKD3D_SHADER_PRIVATE_H */
From: Conor McCarthy cmccarthy@codeweavers.com
--- tests/d3d12.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+)
diff --git a/tests/d3d12.c b/tests/d3d12.c index bc01cadb..23e1e97c 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -36303,6 +36303,164 @@ static void test_readback_map_stability(void) ID3D12Resource_Unmap(buffer, 0, NULL);
ID3D12Resource_Release(buffer); +} + +static void test_vs_ps_relative_addressing(void) +{ + D3D12_ROOT_SIGNATURE_DESC root_signature_desc; + D3D12_ROOT_PARAMETER root_parameters[1]; + ID3D12GraphicsCommandList *command_list; + D3D12_INPUT_LAYOUT_DESC input_layout; + struct test_context_desc desc; + D3D12_VERTEX_BUFFER_VIEW vbv; + struct test_context context; + ID3D12CommandQueue *queue; + ID3D12Resource *vb; + HRESULT hr; + + static const struct + { + struct vec4 position; + uint32_t color[3]; + } + vertices[] = + { + {{-1.0f, -1.0f, 0.0f, 1.0f}, {0xffffff00, 0xff00, 0xff00ff00}}, + {{-1.0f, 1.0f, 0.0f, 1.0f}, {0xffffff00, 0xff00, 0xff00ff00}}, + {{ 1.0f, -1.0f, 0.0f, 1.0f}, {0xffffff00, 0xff00, 0xff00ff00}}, + {{ 1.0f, 1.0f, 0.0f, 1.0f}, {0xffffff00, 0xff00, 0xff00ff00}}, + }; + static const D3D12_INPUT_ELEMENT_DESC layout_desc[] = + { + {"SV_POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 16, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, + {"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 20, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, + {"COLOR", 2, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, + }; + static const DWORD vs_code[] = + { +#if 0 + uint3 index; + + struct vs_data + { + float4 pos : SV_Position; + float4 color[3] : COLOR; + }; + + void main(in struct vs_data vs_input, out struct vs_data vs_output) + { + vs_output.pos = vs_input.pos; + vs_output.color[0] = vs_input.color[index.x]; + vs_output.color[1] = vs_input.color[index.y]; + vs_output.color[2] = vs_input.color[index.z]; + } +#endif + 0x43425844, 0x313cf242, 0x30e9b93c, 0xf8d3ed69, 0x0feecdca, 0x00000001, 0x00000288, 0x00000003, + 0x0000002c, 0x000000b0, 0x00000134, 0x4e475349, 0x0000007c, 0x00000004, 0x00000008, 0x00000068, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000074, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000f0f, 0x00000074, 0x00000001, 0x00000000, 0x00000003, 0x00000002, + 0x00000f0f, 0x00000074, 0x00000002, 0x00000000, 0x00000003, 0x00000003, 0x00000f0f, 0x505f5653, + 0x5449534f, 0x004e4f49, 0x4f4c4f43, 0xabab0052, 0x4e47534f, 0x0000007c, 0x00000004, 0x00000008, + 0x00000068, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x00000074, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x0000000f, 0x00000074, 0x00000001, 0x00000000, 0x00000003, + 0x00000002, 0x0000000f, 0x00000074, 0x00000002, 0x00000000, 0x00000003, 0x00000003, 0x0000000f, + 0x505f5653, 0x5449534f, 0x004e4f49, 0x4f4c4f43, 0xabab0052, 0x58454853, 0x0000014c, 0x00010050, + 0x00000053, 0x0100086a, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x0300005f, 0x001010f2, + 0x00000000, 0x0300005f, 0x001010f2, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, 0x0300005f, + 0x001010f2, 0x00000003, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, + 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x03000065, 0x001020f2, 0x00000003, 0x02000068, + 0x00000001, 0x0400005b, 0x001010f2, 0x00000001, 0x00000003, 0x05000036, 0x001020f2, 0x00000000, + 0x00101e46, 0x00000000, 0x06000036, 0x00100012, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, + 0x07000036, 0x001020f2, 0x00000001, 0x00d01e46, 0x00000001, 0x0010000a, 0x00000000, 0x06000036, + 0x00100012, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x07000036, 0x001020f2, 0x00000002, + 0x00d01e46, 0x00000001, 0x0010000a, 0x00000000, 0x06000036, 0x00100012, 0x00000000, 0x0020802a, + 0x00000000, 0x00000000, 0x07000036, 0x001020f2, 0x00000003, 0x00d01e46, 0x00000001, 0x0010000a, + 0x00000000, 0x0100003e, + }; + static const D3D12_SHADER_BYTECODE vs = {vs_code, sizeof(vs_code)}; + static const DWORD ps_code[] = + { +#if 0 + uint4 index; + + struct ps_data + { + float4 pos : SV_Position; + float4 color[3] : COLOR; + }; + + float4 main(struct ps_data ps_input) : SV_Target + { + return ps_input.color[index.w]; + } +#endif + 0x43425844, 0x2b11c807, 0xf4f69d91, 0x983d18c9, 0x99ff2a5e, 0x00000001, 0x00000188, 0x00000003, + 0x0000002c, 0x000000b0, 0x000000e4, 0x4e475349, 0x0000007c, 0x00000004, 0x00000008, 0x00000068, + 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x00000074, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000f0f, 0x00000074, 0x00000001, 0x00000000, 0x00000003, 0x00000002, + 0x00000f0f, 0x00000074, 0x00000002, 0x00000000, 0x00000003, 0x00000003, 0x00000f0f, 0x505f5653, + 0x5449534f, 0x004e4f49, 0x4f4c4f43, 0xabab0052, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, + 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, + 0xabab0074, 0x58454853, 0x0000009c, 0x00000050, 0x00000027, 0x0100086a, 0x04000059, 0x00208e46, + 0x00000000, 0x00000001, 0x03001062, 0x001010f2, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, + 0x03001062, 0x001010f2, 0x00000003, 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000001, + 0x0400005b, 0x001010f2, 0x00000001, 0x00000003, 0x06000036, 0x00100012, 0x00000000, 0x0020803a, + 0x00000000, 0x00000000, 0x07000036, 0x001020f2, 0x00000000, 0x00d01e46, 0x00000001, 0x0010000a, + 0x00000000, 0x0100003e, + }; + static const D3D12_SHADER_BYTECODE ps = {ps_code, sizeof(ps_code)}; + static const uint32_t indices[] = {1, 2, 0, 1}; + static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f}; + + memset(&desc, 0, sizeof(desc)); + desc.no_root_signature = true; + desc.no_pipeline = true; + if (!init_test_context(&context, &desc)) + return; + command_list = context.list; + queue = context.queue; + + root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + root_parameters[0].Constants.ShaderRegister = 0; + root_parameters[0].Constants.RegisterSpace = 0; + root_parameters[0].Constants.Num32BitValues = 4; + root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + memset(&root_signature_desc, 0, sizeof(root_signature_desc)); + root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); + root_signature_desc.pParameters = root_parameters; + root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + hr = create_root_signature(context.device, &root_signature_desc, &context.root_signature); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + input_layout.pInputElementDescs = layout_desc; + input_layout.NumElements = ARRAY_SIZE(layout_desc); + context.pipeline_state = create_pipeline_state(context.device, + context.root_signature, context.render_target_desc.Format, &vs, &ps, &input_layout); + + vb = create_upload_buffer(context.device, sizeof(vertices), vertices); + vbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(vb); + vbv.StrideInBytes = sizeof(*vertices); + vbv.SizeInBytes = sizeof(vertices); + + ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL); + + ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL); + ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature); + ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state); + ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &indices, 0); + ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &vbv); + ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport); + ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect); + ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0); + + transition_resource_state(command_list, context.render_target, + D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); + todo + check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0); + + ID3D12Resource_Release(vb); destroy_test_context(&context); }
@@ -36484,4 +36642,5 @@ START_TEST(d3d12) run_test(test_unbounded_samplers); run_test(test_clock_calibration); run_test(test_readback_map_stability); + run_test(test_vs_ps_relative_addressing); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/ir.c | 6 +----- libs/vkd3d-shader/tpf.c | 17 +++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 86a47833..df589c37 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -300,11 +300,7 @@ static bool shader_dst_param_normalise_outpointid(struct vkd3d_shader_dst_param
if (normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) { - if (reg->idx[2].offset != ~0u) - { - FIXME("Cannot insert phase id.\n"); - return false; - } + assert(reg->idx[2].offset == ~0u); if (reg->idx[1].offset != ~0u) { WARN("Unexpected address at index 1.\n"); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index e7517177..9895ec3e 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -1656,6 +1656,23 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui else { DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK2) >> VKD3D_SM4_ADDRESSING_SHIFT2; + + /* The normaliser requires the highest slot free in some cases. */ + switch (param->type) + { + case VKD3DSPR_INPUT: + case VKD3DSPR_OUTPUT: + case VKD3DSPR_COLOROUT: + case VKD3DSPR_INCONTROLPOINT: + case VKD3DSPR_OUTCONTROLPOINT: + case VKD3DSPR_PATCHCONST: + vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_PARAM_ORDER_TOO_HIGH, + "Unexpected I/O parameter order greater than 2.\n"); + break; + default: + break; + } + if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, ¶m->idx[2]))) { ERR("Failed to read register index.\n"); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6cea8552..ab59061e 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -74,6 +74,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF = 1000, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_RANGE = 1001, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY = 1002, + VKD3D_SHADER_ERROR_TPF_PARAM_ORDER_TOO_HIGH = 1003,
VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND = 2000, VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE = 2001,
From: Conor McCarthy cmccarthy@codeweavers.com
In Shader Model 6 each signature element can span a range of register indices, or 'rows', and system values do not share a register index with non-system values. Inputs and outputs are referenced by element index instead of register index. This patch merges multiple signature elements into a single element under the following conditions:
- The register index in a load or store is specified dynamically by including a relative address parameter with a base register index. The dcl_index_range instruction is used to identify these. - A register declaration is split across multiple elements which declare different components of the register. - A patch constant function writes tessellation factors. These are an array in SPIR-V, but in SM 5.x each factor is declared as a separate register, and these are dynamically indexed by the fork/join instance id. Elimination of multiple fork/join phases converts the indices to constants, but merging the signature elements into a single arrayed element matches the SPIR-V output.
All references to input/output register indices are converted to element indices. If a relative address is present, the element index is moved up a slot so it cannot be confused with a constant offset. Existing code only handles register index relative addressing for tessellation factors. This patch adds generic support for it. --- libs/vkd3d-shader/d3dbc.c | 1 + libs/vkd3d-shader/dxbc.c | 2 + libs/vkd3d-shader/ir.c | 680 ++++++++++++++++++++- libs/vkd3d-shader/spirv.c | 719 ++++++++--------------- libs/vkd3d-shader/tpf.c | 1 + libs/vkd3d-shader/vkd3d_shader_private.h | 37 +- tests/d3d12.c | 1 - 7 files changed, 953 insertions(+), 488 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 14268440..4ab59e73 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -976,6 +976,7 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi return VKD3D_ERROR_OUT_OF_MEMORY; } ins = &instructions->elements[instructions->count]; + ins->source_index = instructions->count; shader_sm1_read_instruction(sm1, ins);
if (ins->handler_idx == VKD3DSIH_INVALID) diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index db36928e..9a8ffcc5 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -379,6 +379,8 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s { uint32_t name_offset, mask;
+ e[i].sort_index = i; + if (has_stream_index) read_dword(&ptr, &e[i].stream_index); else diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index df589c37..cc4053ce 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -18,6 +18,29 @@
#include "vkd3d_shader_private.h"
+static void VKD3D_PRINTF_FUNC(3, 4) shader_normaliser_error(struct vkd3d_shader_normaliser *normaliser, + enum vkd3d_shader_error error, const char *format, ...) +{ + struct vkd3d_shader_location location = {NULL, normaliser->source_index + 1, 0}; + va_list args; + + va_start(args, format); + vkd3d_shader_verror(normaliser->message_context, &location, error, format, args); + va_end(args); + normaliser->failed = true; +} + +static void VKD3D_PRINTF_FUNC(3, 4) shader_normaliser_warning(struct vkd3d_shader_normaliser *normaliser, + enum vkd3d_shader_error error, const char *format, ...) +{ + struct vkd3d_shader_location location = {NULL, normaliser->source_index + 1, 0}; + va_list args; + + va_start(args, format); + vkd3d_shader_vwarning(normaliser->message_context, &location, error, format, args); + va_end(args); +} + static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) { return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; @@ -245,11 +268,12 @@ static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum v }
void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser, - struct vkd3d_shader_instruction_array *instructions) + struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_message_context *message_context) { memset(normaliser, 0, sizeof(*normaliser)); normaliser->phase = VKD3DSIH_INVALID; normaliser->instructions = *instructions; + normaliser->message_context = message_context; memset(instructions, 0, sizeof(*instructions)); }
@@ -439,6 +463,660 @@ enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struc return VKD3D_OK; }
+static unsigned int shader_signature_find_element_for_reg(const struct vkd3d_shader_sm6_signature *signature, + unsigned int reg_idx, unsigned int write_mask, struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int signature_idx; + + for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx) + { + struct vkd3d_shader_sm6_signature_element *e = &signature->elements[signature_idx]; + if (e->register_index <= reg_idx && e->register_index + e->register_count > reg_idx + && (e->mask & write_mask) == write_mask) + { + return signature_idx; + } + } + + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_INVALID_IO_REGISTER, + "Could not find signature element matching register %u and write mask %#x.\n", reg_idx, write_mask); + return ~0u; +} + +static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE], + unsigned int register_idx, unsigned int write_mask, struct vkd3d_shader_normaliser *normaliser) +{ + if (register_idx >= MAX_REG_OUTPUT) + { + /* An error was already emitted if this occurred while setting the counts, + * and returning 0 is safe otherwise. */ + return 0; + } + return range_map[register_idx][vkd3d_write_mask_get_component_idx(write_mask)]; +} + +static void shader_normaliser_index_range_error(struct vkd3d_shader_normaliser *normaliser, unsigned int register_idx, + unsigned int write_mask) +{ + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_INVALID_INDEX_RANGE, + "Register index range base %u, mask %#x falls within a previous declaration.\n", register_idx, + write_mask); +} + +static void range_map_set_register_range(uint8_t range_map[][VKD3D_VEC4_SIZE], unsigned int register_idx, + unsigned int register_count, unsigned int write_mask, bool is_dcl_indexrange, + struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i, j, r, c, component_idx, component_count; + + assert(write_mask <= VKD3DSP_WRITEMASK_ALL); + component_idx = vkd3d_write_mask_get_component_idx(write_mask); + component_count = vkd3d_write_mask_component_count(write_mask); + + if (write_mask > (1u << (component_idx + component_count)) - 1) + { + WARN("Mask %#x is not contiguous.\n", write_mask); + shader_normaliser_warning(normaliser, VKD3D_SHADER_WARNING_IR_MASK_NOT_CONTIGUOUS, + "Signature element mask %#x is not contiguous.\n", write_mask); + } + + if (register_idx >= MAX_REG_OUTPUT || MAX_REG_OUTPUT - register_idx < register_count) + { + FIXME("Unhandled register index base %u, count %u.\n", register_idx, register_count); + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_TOO_MANY_REGISTERS, + "Register index base %u, count %u exceeds maximum index of %u.\n", register_idx, + register_count, MAX_REG_OUTPUT - 1); + return; + } + + if (range_map[register_idx][component_idx] > register_count && is_dcl_indexrange) + { + if (range_map[register_idx][component_idx] == UINT8_MAX) + { + /* Ranges in different dcl_indexrange instructions with different bases should not overlap. */ + FIXME("Register %u, component %u falls within a previous range.\n", register_idx, component_idx); + shader_normaliser_index_range_error(normaliser, register_idx, write_mask); + } + return; + } + if (range_map[register_idx][component_idx] == register_count) + { + /* Already done. This happens when fxc splits a register declaration by + * component(s). The dcl_indexrange instructions are split too. */ + return; + } + range_map[register_idx][component_idx] = register_count; + + for (i = 0; i < register_count; ++i) + { + r = register_idx + i; + for (j = !i; j < component_count; ++j) + { + c = component_idx + j; + if (range_map[r][c] && is_dcl_indexrange) + { + /* A synthetic patch constant range which overlaps an existing range can start upstream of it + * for fork/join phase instancing, but ranges declared by dcl_indexrange should not overlap. */ + FIXME("Register %u, component %u falls within a previous range.\n", r, c); + shader_normaliser_index_range_error(normaliser, r, c); + } + range_map[r][c] = UINT8_MAX; + } + } +} + +static void shader_normaliser_add_index_range(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_instruction *ins) +{ + const struct vkd3d_shader_index_range *range = &ins->declaration.index_range; + const struct vkd3d_shader_register *reg = &range->dst.reg; + const struct vkd3d_shader_sm6_signature *signature; + uint8_t (*range_map)[VKD3D_VEC4_SIZE]; + unsigned int reg_idx, element_idx; + + switch (reg->type) + { + case VKD3DSPR_INPUT: + case VKD3DSPR_INCONTROLPOINT: + range_map = normaliser->input_range_map; + signature = normaliser->input_signature; + break; + case VKD3DSPR_OUTCONTROLPOINT: + range_map = normaliser->output_range_map; + signature = normaliser->output_signature; + break; + case VKD3DSPR_OUTPUT: + if (!normaliser_is_in_fork_or_join_phase(normaliser)) + { + range_map = normaliser->output_range_map; + signature = normaliser->output_signature; + break; + } + /* fall through */ + case VKD3DSPR_PATCHCONST: + range_map = normaliser->pc_range_map; + signature = normaliser->patch_constant_signature; + break; + default: + FIXME("Unhandled register type %#x.\n", reg->type); + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_UNKNOWN_INDEX_RANGE_TYPE, + "Unknown index range register type %#x.\n", reg->type); + return; + } + + reg_idx = (reg->idx[1].offset != ~0u) ? reg->idx[1].offset : reg->idx[0].offset; + element_idx = shader_signature_find_element_for_reg(signature, reg_idx, range->dst.write_mask, normaliser); + if (element_idx == ~0u) + { + FIXME("Failed to find signature element for register %u and write mask %#x.\n", reg_idx, range->dst.write_mask); + return; + } + + range_map_set_register_range(range_map, reg_idx, range->register_count, + signature->elements[element_idx].mask, true, normaliser); +} + +static int signature_element_mask_compare(const void *a, const void *b) +{ + const struct vkd3d_shader_sm6_signature_element *e = a, *f = b; + + if (e->mask == f->mask) + return vkd3d_u32_compare(e->register_index, f->register_index); + return vkd3d_u32_compare(e->mask, f->mask); +} + +static bool merge_sysval_semantics(struct vkd3d_shader_sm6_signature_element *e, + struct vkd3d_shader_sm6_signature_element *f) +{ + if (e->sysval_semantic < VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE + || e->sysval_semantic > VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN) + return false; + + return e->sysval_semantic == f->sysval_semantic + /* Line detail and density must be merged together to match the SPIR-V array. + * This deletes one of the two sysvals, but these are not used. */ + || (e->sysval_semantic == VKD3D_SHADER_SV_TESS_FACTOR_LINEDET + && f->sysval_semantic == VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN) + || (e->sysval_semantic == VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN + && f->sysval_semantic == VKD3D_SHADER_SV_TESS_FACTOR_LINEDET); +} + +/* Merge tess factor sysvals because they are an array in SPIR-V. */ +static void shader_signature_map_patch_constant_index_ranges(struct vkd3d_shader_sm6_signature *s, + uint8_t range_map[][VKD3D_VEC4_SIZE], struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_sm6_signature_element *e, *f; + unsigned int i, j, register_count; + + qsort(s->elements, s->element_count, sizeof(s->elements[0]), signature_element_mask_compare); + + for (i = 0; i < s->element_count; i += register_count) + { + e = &s->elements[i]; + register_count = 1; + + if (!e->sysval_semantic) + continue; + + for (j = i + 1; j < s->element_count; ++j, ++register_count) + { + f = &s->elements[j]; + if (f->register_index != e->register_index + register_count || !merge_sysval_semantics(e, f)) + break; + } + if (register_count < 2) + continue; + + range_map_set_register_range(range_map, e->register_index, register_count, e->mask, false, normaliser); + } +} + +static int signature_element_register_compare(const void *a, const void *b) +{ + const struct vkd3d_shader_sm6_signature_element *e = a, *f = b; + + return vkd3d_u32_compare(e->register_index, f->register_index); +} + +static int signature_element_index_compare(const void *a, const void *b) +{ + const struct vkd3d_shader_sm6_signature_element *e = a, *f = b; + + return vkd3d_u32_compare(e->sort_index, f->sort_index); +} + +static bool shader_signature_merge(struct vkd3d_shader_sm6_signature *s, uint8_t range_map[][VKD3D_VEC4_SIZE], + bool is_patch_constant, struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i, j, element_count, new_count, register_count; + struct vkd3d_shader_sm6_signature_element *elements; + struct vkd3d_shader_sm6_signature_element *e, *f; + + element_count = s->element_count; + if (!(elements = vkd3d_malloc(element_count * sizeof(*elements)))) + return false; + memcpy(elements, s->elements, element_count * sizeof(*elements)); + + qsort(elements, element_count, sizeof(elements[0]), signature_element_register_compare); + + for (i = 0, new_count = 0; i < element_count; i = j, elements[new_count++] = *e) + { + e = &elements[i]; + j = i + 1; + + if (e->register_index == ~0u) + continue; + + /* Do not merge if the register index will be relative-addressed. */ + if (range_map_get_register_count(range_map, e->register_index, e->mask, normaliser) > 1) + continue; + + for (; j < element_count; ++j) + { + f = &elements[j]; + + /* Merge different components of the same register unless sysvals are different, + * or it will be relative-addressed. */ + if (f->register_index != e->register_index || f->sysval_semantic != e->sysval_semantic + || range_map_get_register_count(range_map, f->register_index, f->mask, normaliser) > 1) + break; + + TRACE("Merging %s, reg %u, mask %#x, sysval %#x with %s, mask %#x, sysval %#x.\n", e->semantic_name, + e->register_index, e->mask, e->sysval_semantic, f->semantic_name, f->mask, f->sysval_semantic); + assert(!(e->mask & f->mask)); + + e->mask |= f->mask; + e->used_mask |= f->used_mask; + e->semantic_index = min(e->semantic_index, f->semantic_index); + } + } + element_count = new_count; + /* Signature 's' is a copy of the original signature struct, so we can replace + * the 'elements' pointer without freeing it. */ + s->elements = elements; + s->element_count = element_count; + + if (is_patch_constant) + shader_signature_map_patch_constant_index_ranges(s, range_map, normaliser); + + for (i = 0, new_count = 0; i < element_count; i += register_count, elements[new_count++] = *e) + { + e = &elements[i]; + register_count = 1; + + if (e->register_index >= MAX_REG_OUTPUT) + continue; + + register_count = range_map_get_register_count(range_map, e->register_index, e->mask, normaliser); + assert(register_count != UINT8_MAX); + register_count += !register_count; + + if (register_count > 1) + { + TRACE("Merging %s, base reg %u, count %u.\n", e->semantic_name, e->register_index, register_count); + e->register_count = register_count; + } + } + element_count = new_count; + + /* Restoring the original order is required for sensible trace output. */ + qsort(elements, element_count, sizeof(elements[0]), signature_element_index_compare); + + s->element_count = element_count; + + return true; +} + +static bool sysval_semantic_is_tess_factor(enum vkd3d_shader_sysval_semantic sysval_semantic) +{ + return sysval_semantic >= VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE + && sysval_semantic <= VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN; +} + +static unsigned int shader_register_normalise_arrayed_addressing(struct vkd3d_shader_register *reg, + unsigned int id_idx, unsigned int register_index) +{ + assert(id_idx < ARRAY_SIZE(reg->idx) - 1); + + /* For a relative-addressed register index, move the id up a slot to separate it from the address, + * because rel_addr can be replaced with a constant offset in some cases. */ + if (reg->idx[id_idx].rel_addr) + { + reg->idx[id_idx + 1].rel_addr = NULL; + reg->idx[id_idx + 1].offset = reg->idx[id_idx].offset; + reg->idx[id_idx].offset -= register_index; + ++id_idx; + } + /* Otherwise we have no address for the arrayed register, so insert one. This happens e.g. where + * tessellation level registers are merged into an array because they're an array in SPIR-V. */ + else + { + ++id_idx; + memmove(®->idx[1], ®->idx[0], id_idx * sizeof(reg->idx[0])); + reg->idx[0].rel_addr = NULL; + reg->idx[0].offset = reg->idx[id_idx].offset - register_index; + } + + return id_idx; +} + +static int shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_param, bool is_io_dcl, + struct vkd3d_shader_normaliser *normaliser) + { + struct vkd3d_shader_register *reg = &dst_param->reg; + const struct vkd3d_shader_sm6_signature *signature; + const struct vkd3d_shader_sm6_signature_element *e; + struct vkd3d_shader_dst_param **dcl_params; + unsigned int id_idx, reg_idx, element_idx; + + if ((reg->type == VKD3DSPR_OUTPUT && normaliser_is_in_fork_or_join_phase(normaliser)) + || reg->type == VKD3DSPR_PATCHCONST) + { + signature = normaliser->patch_constant_signature; + /* Convert patch constant outputs to the patch constant register type to avoid the need + * to convert compiler symbols when accessed as inputs in a later stage. */ + reg->type = VKD3DSPR_PATCHCONST; + dcl_params = normaliser->pc_dcl_params; + } + else if (reg->type == VKD3DSPR_OUTPUT || dst_param->reg.type == VKD3DSPR_COLOROUT) + { + signature = normaliser->output_signature; + dcl_params = normaliser->output_dcl_params; + } + else if (dst_param->reg.type == VKD3DSPR_INCONTROLPOINT || dst_param->reg.type == VKD3DSPR_INPUT) + { + signature = normaliser->input_signature; + dcl_params = normaliser->input_dcl_params; + } + else + { + return 1; + } + + id_idx = reg->idx[1].offset != ~0u ? 1 : 0; + + reg_idx = reg->idx[id_idx].offset; + element_idx = shader_signature_find_element_for_reg(signature, reg_idx, dst_param->write_mask, normaliser); + if (element_idx == ~0u) + { + FIXME("Failed to find signature element for register %u and write mask %#x.\n", reg_idx, dst_param->write_mask); + return -1; + } + e = &signature->elements[element_idx]; + + dst_param->write_mask >>= vkd3d_write_mask_get_component_idx(e->mask); + if (is_io_dcl) + { + if (element_idx >= ARRAY_SIZE(normaliser->input_dcl_params)) + { + FIXME("Unsupported signature element index %u.\n", element_idx); + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_TOO_MANY_ELEMENTS, + "Signature element index %u exceeds the limit of %zu.\n", element_idx, + ARRAY_SIZE(normaliser->input_dcl_params)); + } + else if (dcl_params[element_idx]) + { + /* Merge split declarations into a single one. */ + dcl_params[element_idx]->write_mask |= dst_param->write_mask; + /* Turn this into a nop. */ + return 0; + } + else + { + dcl_params[element_idx] = dst_param; + } + } + + if (normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) + { + if (is_io_dcl) + { + /* Emit an array size for the control points for consistency with inputs. */ + reg->idx[0].offset = normaliser->output_control_point_count; + } + else + { + /* The control point id param. */ + assert(reg->idx[0].rel_addr); + } + id_idx = 1; + } + + if ((e->register_count > 1 || sysval_semantic_is_tess_factor(e->sysval_semantic))) + { + if (is_io_dcl) + { + /* For control point I/O, idx 0 contains the control point count. + * Ensure it is moved up to the next slot. */ + reg->idx[id_idx].offset = reg->idx[0].offset; + reg->idx[0].offset = e->register_count; + ++id_idx; + } + else + { + id_idx = shader_register_normalise_arrayed_addressing(reg, id_idx, e->register_index); + } + } + + /* Replace the register index with the signature element index */ + reg->idx[id_idx].offset = element_idx; + + return 1; +} + +static int shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_param, + struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i, id_idx, reg_idx, write_mask, element_idx, component_idx; + struct vkd3d_shader_register *reg = &src_param->reg; + const struct vkd3d_shader_sm6_signature *signature; + const struct vkd3d_shader_sm6_signature_element *e; + + /* Input/output registers from one phase can be used as inputs in + * subsequent phases. Specifically: + * + * - Control phase inputs are available as "vicp" in fork and join + * phases. + * - Control phase outputs are available as "vocp" in fork and join + * phases. + * - Fork phase patch constants are available as "vpc" in join + * phases. + * + * We handle "vicp" here by converting INCONTROLPOINT src registers to + * type INPUT so they match the control phase declarations. We handle + * "vocp" by converting OUTCONTROLPOINT registers to type OUTPUT. + * Merging fork and join phases handles "vpc". */ + + switch (reg->type) + { + case VKD3DSPR_PATCHCONST: + signature = normaliser->patch_constant_signature; + break; + case VKD3DSPR_INCONTROLPOINT: + if (normaliser->shader_type == VKD3D_SHADER_TYPE_HULL) + reg->type = VKD3DSPR_INPUT; + /* fall through */ + case VKD3DSPR_INPUT: + signature = normaliser->input_signature; + break; + case VKD3DSPR_OUTCONTROLPOINT: + if (normaliser->shader_type == VKD3D_SHADER_TYPE_HULL) + reg->type = VKD3DSPR_OUTPUT; + /* fall through */ + case VKD3DSPR_OUTPUT: + signature = normaliser->output_signature; + break; + default: + return 1; + } + + id_idx = reg->idx[1].offset != ~0u ? 1 : 0; + + reg_idx = reg->idx[id_idx].offset; + write_mask = VKD3DSP_WRITEMASK_0 << vkd3d_swizzle_get_component(src_param->swizzle, 0); + element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask, normaliser); + if (element_idx == ~0u) + { + FIXME("Failed to find signature element for register %u and write mask %#x.\n", reg_idx, write_mask); + return -1; + } + + e = &signature->elements[element_idx]; + if ((e->register_count > 1 || sysval_semantic_is_tess_factor(e->sysval_semantic))) + id_idx = shader_register_normalise_arrayed_addressing(reg, id_idx, e->register_index); + reg->idx[id_idx].offset = element_idx; + + if ((component_idx = vkd3d_write_mask_get_component_idx(e->mask))) + { + for (i = 0; i < VKD3D_VEC4_SIZE; ++i) + if (vkd3d_swizzle_get_component(src_param->swizzle, i)) + src_param->swizzle -= component_idx << VKD3D_SHADER_SWIZZLE_SHIFT(i); + } + + return 1; +} + +static enum vkd3d_result shader_instruction_normalise_io_params(struct vkd3d_shader_instruction *ins, + struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_register *reg; + unsigned int i; + int result = 1; + + normaliser->source_index = ins->source_index; + + switch (ins->handler_idx) + { + case VKD3DSIH_DCL_INPUT: + if (normaliser->shader_type == VKD3D_SHADER_TYPE_HULL) + { + reg = &ins->declaration.dst.reg; + /* We don't need to keep OUTCONTROLPOINT or PATCHCONST input declarations since their + * equivalents were declared earlier, but INCONTROLPOINT may be the first occurrence. */ + if (reg->type == VKD3DSPR_OUTCONTROLPOINT || reg->type == VKD3DSPR_PATCHCONST) + vkd3d_shader_instruction_make_nop(ins); + else if (reg->type == VKD3DSPR_INCONTROLPOINT) + reg->type = VKD3DSPR_INPUT; + } + /* fall through */ + case VKD3DSIH_DCL_INPUT_PS: + case VKD3DSIH_DCL_OUTPUT: + result = shader_dst_param_io_normalise(&ins->declaration.dst, true, normaliser); + break; + case VKD3DSIH_DCL_INPUT_SGV: + case VKD3DSIH_DCL_INPUT_SIV: + case VKD3DSIH_DCL_INPUT_PS_SGV: + case VKD3DSIH_DCL_INPUT_PS_SIV: + case VKD3DSIH_DCL_OUTPUT_SIV: + result = shader_dst_param_io_normalise(&ins->declaration.register_semantic.reg, true, + normaliser); + break; + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + normaliser->phase = ins->handler_idx; + memset(normaliser->input_dcl_params, 0, sizeof(normaliser->input_dcl_params)); + memset(normaliser->output_dcl_params, 0, sizeof(normaliser->output_dcl_params)); + memset(normaliser->pc_dcl_params, 0, sizeof(normaliser->pc_dcl_params)); + break; + default: + if (shader_instruction_is_dcl(ins)) + break; + for (i = 0; i < ins->dst_count; ++i) + result |= shader_dst_param_io_normalise((struct vkd3d_shader_dst_param *)&ins->dst[i], false, + normaliser); + for (i = 0; i < ins->src_count; ++i) + result |= shader_src_param_io_normalise((struct vkd3d_shader_src_param *)&ins->src[i], normaliser); + break; + } + + if (!result) + shader_instruction_init(ins, VKD3DSIH_NOP); + + return result >= 0 ? VKD3D_OK : VKD3D_ERROR_INVALID_SHADER; +} + +enum vkd3d_result shader_normaliser_normalise_io_registers(struct vkd3d_shader_normaliser *normaliser, + enum vkd3d_shader_type shader_type, struct vkd3d_shader_sm6_signature *input_signature, + struct vkd3d_shader_sm6_signature *output_signature, + struct vkd3d_shader_sm6_signature *patch_constant_signature) +{ + struct vkd3d_shader_instruction_array *instructions = &normaliser->instructions; + struct vkd3d_shader_instruction *ins; + enum vkd3d_result result = VKD3D_OK; + bool has_control_point_phase; + unsigned int i, j; + + normaliser->phase = VKD3DSIH_INVALID; + normaliser->shader_type = shader_type; + normaliser->input_signature = input_signature; + normaliser->output_signature = output_signature; + normaliser->patch_constant_signature = patch_constant_signature; + + for (i = 0, has_control_point_phase = false; i < instructions->count; ++i) + { + ins = &instructions->elements[i]; + normaliser->source_index = ins->source_index; + + switch (ins->handler_idx) + { + case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: + normaliser->output_control_point_count = ins->declaration.count; + break; + case VKD3DSIH_DCL_INDEX_RANGE: + shader_normaliser_add_index_range(normaliser, ins); + vkd3d_shader_instruction_make_nop(ins); + break; + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + has_control_point_phase = true; + /* fall through */ + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + normaliser->phase = ins->handler_idx; + break; + default: + break; + } + } + + if (normaliser->shader_type == VKD3D_SHADER_TYPE_HULL && !has_control_point_phase) + { + /* Inputs and outputs must match for the default phase, so merge ranges must match too. */ + for (i = 0; i < MAX_REG_OUTPUT; ++i) + { + for (j = 0; j < VKD3D_VEC4_SIZE; ++j) + { + if (!normaliser->input_range_map[i][j] && normaliser->output_range_map[i][j]) + normaliser->input_range_map[i][j] = normaliser->output_range_map[i][j]; + else if (normaliser->input_range_map[i][j] && !normaliser->output_range_map[i][j]) + normaliser->output_range_map[i][j] = normaliser->input_range_map[i][j]; + else if (normaliser->input_range_map[i][j] != normaliser->output_range_map[i][j]) + { + FIXME("Input and output range maps collide.\n"); + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_INVALID_INDEX_RANGE, + "Default input and output register ranges should match for index %u, component %u.\n", + i, j); + break; + } + } + } + } + + normaliser->source_index = 0; + if (!shader_signature_merge(input_signature, normaliser->input_range_map, false, normaliser) + || !shader_signature_merge(output_signature, normaliser->output_range_map, false, normaliser) + || !shader_signature_merge(patch_constant_signature, normaliser->pc_range_map, true, normaliser)) + { + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + normaliser->phase = VKD3DSIH_INVALID; + for (i = 0; i < normaliser->instructions.count && result >= 0; ++i) + result = shader_instruction_normalise_io_params(&normaliser->instructions.elements[i], normaliser); + + return (result >= 0 && normaliser->failed) ? VKD3D_ERROR_INVALID_SHADER : result; +} + void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser) { shader_instruction_array_destroy(&normaliser->instructions); diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 2834d307..045e490e 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1962,7 +1962,6 @@ struct vkd3d_symbol_register_data uint32_t member_idx; enum vkd3d_shader_component_type component_type; unsigned int write_mask; - uint32_t dcl_mask; unsigned int structure_stride; unsigned int binding_base_idx; bool is_aggregate; /* An aggregate, i.e. a structure or an array. */ @@ -2058,8 +2057,15 @@ static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol, symbol->type = VKD3D_SYMBOL_REGISTER; memset(&symbol->key, 0, sizeof(symbol->key)); symbol->key.reg.type = reg->type; - if ((vkd3d_shader_register_is_input(reg) || vkd3d_shader_register_is_output(reg)) && reg->idx[1].offset != ~0u) - symbol->key.reg.idx = reg->idx[1].offset; + if (vkd3d_shader_register_is_input(reg) || vkd3d_shader_register_is_output(reg) + || vkd3d_shader_register_is_patch_constant(reg)) + { + unsigned int i; + for (i = 2; i > 0; --i) + if (reg->idx[i].offset != ~0u) + break; + symbol->key.reg.idx = reg->idx[i].offset; + } else if (reg->type != VKD3DSPR_IMMCONSTBUFFER) symbol->key.reg.idx = reg->idx[0].offset; } @@ -2074,7 +2080,6 @@ static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol, symbol->info.reg.member_idx = 0; symbol->info.reg.component_type = component_type; symbol->info.reg.write_mask = write_mask; - symbol->info.reg.dcl_mask = 0; symbol->info.reg.structure_stride = 0; symbol->info.reg.binding_base_idx = 0; symbol->info.reg.is_aggregate = false; @@ -2243,9 +2248,9 @@ struct spirv_compiler const struct vkd3d_shader_spirv_target_info *spirv_target_info;
bool after_declarations_section; - const struct vkd3d_shader_sm6_signature *input_signature; - const struct vkd3d_shader_sm6_signature *output_signature; - const struct vkd3d_shader_sm6_signature *patch_constant_signature; + struct vkd3d_shader_sm6_signature input_signature; + struct vkd3d_shader_sm6_signature output_signature; + struct vkd3d_shader_sm6_signature patch_constant_signature; const struct vkd3d_shader_transform_feedback_info *xfb_info; struct vkd3d_shader_output_info { @@ -2422,9 +2427,9 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve
compiler->shader_type = shader_version->type;
- compiler->input_signature = &shader_desc->input_signature; - compiler->output_signature = &shader_desc->output_signature; - compiler->patch_constant_signature = &shader_desc->patch_constant_signature; + compiler->input_signature = shader_desc->input_signature; + compiler->output_signature = shader_desc->output_signature; + compiler->patch_constant_signature = shader_desc->patch_constant_signature;
if ((shader_interface = vkd3d_find_struct(compile_info->next, INTERFACE_INFO))) { @@ -2981,18 +2986,27 @@ static uint32_t spirv_compiler_emit_variable(struct spirv_compiler *compiler,
static uint32_t spirv_compiler_emit_array_variable(struct spirv_compiler *compiler, struct vkd3d_spirv_stream *stream, SpvStorageClass storage_class, - enum vkd3d_shader_component_type component_type, unsigned int component_count, unsigned int array_length) + enum vkd3d_shader_component_type component_type, unsigned int component_count, unsigned int array_length, + unsigned int outer_array_length) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, length_id, ptr_type_id;
- if (!array_length) + if (!array_length && !outer_array_length) return spirv_compiler_emit_variable(compiler, stream, storage_class, component_type, component_count);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count); - length_id = spirv_compiler_get_constant_uint(compiler, array_length); - type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); + if (array_length) + { + length_id = spirv_compiler_get_constant_uint(compiler, array_length); + type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); + } + if (outer_array_length) + { + length_id = spirv_compiler_get_constant_uint(compiler, outer_array_length); + type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); + } ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id); return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0); } @@ -3357,24 +3371,14 @@ static void spirv_compiler_emit_dereference_register(struct spirv_compiler *comp } else if (register_info->is_aggregate) { - if (reg->type == VKD3DSPR_INPUT || reg->type == VKD3DSPR_INCONTROLPOINT) - { - /* Indices for these are swapped compared to the generated SPIR-V. */ - if (reg->idx[1].offset != ~0u) - indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->idx[1]); - if (reg->idx[0].offset != ~0u) - indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->idx[0]); - } - else - { - struct vkd3d_shader_register_index reg_idx = reg->idx[0]; - - if (reg->idx[1].rel_addr) - FIXME("Relative addressing not implemented.\n"); - - reg_idx.offset = register_info->member_idx; - indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®_idx); - } + /* Indices for these are swapped compared to the generated SPIR-V. */ + if (reg->idx[2].offset != ~0u) + indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->idx[1]); + if (reg->idx[1].offset != ~0u) + indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->idx[0]); + if (!index_count) + /* A register sysval which is an array in SPIR-V, e.g. SAMPLEMASK. */ + indexes[index_count++] = spirv_compiler_get_constant_uint(compiler, 0); } else { @@ -4253,35 +4257,12 @@ static const struct vkd3d_spirv_builtin *vkd3d_get_spirv_builtin(const struct sp if ((builtin = get_spirv_builtin_for_register(reg_type))) return builtin;
- if (sysval != VKD3D_SIV_NONE || (reg_type != VKD3DSPR_OUTPUT && reg_type != VKD3DSPR_COLOROUT)) + if (sysval != VKD3D_SIV_NONE || (reg_type != VKD3DSPR_OUTPUT && reg_type != VKD3DSPR_COLOROUT + && reg_type != VKD3DSPR_PATCHCONST)) FIXME("Unhandled builtin (register type %#x, sysval %#x).\n", reg_type, sysval); return NULL; }
-static const struct vkd3d_shader_sm6_signature_element *vkd3d_find_signature_element_for_reg( - const struct vkd3d_shader_sm6_signature *signature, unsigned int *signature_element_index, - unsigned int reg_idx, DWORD write_mask) -{ - unsigned int signature_idx; - - for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx) - { - if (signature->elements[signature_idx].register_index == reg_idx - && (signature->elements[signature_idx].mask & write_mask) == write_mask) - { - if (signature_element_index) - *signature_element_index = signature_idx; - return &signature->elements[signature_idx]; - } - } - - FIXME("Could not find shader signature element (register %u, write mask %#x).\n", - reg_idx, write_mask); - if (signature_element_index) - *signature_element_index = ~0u; - return NULL; -} - static uint32_t spirv_compiler_get_invocation_id(struct spirv_compiler *compiler) { struct vkd3d_shader_register r; @@ -4402,7 +4383,8 @@ static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *compiler, - const struct vkd3d_spirv_builtin *builtin, SpvStorageClass storage_class, unsigned int array_size) + const struct vkd3d_spirv_builtin *builtin, SpvStorageClass storage_class, unsigned int array_size, + unsigned int outer_array_length) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t id; @@ -4411,7 +4393,7 @@ static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *comp
id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, storage_class, - builtin->component_type, builtin->component_count, array_size); + builtin->component_type, builtin->component_count, array_size, outer_array_length); vkd3d_spirv_add_iface_variable(builder, id); spirv_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
@@ -4423,54 +4405,41 @@ static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *comp return id; }
-static bool needs_private_io_variable(const struct vkd3d_shader_sm6_signature *signature, - unsigned int reg_idx, const struct vkd3d_spirv_builtin *builtin, - unsigned int *component_count, unsigned int *out_write_mask) +static bool needs_private_io_variable(const struct vkd3d_spirv_builtin *builtin) { - unsigned int write_mask = 0; - bool have_sysval = false; - unsigned int i, count; - - /* Always use private variables for arrayed builtins. These are generally - * scalars on the D3D side, so would need extra array indices when - * accessing them. It may be feasible to insert those indices at the point - * where the builtins are used, but it's not clear it's worth the effort. */ - if (builtin && (builtin->spirv_array_size || builtin->fixup_pfn)) - return true; - - if (*component_count == VKD3D_VEC4_SIZE) - return false; - - for (i = 0, count = 0; i < signature->element_count; ++i) - { - const struct vkd3d_shader_sm6_signature_element *current = &signature->elements[i]; - - if (current->register_index != reg_idx) - continue; + return builtin && builtin->fixup_pfn; +}
- write_mask |= current->mask; - ++count; +static unsigned int shader_sm6_signature_next_location(const struct vkd3d_shader_sm6_signature *signature) +{ + unsigned int i, max_row;
- if (current->sysval_semantic) - have_sysval = true; - } + if (!signature) + return 0;
- if (count == 1) - return false; + for (i = 0, max_row = 0; i < signature->element_count; ++i) + max_row = max(max_row, signature->elements[i].register_index + signature->elements[i].register_count); + return max_row; +}
- if (builtin || have_sysval) - return true; +static unsigned int shader_register_get_io_indices(const struct vkd3d_shader_register *reg, + unsigned int *array_size, unsigned int *outer_array_size) +{ + unsigned int i, element_idx;
- if (!vkd3d_bitmask_is_contiguous(write_mask)) + *outer_array_size = 0; + *array_size = 0; + element_idx = reg->idx[0].offset; + for (i = 1; i < 3; ++i) { - FIXME("Write mask %#x is non-contiguous.\n", write_mask); - return true; + if (reg->idx[i].offset == ~0u) + break; + *outer_array_size = *array_size; + *array_size = element_idx; + element_idx = reg->idx[i].offset; }
- assert(vkd3d_write_mask_component_count(write_mask) >= *component_count); - *component_count = vkd3d_write_mask_component_count(write_mask); - *out_write_mask = write_mask; - return false; + return element_idx; }
static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, @@ -4480,46 +4449,29 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, const struct vkd3d_shader_sm6_signature_element *signature_element; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_sm6_signature *shader_signature; + unsigned int array_size, outer_array_size, element_idx; const struct vkd3d_shader_register *reg = &dst->reg; unsigned int component_idx, input_component_count; enum vkd3d_shader_component_type component_type; uint32_t type_id, ptr_type_id, float_type_id; const struct vkd3d_spirv_builtin *builtin; + unsigned int write_mask, reg_write_mask; struct vkd3d_symbol *symbol = NULL; uint32_t val_id, input_id, var_id; struct vkd3d_symbol reg_symbol; - struct vkd3d_symbol tmp_symbol; SpvStorageClass storage_class; struct rb_entry *entry = NULL; bool use_private_var = false; - unsigned int write_mask; - unsigned int array_size; - unsigned int reg_idx; uint32_t i, index;
assert(!reg->idx[0].rel_addr); assert(!reg->idx[1].rel_addr);
- if (reg->idx[1].offset != ~0u) - { - array_size = reg->idx[0].offset; - reg_idx = reg->idx[1].offset; - } - else - { - array_size = 0; - reg_idx = reg->idx[0].offset; - } - shader_signature = reg->type == VKD3DSPR_PATCHCONST - ? compiler->patch_constant_signature : compiler->input_signature; + ? &compiler->patch_constant_signature : &compiler->input_signature;
- if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature, - NULL, reg_idx, dst->write_mask))) - { - FIXME("No signature element for shader input, ignoring shader input.\n"); - return 0; - } + element_idx = shader_register_get_io_indices(reg, &array_size, &outer_array_size); + signature_element = &shader_signature->elements[element_idx];
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && !sysval && signature_element->sysval_semantic) sysval = vkd3d_siv_from_sysval(signature_element->sysval_semantic); @@ -4541,12 +4493,16 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, component_idx = vkd3d_write_mask_get_component_idx(signature_element->mask); }
- if (needs_private_io_variable(shader_signature, reg_idx, builtin, &input_component_count, &write_mask) - && (compiler->shader_type != VKD3D_SHADER_TYPE_HULL - || (reg->type != VKD3DSPR_INCONTROLPOINT && reg->type != VKD3DSPR_PATCHCONST))) + if (needs_private_io_variable(builtin)) + { use_private_var = true; + reg_write_mask = write_mask; + } else + { component_idx = vkd3d_write_mask_get_component_idx(write_mask); + reg_write_mask = write_mask >> component_idx; + }
storage_class = SpvStorageClassInput;
@@ -4554,101 +4510,59 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) { + /* Except for vicp there should be one declaration per signature element. Sources of + * duplicate declarations are: a single register split into multiple declarations having + * different components, which should have been merged, and declarations in one phase + * being repeated in another (i.e. vcp/vocp), which should have been deleted. */ + if (reg->type != VKD3DSPR_INPUT || !is_in_fork_or_join_phase(compiler)) + FIXME("Duplicate input definition found.\n"); symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - input_id = symbol->id; - } - else if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL - && (reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_PATCHCONST)) - { - /* Input/output registers from one phase can be used as inputs in - * subsequent phases. Specifically: - * - * - Control phase inputs are available as "vicp" in fork and join - * phases. - * - Control phase outputs are available as "vocp" in fork and join - * phases. - * - Fork phase patch constants are available as "vpc" in join - * phases. - * - * We handle "vicp" and "vpc" here by creating aliases to the shader's - * global inputs and outputs. We handle "vocp" in - * spirv_compiler_leave_shader_phase(). */ - - tmp_symbol = reg_symbol; - if (reg->type == VKD3DSPR_PATCHCONST) - tmp_symbol.key.reg.type = VKD3DSPR_OUTPUT; - else - tmp_symbol.key.reg.type = VKD3DSPR_INPUT; - - if ((entry = rb_get(&compiler->symbol_table, &tmp_symbol))) - { - symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - tmp_symbol = *symbol; - tmp_symbol.key.reg.type = reg->type; - spirv_compiler_put_symbol(compiler, &tmp_symbol); - - input_id = symbol->id; - } - else - { - if (reg->type == VKD3DSPR_PATCHCONST) - ERR("Patch constant register %u was not declared in a previous phase.\n", reg_idx); - else - ERR("Input control point register %u was not declared in a previous phase.\n", reg_idx); - } + return symbol->id; }
- if (!symbol || ~symbol->info.reg.dcl_mask & write_mask) + if (builtin) { - if (builtin) - { - input_id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size); - if (reg->type == VKD3DSPR_PATCHCONST) - vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); - } - else - { - unsigned int location = reg_idx; - - input_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - storage_class, component_type, input_component_count, array_size); - vkd3d_spirv_add_iface_variable(builder, input_id); - if (reg->type == VKD3DSPR_PATCHCONST) - { - vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); - location += compiler->input_signature->element_count; - } - vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, location); - if (component_idx) - vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx); - - spirv_compiler_emit_interpolation_decorations(compiler, input_id, interpolation_mode); - } + input_id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size, + outer_array_size); + if (reg->type == VKD3DSPR_PATCHCONST) + vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); } - - if (!symbol) + else { - var_id = input_id; - if (use_private_var) + unsigned int location = signature_element->register_index; + + input_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, + storage_class, component_type, input_component_count, array_size, outer_array_size); + vkd3d_spirv_add_iface_variable(builder, input_id); + if (reg->type == VKD3DSPR_PATCHCONST) { - storage_class = SpvStorageClassPrivate; - var_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, array_size); + vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); + location += shader_sm6_signature_next_location(&compiler->input_signature); } + vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, location); + if (component_idx) + vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx);
- vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, - use_private_var ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, - use_private_var ? VKD3DSP_WRITEMASK_ALL : write_mask); - reg_symbol.info.reg.dcl_mask |= write_mask; - spirv_compiler_put_symbol(compiler, ®_symbol); - - spirv_compiler_emit_register_debug_name(builder, var_id, reg); + spirv_compiler_emit_interpolation_decorations(compiler, input_id, interpolation_mode); } - else + + var_id = input_id; + if (use_private_var) { - symbol->info.reg.dcl_mask |= write_mask; + storage_class = SpvStorageClassPrivate; + var_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, + storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, array_size, outer_array_size); }
+ vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, + use_private_var ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, + use_private_var ? VKD3DSP_WRITEMASK_ALL : reg_write_mask); + reg_symbol.info.reg.is_aggregate = array_size || outer_array_size; + assert(!builtin || !builtin->spirv_array_size || use_private_var || array_size || outer_array_size); + spirv_compiler_put_symbol(compiler, ®_symbol); + + spirv_compiler_emit_register_debug_name(builder, var_id, reg); + if (use_private_var) { type_id = vkd3d_spirv_get_type_id(builder, component_type, input_component_count); @@ -4673,7 +4587,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id); index = spirv_compiler_get_constant_uint(compiler, builtin->member_idx); val_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, input_id, index); - dst_reg.idx[0].offset = reg_idx + i; + dst_reg.idx[0].offset = element_idx + i; } val_id = vkd3d_spirv_build_op_load(builder, type_id, val_id, SpvMemoryAccessMaskNone);
@@ -4723,12 +4637,11 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler, if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) return;
- input_id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassInput, 0); + input_id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassInput, 0, 0);
write_mask = vkd3d_write_mask_from_component_count(builtin->component_count); vkd3d_symbol_set_register_info(®_symbol, input_id, SpvStorageClassInput, builtin->component_type, write_mask); - reg_symbol.info.reg.dcl_mask = write_mask; reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size; spirv_compiler_put_symbol(compiler, ®_symbol); spirv_compiler_emit_register_debug_name(builder, input_id, reg); @@ -4798,38 +4711,10 @@ static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_sm6_s *mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index); }
-static uint32_t calculate_sysval_array_mask(struct spirv_compiler *compiler, - const struct vkd3d_shader_sm6_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval) -{ - const struct vkd3d_shader_sm6_signature_element *e; - const struct vkd3d_spirv_builtin *sig_builtin; - const struct vkd3d_spirv_builtin *builtin; - uint32_t signature_idx, mask = 0; - - if (!(builtin = get_spirv_builtin_for_sysval(compiler, sysval))) - { - FIXME("Unhandled sysval %#x.\n", sysval); - return 0; - } - - for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx) - { - e = &signature->elements[signature_idx]; - - sig_builtin = get_spirv_builtin_for_sysval(compiler, - vkd3d_siv_from_sysval_indexed(e->sysval_semantic, e->semantic_index)); - - if (sig_builtin && sig_builtin->spirv_builtin == builtin->spirv_builtin) - mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * sig_builtin->member_idx); - } - - return mask; -} - /* Emits arrayed SPIR-V built-in variables. */ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *compiler) { - const struct vkd3d_shader_sm6_signature *output_signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *output_signature = &compiler->output_signature; uint32_t clip_distance_mask = 0, clip_distance_id = 0; uint32_t cull_distance_mask = 0, cull_distance_id = 0; const struct vkd3d_spirv_builtin *builtin; @@ -4859,7 +4744,7 @@ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler * count = vkd3d_popcount(clip_distance_mask); builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SIV_CLIP_DISTANCE); clip_distance_id = spirv_compiler_emit_builtin_variable(compiler, - builtin, SpvStorageClassOutput, count); + builtin, SpvStorageClassOutput, count, 0); }
if (cull_distance_mask) @@ -4867,7 +4752,7 @@ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler * count = vkd3d_popcount(cull_distance_mask); builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SIV_CULL_DISTANCE); cull_distance_id = spirv_compiler_emit_builtin_variable(compiler, - builtin, SpvStorageClassOutput, count); + builtin, SpvStorageClassOutput, count, 0); }
for (i = 0; i < output_signature->element_count; ++i) @@ -4914,13 +4799,12 @@ static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler, return; }
- output_id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0); + output_id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0, 0);
vkd3d_symbol_make_register(®_symbol, reg); write_mask = vkd3d_write_mask_from_component_count(builtin->component_count); vkd3d_symbol_set_register_info(®_symbol, output_id, SpvStorageClassOutput, builtin->component_type, write_mask); - reg_symbol.info.reg.dcl_mask = write_mask; reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size; spirv_compiler_put_symbol(compiler, ®_symbol); spirv_compiler_emit_register_execution_mode(compiler, reg); @@ -4943,7 +4827,7 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c if (variable_id && *variable_id) return *variable_id;
- id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0); + id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0, 0); if (is_in_fork_or_join_phase(compiler)) vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
@@ -4962,36 +4846,28 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, unsigned int component_idx, output_component_count; enum vkd3d_shader_component_type component_type; const struct vkd3d_spirv_builtin *builtin; - struct vkd3d_symbol *symbol = NULL; + unsigned int array_size, outer_array_size; + unsigned int write_mask, reg_write_mask; bool use_private_variable = false; struct vkd3d_symbol reg_symbol; SpvStorageClass storage_class; - struct rb_entry *entry = NULL; - unsigned int signature_idx; - unsigned int write_mask; - unsigned int array_size; + unsigned int element_idx; bool is_patch_constant; uint32_t id, var_id;
is_patch_constant = is_in_fork_or_join_phase(compiler);
- shader_signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature; + shader_signature = is_patch_constant ? &compiler->patch_constant_signature : &compiler->output_signature;
- array_size = is_in_control_point_phase(compiler) ? compiler->output_control_point_count : 0; - - if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature, - &signature_idx, reg->idx[0].offset, dst->write_mask))) - { - FIXME("No signature element for shader output, ignoring shader output.\n"); - return; - } + element_idx = shader_register_get_io_indices(reg, &array_size, &outer_array_size); + signature_element = &shader_signature->elements[element_idx];
builtin = vkd3d_get_spirv_builtin(compiler, dst->reg.type, sysval);
write_mask = signature_element->mask;
- component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask); - output_component_count = vkd3d_write_mask_component_count(signature_element->mask); + component_idx = vkd3d_write_mask_get_component_idx(write_mask); + output_component_count = vkd3d_write_mask_component_count(write_mask); if (builtin) { component_type = builtin->component_type; @@ -5007,116 +4883,97 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, storage_class = SpvStorageClassOutput;
if (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE - || needs_private_io_variable(shader_signature, signature_element->register_index, - builtin, &output_component_count, &write_mask) - || is_patch_constant) + || (compiler->output_info[element_idx].id && compiler->output_info[element_idx].array_element_mask) + || needs_private_io_variable(builtin)) + { use_private_variable = true; + reg_write_mask = write_mask; + } else + { component_idx = vkd3d_write_mask_get_component_idx(write_mask); + reg_write_mask = write_mask >> component_idx; + }
vkd3d_symbol_make_register(®_symbol, reg);
- if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) + if (rb_get(&compiler->symbol_table, ®_symbol)) { - symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - id = symbol->id; + /* See spirv_compiler_emit_input() for possible causes. */ + FIXME("Duplicate output definition found.\n"); + return; }
- if (!symbol || ~symbol->info.reg.dcl_mask & write_mask) + if (compiler->output_info[element_idx].id) { - if (compiler->output_info[signature_idx].id) - { - id = compiler->output_info[signature_idx].id; - if (compiler->output_info[signature_idx].array_element_mask) - use_private_variable = true; - } - else if (builtin) - { - if (spirv_compiler_get_current_shader_phase(compiler)) - id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, builtin); - else - id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size); - - if (builtin->spirv_array_size) - compiler->output_info[signature_idx].array_element_mask = - calculate_sysval_array_mask(compiler, shader_signature, sysval); - - spirv_compiler_emit_register_execution_mode(compiler, &dst->reg); - } + id = compiler->output_info[element_idx].id; + } + else if (builtin) + { + if (spirv_compiler_get_current_shader_phase(compiler)) + id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, builtin); else - { - unsigned int location = reg->idx[0].offset; + id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size, outer_array_size);
- if (is_patch_constant) - location += compiler->output_signature->element_count; + spirv_compiler_emit_register_execution_mode(compiler, &dst->reg); + } + else + { + unsigned int location = signature_element->register_index;
- id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - storage_class, component_type, output_component_count, array_size); - vkd3d_spirv_add_iface_variable(builder, id); + if (is_patch_constant) + location += shader_sm6_signature_next_location(&compiler->output_signature);
- if (is_dual_source_blending(compiler) && reg->idx[0].offset < 2) - { - vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, 0); - vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationIndex, reg->idx[0].offset); - } - else - { - vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, location); - } + id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, + storage_class, component_type, output_component_count, array_size, outer_array_size); + vkd3d_spirv_add_iface_variable(builder, id);
- if (component_idx) - vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx); + if (is_dual_source_blending(compiler) && signature_element->register_index < 2) + { + vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, 0); + vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationIndex, signature_element->register_index); + } + else + { + vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, location); }
- if (is_patch_constant) - vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0); - - spirv_compiler_decorate_xfb_output(compiler, id, output_component_count, signature_element); - - compiler->output_info[signature_idx].id = id; - compiler->output_info[signature_idx].component_type = component_type; + if (component_idx) + vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx); }
- if (!symbol) - { - var_id = id; - if (use_private_variable) - storage_class = SpvStorageClassPrivate; - if (is_patch_constant) - var_id = compiler->hs.patch_constants_id; - else if (use_private_variable) - var_id = spirv_compiler_emit_variable(compiler, &builder->global_stream, - storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE); + if (is_patch_constant) + vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
- vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, - use_private_variable ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, - use_private_variable ? VKD3DSP_WRITEMASK_ALL : write_mask); - reg_symbol.info.reg.is_aggregate = use_private_variable ? is_patch_constant : array_size; - if (is_patch_constant) - { - reg_symbol.info.reg.member_idx = reg->idx[0].offset; - } - reg_symbol.info.reg.dcl_mask = write_mask; + spirv_compiler_decorate_xfb_output(compiler, id, output_component_count, signature_element);
- spirv_compiler_put_symbol(compiler, ®_symbol); + compiler->output_info[element_idx].id = id; + compiler->output_info[element_idx].component_type = component_type;
- if (!is_patch_constant) - spirv_compiler_emit_register_debug_name(builder, var_id, reg); - } - else + var_id = id; + if (use_private_variable) { - symbol->info.reg.dcl_mask |= write_mask; - var_id = symbol->id; + storage_class = SpvStorageClassPrivate; + var_id = spirv_compiler_emit_variable(compiler, &builder->global_stream, + storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE); }
+ vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, + use_private_variable ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, + use_private_variable ? VKD3DSP_WRITEMASK_ALL : reg_write_mask); + reg_symbol.info.reg.is_aggregate = array_size || outer_array_size; + assert(!builtin || !builtin->spirv_array_size || use_private_variable || array_size || outer_array_size); + + spirv_compiler_put_symbol(compiler, ®_symbol); + + if (!is_patch_constant) + spirv_compiler_emit_register_debug_name(builder, var_id, reg); + if (use_private_variable) { - unsigned int idx = spirv_compiler_get_output_variable_index(compiler, reg->idx[0].offset); + unsigned int idx = spirv_compiler_get_output_variable_index(compiler, element_idx); compiler->private_output_variable[idx] = var_id; compiler->private_output_variable_write_mask[idx] |= dst->write_mask; - if (is_patch_constant) - compiler->private_output_variable_array_idx[idx] = spirv_compiler_get_constant_uint( - compiler, reg->idx[0].offset); if (!compiler->epilogue_function_id) compiler->epilogue_function_id = vkd3d_spirv_alloc_id(builder); } @@ -5168,6 +5025,9 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi use_mask |= element->used_mask; } } + index = vkd3d_write_mask_get_component_idx(output->mask); + dst_write_mask >>= index; + use_mask >>= index; write_mask &= dst_write_mask;
if (!write_mask) @@ -5251,7 +5111,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler *
is_patch_constant = is_in_fork_or_join_phase(compiler);
- signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature; + signature = is_patch_constant ? &compiler->patch_constant_signature : &compiler->output_signature;
function_id = compiler->epilogue_function_id;
@@ -5290,8 +5150,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * if (!compiler->output_info[i].id) continue;
- variable_idx = spirv_compiler_get_output_variable_index(compiler, - signature->elements[i].register_index); + variable_idx = spirv_compiler_get_output_variable_index(compiler, i); if (!param_id[variable_idx]) continue;
@@ -5321,24 +5180,6 @@ static void spirv_compiler_emit_hull_shader_builtins(struct spirv_compiler *comp spirv_compiler_emit_input_register(compiler, &dst); }
-static void spirv_compiler_emit_hull_shader_patch_constants(struct spirv_compiler *compiler) -{ - const struct vkd3d_shader_sm6_signature *signature = compiler->patch_constant_signature; - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t register_count = 0; - unsigned int signature_idx; - - for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx) - register_count = max(register_count, signature->elements[signature_idx].register_index + 1); - - if (!register_count) - return; - - compiler->hs.patch_constants_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - SpvStorageClassPrivate, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, register_count); - vkd3d_spirv_build_op_name(builder, compiler->hs.patch_constants_id, "opc"); -} - static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler) { const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info; @@ -5352,7 +5193,6 @@ static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *comp case VKD3D_SHADER_TYPE_HULL: vkd3d_spirv_set_execution_model(builder, SpvExecutionModelTessellationControl); spirv_compiler_emit_hull_shader_builtins(compiler); - spirv_compiler_emit_hull_shader_patch_constants(compiler); break; case VKD3D_SHADER_TYPE_DOMAIN: vkd3d_spirv_set_execution_model(builder, SpvExecutionModelTessellationEvaluation); @@ -5381,8 +5221,6 @@ static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *comp if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) { vkd3d_spirv_builder_begin_main_function(builder); - - spirv_compiler_emit_shader_signature_outputs(compiler); } }
@@ -5469,7 +5307,7 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
id = spirv_compiler_emit_array_variable(compiler, &builder->function_stream, - SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, temp->register_size); + SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, temp->register_size, 0);
spirv_compiler_emit_register_debug_name(builder, id, ®);
@@ -6171,7 +6009,8 @@ static void spirv_compiler_emit_dcl_output(struct spirv_compiler *compiler, { const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst;
- if (vkd3d_shader_register_is_output(&dst->reg)) + if (vkd3d_shader_register_is_output(&dst->reg) + || (is_in_fork_or_join_phase(compiler) && vkd3d_shader_register_is_patch_constant(&dst->reg))) spirv_compiler_emit_output(compiler, dst, VKD3D_SIV_NONE); else spirv_compiler_emit_output_register(compiler, dst); @@ -6189,64 +6028,6 @@ static void spirv_compiler_emit_dcl_output_siv(struct spirv_compiler *compiler, spirv_compiler_emit_output(compiler, dst, sysval); }
-static bool spirv_compiler_check_index_range(struct spirv_compiler *compiler, - const struct vkd3d_shader_index_range *range) -{ - const struct vkd3d_shader_register *reg = &range->dst.reg; - struct vkd3d_shader_register_info reg_info; - struct vkd3d_shader_register current_reg; - struct vkd3d_symbol reg_symbol; - unsigned int i; - uint32_t id; - - current_reg = *reg; - vkd3d_symbol_make_register(®_symbol, ¤t_reg); - if (!spirv_compiler_get_register_info(compiler, ¤t_reg, ®_info)) - { - ERR("Failed to get register info.\n"); - return false; - } - - /* FIXME: We should check if it's an array. */ - if (!reg_info.is_aggregate) - { - FIXME("Unhandled register %#x.\n", reg->type); - return false; - } - id = reg_info.id; - - for (i = reg->idx[0].offset; i < reg->idx[0].offset + range->register_count; ++i) - { - current_reg.idx[0].offset = i; - vkd3d_symbol_make_register(®_symbol, ¤t_reg); - - if (range->dst.write_mask != reg_info.write_mask - || vkd3d_write_mask_component_count(reg_info.write_mask) != 1) - { - FIXME("Unhandled index range write mask %#x (%#x).\n", - range->dst.write_mask, reg_info.write_mask); - return false; - } - - if (reg_info.id != id) - { - FIXME("Unhandled index range %#x, %u.\n", reg->type, i); - return false; - } - } - - return true; -} - -static void spirv_compiler_emit_dcl_index_range(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) -{ - const struct vkd3d_shader_index_range *range = &instruction->declaration.index_range; - - if (!spirv_compiler_check_index_range(compiler, range)) - FIXME("Ignoring dcl_index_range %#x %u.\n", range->dst.reg.type, range->register_count); -} - static void spirv_compiler_emit_dcl_stream(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { @@ -6310,7 +6091,7 @@ static void spirv_compiler_emit_point_size(struct spirv_compiler *compiler) || compiler->write_tess_geom_point_size) { vkd3d_spirv_build_op_store(&compiler->spirv_builder, - spirv_compiler_emit_builtin_variable(compiler, &point_size, SpvStorageClassOutput, 0), + spirv_compiler_emit_builtin_variable(compiler, &point_size, SpvStorageClassOutput, 0, 0), spirv_compiler_get_constant_float(compiler, 1.0f), SpvMemoryAccessMaskNone); } } @@ -6446,12 +6227,8 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile
static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) { - const struct vkd3d_shader_sm6_signature *signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *signature = &compiler->output_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - struct vkd3d_symbol reg_symbol, *symbol; - struct vkd3d_shader_register reg; - struct rb_entry *entry; - unsigned int i;
if (is_in_control_point_phase(compiler) && compiler->emit_default_control_point_phase) spirv_compiler_emit_default_control_point_phase(compiler); @@ -6461,11 +6238,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) compiler->temp_id = 0; compiler->temp_count = 0;
- /* - * vocp inputs in fork and join shader phases are outputs of the control - * point phase. Reinsert symbols for vocp registers while leaving the - * control point phase. - */ if (is_in_control_point_phase(compiler)) { if (compiler->epilogue_function_id) @@ -6474,42 +6246,12 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) spirv_compiler_emit_shader_epilogue_function(compiler); }
- memset(®, 0, sizeof(reg)); - /* Fork and join phases share output registers (patch constants). * Control point phase has separate output registers. */ memset(compiler->output_info, 0, signature->element_count * sizeof(*compiler->output_info)); memset(compiler->private_output_variable, 0, sizeof(compiler->private_output_variable)); memset(compiler->private_output_variable_array_idx, 0, sizeof(compiler->private_output_variable_array_idx)); memset(compiler->private_output_variable_write_mask, 0, sizeof(compiler->private_output_variable_write_mask)); - - for (i = 0; i < signature->element_count; ++i) - { - const struct vkd3d_shader_sm6_signature_element *e = &signature->elements[i]; - - reg.type = VKD3DSPR_OUTPUT; - reg.idx[0].offset = e->register_index; - reg.idx[1].offset = ~0u; - vkd3d_symbol_make_register(®_symbol, ®); - if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) - { - rb_remove(&compiler->symbol_table, entry); - - symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - - reg.type = VKD3DSPR_OUTCONTROLPOINT; - reg.idx[1].offset = reg.idx[0].offset; - reg.idx[0].offset = compiler->output_control_point_count; - vkd3d_symbol_make_register(symbol, ®); - symbol->info.reg.is_aggregate = false; - - if (rb_put(&compiler->symbol_table, symbol, entry) == -1) - { - ERR("Failed to insert vocp symbol entry (%s).\n", debug_vkd3d_symbol(symbol)); - vkd3d_symbol_free(entry, NULL); - } - } - } } }
@@ -6548,15 +6290,15 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) { - const struct vkd3d_shader_sm6_signature *output_signature = compiler->output_signature; - const struct vkd3d_shader_sm6_signature *input_signature = compiler->input_signature; + const struct vkd3d_shader_sm6_signature *output_signature = &compiler->output_signature; + const struct vkd3d_shader_sm6_signature *input_signature = &compiler->input_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; enum vkd3d_shader_component_type component_type; struct vkd3d_shader_src_param invocation; + unsigned int component_count, array_size; struct vkd3d_shader_register input_reg; uint32_t type_id, output_ptr_type_id; uint32_t input_id, output_id, dst_id; - unsigned int component_count; uint32_t invocation_id; unsigned int i;
@@ -6586,18 +6328,22 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile assert(input->mask == output->mask); assert(input->component_type == output->component_type);
- input_reg.idx[1].offset = input->register_index; + input_reg.idx[1].offset = i; input_id = spirv_compiler_get_register_id(compiler, &input_reg);
component_type = output->component_type; component_count = vkd3d_write_mask_component_count(output->mask); - output_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - SpvStorageClassOutput, component_type, component_count, compiler->output_control_point_count); + type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count); + if ((array_size = (input->register_count > 1) ? input->register_count : 0)) + type_id = vkd3d_spirv_get_op_type_array(builder, type_id, spirv_compiler_get_constant_uint(compiler, + array_size)); + + output_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, SpvStorageClassOutput, + component_type, component_count, array_size, compiler->output_control_point_count); vkd3d_spirv_add_iface_variable(builder, output_id); vkd3d_spirv_build_op_decorate1(builder, output_id, SpvDecorationLocation, output->register_index); vkd3d_spirv_build_op_name(builder, output_id, "vocp%u", output->register_index);
- type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count); output_ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id); dst_id = vkd3d_spirv_build_op_access_chain1(builder, output_ptr_type_id, output_id, invocation_id);
@@ -9402,9 +9148,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_OUTPUT_SIV: spirv_compiler_emit_dcl_output_siv(compiler, instruction); break; - case VKD3DSIH_DCL_INDEX_RANGE: - spirv_compiler_emit_dcl_index_range(compiler, instruction); - break; case VKD3DSIH_DCL_STREAM: spirv_compiler_emit_dcl_stream(compiler, instruction); break; @@ -9700,17 +9443,24 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, compiler->location.column = 0; compiler->location.line = 1;
- if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + shader_normaliser_init(&normaliser, instructions, compiler->message_context); + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL + && (result = shader_normaliser_flatten_hull_shader_phases(&normaliser)) >= 0) { - shader_normaliser_init(&normaliser, instructions); - if ((result = shader_normaliser_flatten_hull_shader_phases(&normaliser)) >= 0) - result = shader_normaliser_normalise_hull_shader_control_point_io(&normaliser, - &parser->shader_desc.input_signature); - instructions = &normaliser.instructions; - - if (result >= 0 && TRACE_ON()) - vkd3d_shader_trace(instructions, &parser->shader_version); + result = shader_normaliser_normalise_hull_shader_control_point_io(&normaliser, + &parser->shader_desc.input_signature); } + if (result >= 0) + result = shader_normaliser_normalise_io_registers(&normaliser, parser->shader_version.type, + &compiler->input_signature, &compiler->output_signature, &compiler->patch_constant_signature); + + instructions = &normaliser.instructions; + + if (result >= 0 && TRACE_ON()) + vkd3d_shader_trace(instructions, &parser->shader_version); + + if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) + spirv_compiler_emit_shader_signature_outputs(compiler);
for (i = 0; i < instructions->count && result >= 0; ++i) { @@ -9718,8 +9468,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]); }
- if (instructions == &normaliser.instructions) - shader_normaliser_destroy(&normaliser); + shader_normaliser_destroy(&normaliser);
if (result < 0) return result; diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 9895ec3e..171aa943 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2206,6 +2206,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi return VKD3D_ERROR_OUT_OF_MEMORY; } ins = &instructions->elements[instructions->count]; + ins->source_index = instructions->count; shader_sm4_read_instruction(sm4, ins);
if (ins->handler_idx == VKD3DSIH_INVALID) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index ab59061e..6967a27d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -140,6 +140,14 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY = 7004,
VKD3D_SHADER_WARNING_D3DBC_IGNORED_INSTRUCTION_FLAGS= 7300, + + VKD3D_SHADER_ERROR_IR_TOO_MANY_REGISTERS = 8000, + VKD3D_SHADER_ERROR_IR_INVALID_IO_REGISTER = 8001, + VKD3D_SHADER_ERROR_IR_INVALID_INDEX_RANGE = 8002, + VKD3D_SHADER_ERROR_IR_UNKNOWN_INDEX_RANGE_TYPE = 8003, + VKD3D_SHADER_ERROR_IR_TOO_MANY_ELEMENTS = 8004, + + VKD3D_SHADER_WARNING_IR_MASK_NOT_CONTIGUOUS = 8300, };
enum vkd3d_shader_opcode @@ -777,6 +785,7 @@ enum vkd3d_shader_input_sysval_semantic
struct vkd3d_shader_sm6_signature_element { + unsigned int sort_index; const char *semantic_name; unsigned int semantic_index; unsigned int stream_index; @@ -908,6 +917,7 @@ struct vkd3d_shader_instruction unsigned int resource_stride; enum vkd3d_data_type resource_data_type[VKD3D_VEC4_SIZE]; bool coissue, structured, raw; + unsigned int source_index; const struct vkd3d_shader_src_param *predicate; union { @@ -950,6 +960,11 @@ static inline bool vkd3d_shader_register_is_output(const struct vkd3d_shader_reg return reg->type == VKD3DSPR_OUTPUT || reg->type == VKD3DSPR_COLOROUT; }
+static inline bool vkd3d_shader_register_is_patch_constant(const struct vkd3d_shader_register *reg) +{ + return reg->type == VKD3DSPR_PATCHCONST; +} + struct vkd3d_shader_location { const char *source_name; @@ -1356,7 +1371,15 @@ int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code);
struct vkd3d_shader_normaliser { + struct vkd3d_shader_message_context *message_context; + unsigned int source_index; + bool failed; + struct vkd3d_shader_instruction_array instructions; + enum vkd3d_shader_type shader_type; + struct vkd3d_shader_sm6_signature *input_signature; + struct vkd3d_shader_sm6_signature *output_signature; + struct vkd3d_shader_sm6_signature *patch_constant_signature;
unsigned int max_temp_count; unsigned int temp_dcl_idx; @@ -1364,15 +1387,27 @@ struct vkd3d_shader_normaliser unsigned int instance_count; unsigned int phase_body_idx; enum vkd3d_shader_opcode phase; + unsigned int output_control_point_count;
struct vkd3d_shader_src_param *outpointid_param; + + struct vkd3d_shader_dst_param *input_dcl_params[MAX_REG_OUTPUT]; + struct vkd3d_shader_dst_param *output_dcl_params[MAX_REG_OUTPUT]; + struct vkd3d_shader_dst_param *pc_dcl_params[MAX_REG_OUTPUT]; + uint8_t input_range_map[MAX_REG_OUTPUT][VKD3D_VEC4_SIZE]; + uint8_t output_range_map[MAX_REG_OUTPUT][VKD3D_VEC4_SIZE]; + uint8_t pc_range_map[MAX_REG_OUTPUT][VKD3D_VEC4_SIZE]; };
void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser, - struct vkd3d_shader_instruction_array *instructions); + struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_message_context *message_context); enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shader_normaliser *normaliser); enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struct vkd3d_shader_normaliser *normaliser, const struct vkd3d_shader_sm6_signature *input_signature); +enum vkd3d_result shader_normaliser_normalise_io_registers(struct vkd3d_shader_normaliser *normaliser, + enum vkd3d_shader_type shader_type, struct vkd3d_shader_sm6_signature *input_signature, + struct vkd3d_shader_sm6_signature *output_signature, + struct vkd3d_shader_sm6_signature *patch_constant_signature); void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser);
#endif /* __VKD3D_SHADER_PRIVATE_H */ diff --git a/tests/d3d12.c b/tests/d3d12.c index 23e1e97c..1eb17a96 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -36457,7 +36457,6 @@ static void test_vs_ps_relative_addressing(void)
transition_resource_state(command_list, context.render_target, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); - todo check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
ID3D12Resource_Release(vb);
Unfortunately I see no reasonable way to split the last patch. It's all interdependent.
I haven't quite made it through all the changes in patch 4/4, but some initial comments:
From patch 1/4:
+void vkd3d_shader_sm6_free_shader_signature(struct vkd3d_shader_sm6_signature *signature) +{ + vkd3d_free(signature->elements); + signature->elements = NULL; +}
If this were part of the public API, this should be called "vkd3d_shader_free_sm6_signature()"; for an internal API, the convention would be "vkd3d_shader_sm6_signature_cleanup()". We (Zeb, mostly) have also been omitting the vkd3d_/vkd3d_shader_ prefix on new (module) internal API. I'm not too bothered by either variant, but if you prefer, you could also go with "struct sm6_signature" and "sm6_signature_cleanup()".
+static bool shader_signature_from_shader_sm6_signature(struct vkd3d_shader_signature *signature, + const struct vkd3d_shader_sm6_signature *src) +{ [...] + if (!(signature->elements = vkd3d_malloc(signature->element_count * sizeof(*signature->elements)))) + return false;
This works, but only because sizeof(*signature->elements) is smaller than sizeof(*src->elements). That may be more fragile than we care for; we'd normally use vkd3d_calloc() here, like shader_parse_signature() does.
From patch 2/4:
+ static const DWORD vs_code[] = + { +#if 0 + uint3 index; + + struct vs_data + { + float4 pos : SV_Position; + float4 color[3] : COLOR; + }; + + void main(in struct vs_data vs_input, out struct vs_data vs_output) + { + vs_output.pos = vs_input.pos; + vs_output.color[0] = vs_input.color[index.x]; + vs_output.color[1] = vs_input.color[index.y]; + vs_output.color[2] = vs_input.color[index.z]; + } +#endif [...] + }; + static const D3D12_SHADER_BYTECODE vs = {vs_code, sizeof(vs_code)}; + static const DWORD ps_code[] = + { +#if 0 + uint4 index; + + struct ps_data + { + float4 pos : SV_Position; + float4 color[3] : COLOR; + }; + + float4 main(struct ps_data ps_input) : SV_Target + { + return ps_input.color[index.w]; + } +#endif [..] + };
Perhaps the answer is simply "no", but is there any chance the HLSL compiler is already (or soon...) able to compile these and we could use something like hlsl_d3d12.c's "compile_shader" for these?
From patch 3/4:
+ /* The normaliser requires the highest slot free in some cases. */ + switch (param->type) + { + case VKD3DSPR_INPUT: + case VKD3DSPR_OUTPUT: + case VKD3DSPR_COLOROUT: + case VKD3DSPR_INCONTROLPOINT: + case VKD3DSPR_OUTCONTROLPOINT: + case VKD3DSPR_PATCHCONST: + vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_PARAM_ORDER_TOO_HIGH, + "Unexpected I/O parameter order greater than 2.\n"); + break; + }
It's not introduced by this patch, but unfortunately I only notice this issue now: It seems that during the vkd3d_shader_instruction_array conversion a number of checks for "parser->failed" ended up getting dropped. In a lot of cases we also set VKD3DSIH_INVALID, and some of the remaining checks end up catching that and mitigating the issue, but we should be checking for that flag in vkd3d_shader_sm4_parser_create() and vkd3d_shader_sm1_parser_create().
Both the comment and the error message are perhaps slightly inaccurate; from the point of view of the parser, the issue here is that (depending on the shader type and potentially the phase) shader registers have a particular dimension. Addressing them using either more or fewer indices would be invalid. Perhaps we don't immediately need to be quite that strict (although I suppose we could extend register_type_table[] to include the required information), but I think the error should essentially be something along the lines of "invalid index count for register type".
From patch 4/4:
+static void VKD3D_PRINTF_FUNC(3, 4) shader_normaliser_error(struct vkd3d_shader_normaliser *normaliser, + enum vkd3d_shader_error error, const char *format, ...) +{ + struct vkd3d_shader_location location = {NULL, normaliser->source_index + 1, 0}; + va_list args; + + va_start(args, format); + vkd3d_shader_verror(normaliser->message_context, &location, error, format, args); + va_end(args); + normaliser->failed = true; +}
That drops the original "source_name" field. We should be able to store that in the vkd3d_shader_instruction_array structure, but we could also just store a vkd3d_shader_location structure inside the vkd3d_shader_instruction structure, which the normaliser could then point to. This can all be tested with vkd3d-compiler and an appropriate shader, of course.
+static unsigned int shader_signature_find_element_for_reg(const struct vkd3d_shader_sm6_signature *signature, + unsigned int reg_idx, unsigned int write_mask, struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int signature_idx; + + for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx) + { [...] + } + + shader_normaliser_error(normaliser, VKD3D_SHADER_ERROR_IR_INVALID_IO_REGISTER, + "Could not find signature element matching register %u and write mask %#x.\n", reg_idx, write_mask); + return ~0u; +}
Technically we're iterating over signature elements above, not signatures; that makes "signature_idx" perhaps a bit awkward as a variable name. We could also just use something like "i", of course.
I think we could return a pointer to the element itself here, instead of the index. (Like vkd3d_shader_find_signature_element(), incidentally.) All the current callers seem to just use the index to get at the element.
Somewhat similarly, it probably makes sense to call shader_normaliser_error() from the callers instead of here. On the one hand, all the callers already do some error handling anyway, while on the other hand I could imagine callers potentially being able to give better error messages than we can here.
+static int signature_element_mask_compare(const void *a, const void *b) +{ + const struct vkd3d_shader_sm6_signature_element *e = a, *f = b; + + if (e->mask == f->mask) + return vkd3d_u32_compare(e->register_index, f->register_index); + return vkd3d_u32_compare(e->mask, f->mask); +}
The code above works, but it is a bit unusual. The usual way to write that would be:
```c if ((ret = vkd3d_u32_compare(e->mask, f->mask))) return ret; return vkd3d_u32_compare(e->register_index, f->register_index); ```
+static bool merge_sysval_semantics(struct vkd3d_shader_sm6_signature_element *e, + struct vkd3d_shader_sm6_signature_element *f) +{ [...] +}
Despite the name, this function does not merge anything. Also, the parameters could be const.
Unfortunately I see no reasonable way to split the last patch. It's all interdependent.
Introducing "source_index" seem reasonably separate, at least.
We (Zeb, mostly) have also been omitting the vkd3d_/vkd3d_shader_ prefix on new (module) internal API. I'm not too bothered by either variant, but if you prefer, you could also go with "struct sm6_signature" and "sm6_signature_cleanup()".
My reasoning is that firstly, I like a clear distinction between what is and isn't external API, and secondly, typing out vkd3d_shader everywhere makes names annoyingly long.
I've said this a few times, but along the same lines, I'd like to propose giving struct vkd3d_shader_instruction (and related structures / functions) a different, shorter prefix in place of "vkd3d_shader". Some ideas: - "ir" (to match the file name. Granted, this isn't the only IR in vkd3d-shader, but it's also probably the only one that will have a generic role in every transformation), - "vsir" (an abbreviation of "vkd3d-shader IR"), - "vazir" (a more cute/clever name, Persian for "minister" but which I understand can also mean something close to "helper" or "assistant", which seems quite fitting. I've tried to also make it into an acronym but the 'z' makes things difficult).
Perhaps the answer is simply "no", but is there any chance the HLSL compiler is already (or soon...) able to compile these and we could use something like hlsl_d3d12.c's "compile_shader" for these?
We need to handle array semantics (148, which I've signed off on and is hopefully just waiting for Gio's sign-off) and then relative addressing (which isn't done but looks pretty easy). I'm of the opinion it shouldn't block this patch, though.
FWIW, given the simplicity of the test it should even be possible to port it to a shader_test file :-)