-- v12: vkd3d-shader/ir: Normalise signatures and input/output registers to the Shader Model 6 pattern. vkd3d-shader/ir: Eliminate struct vkd3d_shader_normaliser. vkd3d-shader/spirv: Support emitting multi-dimensional array variables.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 54 ++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 18 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index fa4d056e..22c6d4c3 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2981,18 +2981,26 @@ 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, + const unsigned int *array_lengths, unsigned int length_count) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, length_id, ptr_type_id; + unsigned int i;
- if (!array_length) + if (!length_count) 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); + for (i = 0; i < length_count; ++i) + { + if (!array_lengths[i]) + continue; + length_id = spirv_compiler_get_constant_uint(compiler, array_lengths[i]); + 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); } @@ -4401,17 +4409,21 @@ static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationOffset, offset); }
-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) +static uint32_t spirv_compiler_emit_builtin_variable_v(struct spirv_compiler *compiler, + const struct vkd3d_spirv_builtin *builtin, SpvStorageClass storage_class, const unsigned int *array_sizes, + unsigned int size_count) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + unsigned int sizes[2]; uint32_t id;
- array_size = max(array_size, builtin->spirv_array_size); + assert(size_count <= ARRAY_SIZE(sizes)); + memcpy(sizes, array_sizes, size_count * sizeof(sizes[0])); + array_sizes = sizes; + sizes[0] = max(sizes[0], builtin->spirv_array_size);
- id = spirv_compiler_emit_array_variable(compiler, - &builder->global_stream, storage_class, - builtin->component_type, builtin->component_count, array_size); + id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, storage_class, + builtin->component_type, builtin->component_count, array_sizes, size_count); vkd3d_spirv_add_iface_variable(builder, id); spirv_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
@@ -4423,6 +4435,12 @@ static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *comp return id; }
+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) +{ + return spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, &array_size, 1); +} + static bool needs_private_io_variable(const struct shader_signature *signature, unsigned int reg_idx, const struct vkd3d_spirv_builtin *builtin, unsigned int *component_count, unsigned int *out_write_mask) @@ -4602,7 +4620,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, { if (builtin) { - input_id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size); + input_id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, &array_size, 1); if (reg->type == VKD3DSPR_PATCHCONST) vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); } @@ -4611,7 +4629,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, 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); + storage_class, component_type, input_component_count, &array_size, 1); vkd3d_spirv_add_iface_variable(builder, input_id); if (reg->type == VKD3DSPR_PATCHCONST) { @@ -4633,7 +4651,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, { 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); + storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &array_size, 1); }
vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, @@ -5034,7 +5052,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, 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); + id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, &array_size, 1);
if (builtin->spirv_array_size) compiler->output_info[signature_idx].array_element_mask = @@ -5050,7 +5068,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, location += compiler->output_signature->element_count;
id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - storage_class, component_type, output_component_count, array_size); + storage_class, component_type, output_component_count, &array_size, 1); vkd3d_spirv_add_iface_variable(builder, id);
if (is_dual_source_blending(compiler) && reg->idx[0].offset < 2) @@ -5334,7 +5352,7 @@ static void spirv_compiler_emit_hull_shader_patch_constants(struct spirv_compile 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); + SpvStorageClassPrivate, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, ®ister_count, 1); vkd3d_spirv_build_op_name(builder, compiler->hs.patch_constants_id, "opc"); }
@@ -5468,7 +5486,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, 1);
spirv_compiler_emit_register_debug_name(builder, id, ®);
@@ -6568,7 +6586,7 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile 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); + SpvStorageClassOutput, component_type, component_count, &compiler->output_control_point_count, 1); 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);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/ir.c | 110 +++++++++++++---------- libs/vkd3d-shader/spirv.c | 15 ++-- libs/vkd3d-shader/vkd3d_shader_private.h | 23 +---- 3 files changed, 76 insertions(+), 72 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index e431dddd..83b310c3 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -85,14 +85,21 @@ static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_i shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, instance_id); }
-static bool normaliser_is_in_control_point_phase(const struct vkd3d_shader_normaliser *normaliser) +struct hull_flattener { - return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; -} + struct vkd3d_shader_instruction_array instructions; + + unsigned int max_temp_count; + unsigned int temp_dcl_idx; + + unsigned int instance_count; + unsigned int phase_body_idx; + enum vkd3d_shader_opcode phase; +};
-static bool normaliser_is_in_fork_or_join_phase(const struct vkd3d_shader_normaliser *normaliser) +static bool flattener_is_in_fork_or_join_phase(const struct hull_flattener *flattener) { - return normaliser->phase == VKD3DSIH_HS_FORK_PHASE || normaliser->phase == VKD3DSIH_HS_JOIN_PHASE; + return flattener->phase == VKD3DSIH_HS_FORK_PHASE || flattener->phase == VKD3DSIH_HS_JOIN_PHASE; }
struct shader_phase_location @@ -109,7 +116,7 @@ struct shader_phase_location_array unsigned int count; };
-static void shader_normaliser_eliminate_phase_related_dcls(struct vkd3d_shader_normaliser *normaliser, +static void flattener_eliminate_phase_related_dcls(struct hull_flattener *normaliser, unsigned int index, struct shader_phase_location_array *locations) { struct vkd3d_shader_instruction *ins = &normaliser->instructions.elements[index]; @@ -118,7 +125,7 @@ static void shader_normaliser_eliminate_phase_related_dcls(struct vkd3d_shader_n
if (ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) { - b = normaliser_is_in_fork_or_join_phase(normaliser); + b = flattener_is_in_fork_or_join_phase(normaliser); /* Reset the phase info. */ normaliser->phase_body_idx = ~0u; normaliser->phase = ins->handler_idx; @@ -173,7 +180,7 @@ static void shader_normaliser_eliminate_phase_related_dcls(struct vkd3d_shader_n } }
-static enum vkd3d_result shader_normaliser_flatten_phases(struct vkd3d_shader_normaliser *normaliser, +static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser, struct shader_phase_location_array *locations) { struct shader_phase_location *loc; @@ -246,46 +253,55 @@ static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum v ins->handler_idx = handler_idx; }
-void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser, - struct vkd3d_shader_instruction_array *instructions) +enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions) { - memset(normaliser, 0, sizeof(*normaliser)); - normaliser->phase = VKD3DSIH_INVALID; - normaliser->instructions = *instructions; - memset(instructions, 0, sizeof(*instructions)); -} - -enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shader_normaliser *normaliser) -{ - struct vkd3d_shader_instruction_array *instructions = &normaliser->instructions; + struct hull_flattener flattener = {*src_instructions}; + struct vkd3d_shader_instruction_array *instructions; struct shader_phase_location_array locations; enum vkd3d_result result = VKD3D_OK; unsigned int i;
+ instructions = &flattener.instructions; + + flattener.phase = VKD3DSIH_INVALID; for (i = 0, locations.count = 0; i < instructions->count; ++i) - shader_normaliser_eliminate_phase_related_dcls(normaliser, i, &locations); + flattener_eliminate_phase_related_dcls(&flattener, i, &locations);
- if ((result = shader_normaliser_flatten_phases(normaliser, &locations)) < 0) + if ((result = flattener_flatten_phases(&flattener, &locations)) < 0) return result;
- if (normaliser->phase != VKD3DSIH_INVALID) + if (flattener.phase != VKD3DSIH_INVALID) { - if (normaliser->temp_dcl_idx) - instructions->elements[normaliser->temp_dcl_idx].declaration.count = normaliser->max_temp_count; + if (flattener.temp_dcl_idx) + instructions->elements[flattener.temp_dcl_idx].declaration.count = flattener.max_temp_count;
- if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + 1)) + if (!shader_instruction_array_reserve(&flattener.instructions, flattener.instructions.count + 1)) return VKD3D_ERROR_OUT_OF_MEMORY; shader_instruction_init(&instructions->elements[instructions->count++], VKD3DSIH_RET); }
+ *src_instructions = flattener.instructions; return result; }
-static struct vkd3d_shader_src_param *shader_normaliser_create_outpointid_param(struct vkd3d_shader_normaliser *normaliser) +struct control_point_normaliser +{ + struct vkd3d_shader_instruction_array instructions; + enum vkd3d_shader_opcode phase; + struct vkd3d_shader_src_param *outpointid_param; +}; + +static bool control_point_normaliser_is_in_control_point_phase(const struct control_point_normaliser *normaliser) +{ + return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +} + +static struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( + struct vkd3d_shader_instruction_array *instructions) { struct vkd3d_shader_src_param *rel_addr;
- if (!(rel_addr = shader_src_param_allocator_get(&normaliser->instructions.src_params, 1))) + if (!(rel_addr = shader_src_param_allocator_get(&instructions->src_params, 1))) return NULL;
shader_register_init(&rel_addr->reg, VKD3DSPR_OUTPOINTID, VKD3D_DATA_UINT, 0); @@ -296,11 +312,11 @@ static struct vkd3d_shader_src_param *shader_normaliser_create_outpointid_param( }
static void shader_dst_param_normalise_outpointid(struct vkd3d_shader_dst_param *dst_param, - struct vkd3d_shader_normaliser *normaliser) + struct control_point_normaliser *normaliser) { struct vkd3d_shader_register *reg = &dst_param->reg;
- if (normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) + if (control_point_normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) { /* The TPF reader validates idx_count. */ assert(reg->idx_count == 1); @@ -321,7 +337,7 @@ static void shader_dst_param_io_init(struct vkd3d_shader_dst_param *param, const shader_register_init(¶m->reg, reg_type, vkd3d_data_type_from_component_type(e->component_type), idx_count); }
-static enum vkd3d_result shader_normaliser_emit_hs_input(struct vkd3d_shader_normaliser *normaliser, +static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_point_normaliser *normaliser, const struct shader_signature *s, unsigned int input_control_point_count, unsigned int dst) { struct vkd3d_shader_instruction *ins; @@ -372,22 +388,26 @@ static enum vkd3d_result shader_normaliser_emit_hs_input(struct vkd3d_shader_nor return VKD3D_OK; }
-enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struct vkd3d_shader_normaliser *normaliser, - const struct shader_signature *input_signature) +enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( + struct vkd3d_shader_instruction_array *src_instructions, const struct shader_signature *input_signature) { - struct vkd3d_shader_instruction_array *instructions = &normaliser->instructions; + struct vkd3d_shader_instruction_array *instructions; + struct control_point_normaliser normaliser; unsigned int input_control_point_count; struct vkd3d_shader_instruction *ins; + enum vkd3d_result ret; unsigned int i, j;
- if (!(normaliser->outpointid_param = shader_normaliser_create_outpointid_param(normaliser))) + if (!(normaliser.outpointid_param = instruction_array_create_outpointid_param(src_instructions))) { ERR("Failed to allocate src param.\n"); return VKD3D_ERROR_OUT_OF_MEMORY; } + normaliser.instructions = *src_instructions; + instructions = &normaliser.instructions; + normaliser.phase = VKD3DSIH_INVALID;
- normaliser->phase = VKD3DSIH_INVALID; - for (i = 0; i < normaliser->instructions.count; ++i) + for (i = 0; i < normaliser.instructions.count; ++i) { ins = &instructions->elements[i];
@@ -396,18 +416,18 @@ enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struc case VKD3DSIH_HS_CONTROL_POINT_PHASE: case VKD3DSIH_HS_FORK_PHASE: case VKD3DSIH_HS_JOIN_PHASE: - normaliser->phase = ins->handler_idx; + normaliser.phase = ins->handler_idx; break; default: if (shader_instruction_is_dcl(ins)) break; for (j = 0; j < ins->dst_count; ++j) - shader_dst_param_normalise_outpointid((struct vkd3d_shader_dst_param *)&ins->dst[j], normaliser); + shader_dst_param_normalise_outpointid((struct vkd3d_shader_dst_param *)&ins->dst[j], &normaliser); break; } }
- normaliser->phase = VKD3DSIH_INVALID; + normaliser.phase = VKD3DSIH_INVALID; input_control_point_count = 1;
for (i = 0; i < instructions->count; ++i) @@ -420,19 +440,19 @@ enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struc input_control_point_count = ins->declaration.count; break; case VKD3DSIH_HS_CONTROL_POINT_PHASE: + *src_instructions = normaliser.instructions; return VKD3D_OK; case VKD3DSIH_HS_FORK_PHASE: case VKD3DSIH_HS_JOIN_PHASE: - return shader_normaliser_emit_hs_input(normaliser, input_signature, input_control_point_count, i); + ret = control_point_normaliser_emit_hs_input(&normaliser, input_signature, + input_control_point_count, i); + *src_instructions = normaliser.instructions; + return ret; default: break; } }
+ *src_instructions = normaliser.instructions; return VKD3D_OK; } - -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 22c6d4c3..e76b5d54 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9689,7 +9689,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct vkd3d_shader_instruction_array *instructions = &parser->instructions; const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - struct vkd3d_shader_normaliser normaliser; + struct vkd3d_shader_instruction_array normalised_instructions; enum vkd3d_result result = VKD3D_OK; unsigned int i;
@@ -9698,11 +9698,12 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { - 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, + normalised_instructions = parser->instructions; + memset(&parser->instructions, 0, sizeof(parser->instructions)); + instructions = &normalised_instructions; + if ((result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0) + result = instruction_array_normalise_hull_shader_control_point_io(instructions, &parser->shader_desc.input_signature); - instructions = &normaliser.instructions;
if (result >= 0 && TRACE_ON()) vkd3d_shader_trace(instructions, &parser->shader_version); @@ -9714,8 +9715,8 @@ 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); + if (instructions == &normalised_instructions) + shader_instruction_array_destroy(&normalised_instructions);
if (result < 0) return result; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 0f294d21..77b62def 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1363,25 +1363,8 @@ void dxbc_writer_add_section(struct dxbc_writer *dxbc, uint32_t tag, const void void dxbc_writer_init(struct dxbc_writer *dxbc); int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code);
-struct vkd3d_shader_normaliser -{ - struct vkd3d_shader_instruction_array instructions; - - unsigned int max_temp_count; - unsigned int temp_dcl_idx; - - unsigned int instance_count; - unsigned int phase_body_idx; - enum vkd3d_shader_opcode phase; - - struct vkd3d_shader_src_param *outpointid_param; -}; - -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 shader_signature *input_signature); -void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser); +enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *instructions); +enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( + struct vkd3d_shader_instruction_array *instructions, const struct shader_signature *input_signature);
#endif /* __VKD3D_SHADER_PRIVATE_H */
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/dxbc.c | 2 + libs/vkd3d-shader/ir.c | 615 ++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 688 ++++++++--------------- libs/vkd3d-shader/vkd3d_shader_private.h | 9 + tests/d3d12.c | 1 - 5 files changed, 845 insertions(+), 470 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 743ba369..3e3f06fa 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -373,6 +373,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 83b310c3..d542fbb0 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -456,3 +456,618 @@ enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( *src_instructions = normaliser.instructions; return VKD3D_OK; } + +struct io_normaliser +{ + struct vkd3d_shader_instruction_array instructions; + enum vkd3d_shader_type shader_type; + struct shader_signature *input_signature; + struct shader_signature *output_signature; + struct shader_signature *patch_constant_signature; + + unsigned int max_temp_count; + unsigned int temp_dcl_idx; + + 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]; +}; + +static bool io_normaliser_is_in_fork_or_join_phase(const struct io_normaliser *normaliser) +{ + return normaliser->phase == VKD3DSIH_HS_FORK_PHASE || normaliser->phase == VKD3DSIH_HS_JOIN_PHASE; +} + +static bool io_normaliser_is_in_control_point_phase(const struct io_normaliser *normaliser) +{ + return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +} + +static unsigned int shader_signature_find_element_for_reg(const struct shader_signature *signature, + unsigned int reg_idx, unsigned int write_mask) +{ + unsigned int i; + + for (i = 0; i < signature->element_count; ++i) + { + struct signature_element *e = &signature->elements[i]; + if (e->register_index <= reg_idx && e->register_index + e->register_count > reg_idx + && (e->mask & write_mask) == write_mask) + { + return i; + } + } + + /* Validated in the TPF reader. */ + vkd3d_unreachable(); +} + +static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE], + unsigned int register_idx, unsigned int write_mask) +{ + return range_map[register_idx][vkd3d_write_mask_get_component_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) +{ + 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); + + assert(register_idx < MAX_REG_OUTPUT && MAX_REG_OUTPUT - register_idx >= register_count); + + if (range_map[register_idx][component_idx] > register_count && is_dcl_indexrange) + { + /* Validated in the TPF reader. */ + assert(range_map[register_idx][component_idx] != UINT8_MAX); + 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; + /* 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. + * The latter is validated in the TPF reader. */ + assert(!range_map[r][c] || !is_dcl_indexrange); + range_map[r][c] = UINT8_MAX; + } + } +} + +static void io_normaliser_add_index_range(struct io_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; + unsigned int reg_idx, write_mask, element_idx; + const struct shader_signature *signature; + uint8_t (*range_map)[VKD3D_VEC4_SIZE]; + + 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 (!io_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: + /* Validated in the TPF reader. */ + vkd3d_unreachable(); + } + + reg_idx = reg->idx[reg->idx_count - 1].offset; + write_mask = range->dst.write_mask; + element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); + range_map_set_register_range(range_map, reg_idx, range->register_count, + signature->elements[element_idx].mask, true); +} + +static int signature_element_mask_compare(const void *a, const void *b) +{ + const struct signature_element *e = a, *f = b; + int ret; + + return (ret = vkd3d_u32_compare(e->mask, f->mask)) ? ret : vkd3d_u32_compare(e->register_index, f->register_index); +} + +static bool sysval_semantics_should_merge(const struct signature_element *e, const struct 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 shader_signature *s, + uint8_t range_map[][VKD3D_VEC4_SIZE]) +{ + struct 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 || !sysval_semantics_should_merge(e, f)) + break; + } + if (register_count < 2) + continue; + + range_map_set_register_range(range_map, e->register_index, register_count, e->mask, false); + } +} + +static int signature_element_register_compare(const void *a, const void *b) +{ + const struct 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 signature_element *e = a, *f = b; + + return vkd3d_u32_compare(e->sort_index, f->sort_index); +} + +static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map[][VKD3D_VEC4_SIZE], + bool is_patch_constant) +{ + unsigned int i, j, element_count, new_count, register_count; + struct signature_element *elements; + struct 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) > 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) > 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); + + 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); + 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 bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_param, bool is_io_dcl, + struct io_normaliser *normaliser) + { + unsigned int id_idx, reg_idx, write_mask, element_idx; + struct vkd3d_shader_register *reg = &dst_param->reg; + struct vkd3d_shader_dst_param **dcl_params; + const struct shader_signature *signature; + const struct signature_element *e; + + if ((reg->type == VKD3DSPR_OUTPUT && io_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 true; + } + + id_idx = reg->idx_count - 1; + reg_idx = reg->idx[id_idx].offset; + write_mask = dst_param->write_mask; + element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); + e = &signature->elements[element_idx]; + + dst_param->write_mask >>= vkd3d_write_mask_get_component_idx(e->mask); + if (is_io_dcl) + { + /* Validated in the TPF reader. */ + assert(element_idx < ARRAY_SIZE(normaliser->input_dcl_params)); + + 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 false; + } + else + { + dcl_params[element_idx] = dst_param; + } + } + + if (io_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; + reg->idx_count = id_idx + 1; + + return true; +} + +static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_param, + struct io_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 shader_signature *signature; + const struct 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; + } + + id_idx = reg->idx_count - 1; + 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); + + 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; + reg->idx_count = id_idx + 1; + + 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); + } +} + +static void shader_instruction_normalise_io_params(struct vkd3d_shader_instruction *ins, + struct io_normaliser *normaliser) +{ + struct vkd3d_shader_register *reg; + bool keep = true; + unsigned int i; + + 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: + keep = 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: + keep = 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) + shader_dst_param_io_normalise((struct vkd3d_shader_dst_param *)&ins->dst[i], false, normaliser); + for (i = 0; i < ins->src_count; ++i) + shader_src_param_io_normalise((struct vkd3d_shader_src_param *)&ins->src[i], normaliser); + break; + } + + if (!keep) + shader_instruction_init(ins, VKD3DSIH_NOP); +} + +enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_shader_instruction_array *instructions, + enum vkd3d_shader_type shader_type, struct shader_signature *input_signature, + struct shader_signature *output_signature, struct shader_signature *patch_constant_signature) +{ + struct io_normaliser normaliser = {*instructions}; + struct vkd3d_shader_instruction *ins; + 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]; + + 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: + io_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 assert(normaliser.input_range_map[i][j] == normaliser.output_range_map[i][j]); + } + } + } + + if (!shader_signature_merge(input_signature, normaliser.input_range_map, false) + || !shader_signature_merge(output_signature, normaliser.output_range_map, false) + || !shader_signature_merge(patch_constant_signature, normaliser.pc_range_map, true)) + { + *instructions = normaliser.instructions; + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + normaliser.phase = VKD3DSIH_INVALID; + for (i = 0; i < normaliser.instructions.count; ++i) + shader_instruction_normalise_io_params(&normaliser.instructions.elements[i], &normaliser); + + *instructions = normaliser.instructions; + return VKD3D_OK; +} diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index e76b5d54..ed24e743 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 shader_signature *input_signature; - const struct shader_signature *output_signature; - const struct shader_signature *patch_constant_signature; + struct shader_signature input_signature; + struct shader_signature output_signature; + struct shader_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))) { @@ -3365,24 +3370,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 { @@ -4261,35 +4256,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 signature_element *vkd3d_find_signature_element_for_reg( - const struct shader_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; @@ -4441,54 +4413,41 @@ static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *comp return spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, &array_size, 1); }
-static bool needs_private_io_variable(const struct shader_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 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_signature_next_location(const struct shader_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_sizes) +{ + unsigned int i, element_idx;
- if (!vkd3d_bitmask_is_contiguous(write_mask)) + array_sizes[0] = 0; + array_sizes[1] = 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; + array_sizes[1] = array_sizes[0]; + array_sizes[0] = 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, @@ -4503,41 +4462,25 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, 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; + unsigned int array_sizes[2]; + unsigned int element_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_sizes); + 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); @@ -4559,12 +4502,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;
@@ -4572,111 +4519,68 @@ 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_v(compiler, builtin, storage_class, &array_size, 1); - 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, 1); - 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_v(compiler, builtin, storage_class, array_sizes, 2); + 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_sizes, 2); + 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, 1); + vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); + location += shader_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_sizes, 2); }
+ 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_sizes[0] || array_sizes[1]; + assert(!builtin || !builtin->spirv_array_size || use_private_var || array_sizes[0] || array_sizes[1]); + 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); - for (i = 0; i < max(array_size, 1); ++i) + for (i = 0; i < max(array_sizes[0], 1); ++i) { struct vkd3d_shader_register dst_reg = *reg; dst_reg.data_type = VKD3D_DATA_FLOAT;
val_id = input_id; - if (array_size) + if (array_sizes[0]) { ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id); index = spirv_compiler_get_constant_uint(compiler, i); @@ -4691,7 +4595,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);
@@ -4746,7 +4650,6 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler, 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); @@ -4776,15 +4679,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil } }
-static unsigned int spirv_compiler_get_output_variable_index( - struct spirv_compiler *compiler, unsigned int register_idx) -{ - if (register_idx == ~0u) /* oDepth */ - return ARRAY_SIZE(compiler->private_output_variable) - 1; - assert(register_idx < ARRAY_SIZE(compiler->private_output_variable) - 1); - return register_idx; -} - static unsigned int get_shader_output_swizzle(const struct spirv_compiler *compiler, unsigned int register_idx) { @@ -4815,38 +4709,10 @@ static void calculate_clip_or_cull_distance_mask(const struct signature_element *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 shader_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval) -{ - const struct vkd3d_spirv_builtin *sig_builtin; - const struct vkd3d_spirv_builtin *builtin; - const struct signature_element *e; - 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 shader_signature *output_signature = compiler->output_signature; + const struct shader_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; @@ -4937,7 +4803,6 @@ static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler, 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); @@ -4979,36 +4844,28 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, enum vkd3d_shader_component_type component_type; const struct shader_signature *shader_signature; const struct vkd3d_spirv_builtin *builtin; - struct vkd3d_symbol *symbol = NULL; + 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 array_sizes[2]; + 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_sizes); + 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; @@ -5024,116 +4881,96 @@ 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_v(compiler, builtin, storage_class, &array_size, 1); - - 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_v(compiler, builtin, storage_class, array_sizes, 2);
- 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, 1); - vkd3d_spirv_add_iface_variable(builder, id); + if (is_patch_constant) + location += shader_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_sizes, 2); + 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_sizes[0] || array_sizes[1]; + assert(!builtin || !builtin->spirv_array_size || use_private_variable || array_sizes[0] || array_sizes[1]); + + 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); - 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); + compiler->private_output_variable[element_idx] = var_id; + compiler->private_output_variable_write_mask[element_idx] |= reg_write_mask; if (!compiler->epilogue_function_id) compiler->epilogue_function_id = vkd3d_spirv_alloc_id(builder); } @@ -5185,6 +5022,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) @@ -5259,7 +5099,6 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * uint32_t output_index_id = 0; bool is_patch_constant; unsigned int i, count; - DWORD variable_idx;
STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_id)); STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_type_id)); @@ -5268,7 +5107,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;
@@ -5307,14 +5146,12 @@ 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); - if (!param_id[variable_idx]) + if (!param_id[i]) continue;
spirv_compiler_emit_store_shader_output(compiler, signature, &signature->elements[i], &compiler->output_info[i], output_index_id, - param_id[variable_idx], compiler->private_output_variable_write_mask[variable_idx]); + param_id[i], compiler->private_output_variable_write_mask[i]); }
vkd3d_spirv_build_op_return(&compiler->spirv_builder); @@ -5338,24 +5175,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 shader_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, ®ister_count, 1); - 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; @@ -5369,7 +5188,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); @@ -5398,8 +5216,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); } }
@@ -6188,7 +6004,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); @@ -6206,41 +6023,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; - - 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; - } - - 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) { @@ -6440,12 +6222,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 shader_signature *signature = compiler->output_signature; + const struct shader_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); @@ -6455,11 +6233,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) @@ -6468,42 +6241,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 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); - } - } - } } }
@@ -6542,8 +6285,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 shader_signature *output_signature = compiler->output_signature; - const struct shader_signature *input_signature = compiler->input_signature; + const struct shader_signature *output_signature = &compiler->output_signature; + const struct shader_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; @@ -6551,6 +6294,7 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile uint32_t type_id, output_ptr_type_id; uint32_t input_id, output_id, dst_id; unsigned int component_count; + unsigned int array_sizes[2]; uint32_t invocation_id; unsigned int i;
@@ -6580,18 +6324,23 @@ 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, 1); + type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count); + if ((array_sizes[0] = (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_sizes[0])); + + array_sizes[1] = compiler->output_control_point_count; + output_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, SpvStorageClassOutput, + component_type, component_count, array_sizes, 2); 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);
@@ -9397,9 +9146,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; @@ -9686,37 +9432,41 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct vkd3d_shader_code *spirv) { const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; - struct vkd3d_shader_instruction_array *instructions = &parser->instructions; const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - struct vkd3d_shader_instruction_array normalised_instructions; + struct vkd3d_shader_instruction_array instructions; enum vkd3d_result result = VKD3D_OK; unsigned int i;
compiler->location.column = 0; compiler->location.line = 1;
- if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) - { - normalised_instructions = parser->instructions; - memset(&parser->instructions, 0, sizeof(parser->instructions)); - instructions = &normalised_instructions; - if ((result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0) - result = instruction_array_normalise_hull_shader_control_point_io(instructions, - &parser->shader_desc.input_signature); + instructions = parser->instructions; + memset(&parser->instructions, 0, sizeof(parser->instructions));
- if (result >= 0 && TRACE_ON()) - vkd3d_shader_trace(instructions, &parser->shader_version); + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL + && (result = instruction_array_flatten_hull_shader_phases(&instructions)) >= 0) + { + result = instruction_array_normalise_hull_shader_control_point_io(&instructions, + &parser->shader_desc.input_signature); } + if (result >= 0) + result = instruction_array_normalise_io_registers(&instructions, parser->shader_version.type, + &compiler->input_signature, &compiler->output_signature, &compiler->patch_constant_signature); + + 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) + for (i = 0; i < instructions.count && result >= 0; ++i) { compiler->location.line = i + 1; - result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]); + result = spirv_compiler_handle_instruction(compiler, &instructions.elements[i]); }
- if (instructions == &normalised_instructions) - shader_instruction_array_destroy(&normalised_instructions); + shader_instruction_array_destroy(&instructions);
if (result < 0) return result; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 77b62def..406d53a3 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -786,6 +786,7 @@ enum vkd3d_shader_input_sysval_semantic
struct signature_element { + unsigned int sort_index; const char *semantic_name; unsigned int semantic_index; unsigned int stream_index; @@ -959,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; @@ -1366,5 +1372,8 @@ int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code); enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *instructions); enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( struct vkd3d_shader_instruction_array *instructions, const struct shader_signature *input_signature); +enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_shader_instruction_array *instructions, + enum vkd3d_shader_type shader_type, struct shader_signature *input_signature, + struct shader_signature *output_signature, struct shader_signature *patch_constant_signature);
#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);
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/spirv.c:
{ if (builtin) {
input_id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
input_id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, &array_size, 1);
For my own education, why aren't you using `spirv_compiler_emit_builtin_variable()` (here and elsewhere)?
On Fri May 19 12:45:22 2023 +0000, Giovanni Mascellani wrote:
For my own education, why aren't you using `spirv_compiler_emit_builtin_variable()` (here and elsewhere)?
Only to give the multi-dimensional version something to do, otherwise it would be dead code, or part of the next patch making it larger.
On Fri May 19 13:10:49 2023 +0000, Conor McCarthy wrote:
Only to give the multi-dimensional version something to do, otherwise it would be dead code, or part of the next patch making it larger.
Well, `spirv_compiler_emit_builtin_variable()` calls `spirv_compiler_emit_builtin_variable_v()`, doesn't it? So you'd have no dead code anyway. Am I missing something?
On Mon May 22 14:21:34 2023 +0000, Giovanni Mascellani wrote:
Well, `spirv_compiler_emit_builtin_variable()` calls `spirv_compiler_emit_builtin_variable_v()`, doesn't it? So you'd have no dead code anyway. Am I missing something?
Oops I missed that.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/ir.c:
signature = normaliser->output_signature;
break;
default:
return;
- }
- id_idx = reg->idx_count - 1;
- 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);
- 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;
- reg->idx_count = id_idx + 1;
I guess that putting `element_idx` in the last index slot is intended, to match the code that would be generated by the SM6 parser, isn't it? Because in itself it feels pretty ugly, since it swaps the natural order of array dimensions (i.e., putting major dimensions first).
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/ir.c:
keep = 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)
shader_dst_param_io_normalise((struct vkd3d_shader_dst_param *)&ins->dst[i], false, normaliser);
I don't like casting away `const` too much. What is the reason why `dst` is a pointer to `const` in the first pace? Given that it seems that we want to modify instructions, maybe it makes sense to remove `const` from the `struct vkd3d_shader_instruction`?
The same happens a couple of lines below.
One side effect of this MR is that the indices in `struct vkd3d_shader_register` begin having a different meaning depending on whether they have to be interpreted as SM4-like or SM6-like, which is dictated by the context (right now the context amounts to begin before or after `instruction_array_normalise_io_registers()`, but in the future it might become more complicated). I think this can be handled, but I don't find ideal. Maybe there should be a flag at some point of the `vkd3d_shader_instruction` structure tree that should keep track of that information? I don't know, just thinking out loud.