Normalise the incoming vkd3d_shader_instruction IR to the shader model 6 pattern where only one patch constant function is emitted. This allows generation of a single patch constant function in SPIR-V.
-- v14: vkd3d-shader/spirv: Declare the phase SPIR-V function in spirv_compiler_enter_shader_phase(). vkd3d-shader/spirv: Remove the hull shader phase array. vkd3d-shader/trace: Trace the normalised instruction array after tracing the input. vkd3d-shader/ir: Merge all shader IR fork and join phases into a single phase.
From: Conor McCarthy cmccarthy@codeweavers.com
Normalise the incoming vkd3d_shader_instruction IR to the shader model 6 pattern. This allows generation of a single patch constant function in SPIR-V. --- Makefile.am | 1 + libs/vkd3d-shader/ir.c | 264 +++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 144 ++++--------- libs/vkd3d-shader/vkd3d_shader_main.c | 78 +++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 19 ++ 5 files changed, 401 insertions(+), 105 deletions(-) create mode 100644 libs/vkd3d-shader/ir.c
diff --git a/Makefile.am b/Makefile.am index ebda192d..b9cc242e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -248,6 +248,7 @@ libvkd3d_shader_la_SOURCES = \ libs/vkd3d-shader/hlsl_constant_ops.c \ libs/vkd3d-shader/hlsl_sm1.c \ libs/vkd3d-shader/hlsl_sm4.c \ + libs/vkd3d-shader/ir.c \ libs/vkd3d-shader/preproc.h \ libs/vkd3d-shader/sm4.h \ libs/vkd3d-shader/spirv.c \ diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c new file mode 100644 index 00000000..a077a05d --- /dev/null +++ b/libs/vkd3d-shader/ir.c @@ -0,0 +1,264 @@ +/* + * Copyright 2023 Conor McCarthy for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "vkd3d_shader_private.h" + +static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) +{ + return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; +} + +static bool shader_instruction_is_dcl(const struct vkd3d_shader_instruction *ins) +{ + return (VKD3DSIH_DCL <= ins->handler_idx && ins->handler_idx <= VKD3DSIH_DCL_VERTICES_OUT) + || ins->handler_idx == VKD3DSIH_HS_DECLS; +} + +static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins) +{ + ins->handler_idx = VKD3DSIH_NOP; + ins->dst_count = 0; + ins->src_count = 0; + ins->dst = NULL; + ins->src = NULL; +} + +static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg, + unsigned int instance_id) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (reg->idx[i].rel_addr && shader_register_is_phase_instance_id(®->idx[i].rel_addr->reg)) + { + reg->idx[i].rel_addr = NULL; + reg->idx[i].offset += instance_id; + } + } +} + +static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_instruction *ins, + unsigned int instance_id) +{ + struct vkd3d_shader_register *reg; + unsigned int i; + + for (i = 0; i < ins->src_count; ++i) + { + reg = (struct vkd3d_shader_register *)&ins->src[i].reg; + if (shader_register_is_phase_instance_id(reg)) + { + reg->type = VKD3DSPR_IMMCONST; + reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + reg->non_uniform = false; + reg->idx[0].offset = ~0u; + reg->idx[0].rel_addr = NULL; + reg->idx[1].offset = ~0u; + reg->idx[1].rel_addr = NULL; + reg->idx[2].offset = ~0u; + reg->idx[2].rel_addr = NULL; + reg->immconst_type = VKD3D_IMMCONST_SCALAR; + reg->u.immconst_uint[0] = instance_id; + continue; + } + shader_register_eliminate_phase_addressing(reg, instance_id); + } + + for (i = 0; i < ins->dst_count; ++i) + shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, instance_id); +} + +static bool normaliser_is_in_fork_or_join_phase(const struct vkd3d_shader_normaliser *normaliser) +{ + return normaliser->phase == VKD3DSIH_HS_FORK_PHASE || normaliser->phase == VKD3DSIH_HS_JOIN_PHASE; +} + +struct shader_phase_location +{ + unsigned int index; + unsigned int instance_count; + unsigned int instruction_count; +}; + +struct shader_phase_location_array +{ + /* Unlikely worst case: one phase for each component of each output register. */ + struct shader_phase_location locations[MAX_REG_OUTPUT * VKD3D_VEC4_SIZE]; + unsigned int count; +}; + +static void shader_normaliser_eliminate_phase_related_dcls(struct vkd3d_shader_normaliser *normaliser, + unsigned int index, struct shader_phase_location_array *locations) +{ + struct vkd3d_shader_instruction *ins = &normaliser->instructions.elements[index]; + struct shader_phase_location *loc; + bool b; + + if (ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) + { + b = normaliser_is_in_fork_or_join_phase(normaliser); + /* Reset the phase info. */ + normaliser->phase_body_idx = ~0u; + normaliser->phase = ins->handler_idx; + normaliser->instance_count = 1; + /* Leave the first occurrence and delete the rest. */ + if (b) + vkd3d_shader_instruction_make_nop(ins); + return; + } + else if (ins->handler_idx == VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT + || ins->handler_idx == VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT) + { + normaliser->instance_count = ins->declaration.count + !ins->declaration.count; + vkd3d_shader_instruction_make_nop(ins); + return; + } + else if (ins->handler_idx == VKD3DSIH_DCL_INPUT && shader_register_is_phase_instance_id( + &ins->declaration.dst.reg)) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + else if (ins->handler_idx == VKD3DSIH_DCL_TEMPS && normaliser->phase != VKD3DSIH_INVALID) + { + /* Leave only the first temp declaration and set it to the max count later. */ + if (!normaliser->max_temp_count) + normaliser->temp_dcl_idx = index; + else + vkd3d_shader_instruction_make_nop(ins); + normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count); + return; + } + + if (normaliser->phase == VKD3DSIH_INVALID || shader_instruction_is_dcl(ins)) + return; + + if (normaliser->phase_body_idx == ~0u) + normaliser->phase_body_idx = index; + + if (ins->handler_idx == VKD3DSIH_RET) + { + vkd3d_shader_instruction_make_nop(ins); + if (locations->count >= ARRAY_SIZE(locations->locations)) + { + FIXME("Insufficient space for phase location.\n"); + return; + } + loc = &locations->locations[locations->count++]; + loc->index = normaliser->phase_body_idx; + loc->instance_count = normaliser->instance_count; + loc->instruction_count = index - normaliser->phase_body_idx; + } +} + +static enum vkd3d_result shader_normaliser_flatten_phases(struct vkd3d_shader_normaliser *normaliser, + struct shader_phase_location_array *locations) +{ + struct shader_phase_location *loc; + unsigned int i, j, k, end, count; + + for (i = 0, count = 0; i < locations->count; ++i) + count += (locations->locations[i].instance_count - 1) * locations->locations[i].instruction_count; + + if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + count)) + return VKD3D_ERROR_OUT_OF_MEMORY; + end = normaliser->instructions.count; + normaliser->instructions.count += count; + + for (i = locations->count; i > 0; --i) + { + loc = &locations->locations[i - 1]; + j = loc->index + loc->instruction_count; + memmove(&normaliser->instructions.elements[j + count], &normaliser->instructions.elements[j], + (end - j) * sizeof(*normaliser->instructions.elements)); + end = j; + count -= (loc->instance_count - 1) * loc->instruction_count; + loc->index += count; + } + + for (i = 0, count = 0; i < locations->count; ++i) + { + loc = &locations->locations[i]; + /* Make a copy of the non-dcl instructions for each instance. */ + for (j = 1; j < loc->instance_count; ++j) + { + for (k = 0; k < loc->instruction_count; ++k) + { + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, + loc->index + loc->instruction_count * j + k, loc->index + k)) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + } + /* Replace each reference to the instance id with a constant instance id. */ + for (j = 0; j < loc->instance_count; ++j) + { + for (k = 0; k < loc->instruction_count; ++k) + shader_instruction_eliminate_phase_instance_id( + &normaliser->instructions.elements[loc->index + loc->instruction_count * j + k], j); + } + } + + return VKD3D_OK; +} + +static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx) +{ + memset(ins, 0, sizeof(*ins)); + ins->handler_idx = handler_idx; +} + +void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser, + struct vkd3d_shader_instruction_array *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 shader_phase_location_array locations; + enum vkd3d_result result = VKD3D_OK; + unsigned int i; + + for (i = 0, locations.count = 0; i < instructions->count; ++i) + shader_normaliser_eliminate_phase_related_dcls(normaliser, i, &locations); + + if ((result = shader_normaliser_flatten_phases(normaliser, &locations)) < 0) + return result; + + if (normaliser->phase != VKD3DSIH_INVALID) + { + if (normaliser->temp_dcl_idx) + instructions->elements[normaliser->temp_dcl_idx].declaration.count = normaliser->max_temp_count; + + if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + shader_instruction_init(&instructions->elements[instructions->count++], VKD3DSIH_RET); + } + + return result; +} + +void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser) +{ + shader_instruction_array_destroy(&normaliser->instructions); +} diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index f0cfee47..3564c951 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2199,9 +2199,7 @@ struct vkd3d_shader_phase { enum vkd3d_shader_opcode type; unsigned int idx; - unsigned int instance_count; uint32_t function_id; - uint32_t instance_id; size_t function_location; };
@@ -2887,12 +2885,6 @@ static bool spirv_compiler_get_register_name(char *buffer, unsigned int buffer_s case VKD3DSPR_DEPTHOUTLE: snprintf(buffer, buffer_size, "oDepth"); break; - case VKD3DSPR_FORKINSTID: - snprintf(buffer, buffer_size, "vForkInstanceId"); - break; - case VKD3DSPR_JOININSTID: - snprintf(buffer, buffer_size, "vJoinInstanceId"); - break; case VKD3DSPR_GSINSTID: snprintf(buffer, buffer_size, "vGSInstanceID"); break; @@ -4333,29 +4325,15 @@ static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler, { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t void_id, function_type_id; - unsigned int param_count; uint32_t param_type_id;
- if (phase->instance_count) - { - param_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); - param_count = 1; - } - else - { - param_count = 0; - } - phase->function_id = vkd3d_spirv_alloc_id(builder);
void_id = vkd3d_spirv_get_op_type_void(builder); - function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, param_count); + function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, 0); vkd3d_spirv_build_op_function(builder, void_id, phase->function_id, SpvFunctionControlMaskNone, function_type_id);
- if (phase->instance_count) - phase->instance_id = vkd3d_spirv_build_op_function_parameter(builder, param_type_id); - vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
@@ -4772,10 +4750,7 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler, static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compiler, const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst) { - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_register *reg = &dst->reg; - struct vkd3d_symbol reg_symbol; - uint32_t val_id;
switch (reg->type) { @@ -4787,10 +4762,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil case VKD3DSPR_PRIMID: spirv_compiler_emit_input_register(compiler, dst); return; - case VKD3DSPR_FORKINSTID: - case VKD3DSPR_JOININSTID: - val_id = phase->instance_id; - break; case VKD3DSPR_OUTPOINTID: /* Emitted in spirv_compiler_emit_initial_declarations(). */ case VKD3DSPR_OUTCONTROLPOINT: /* See spirv_compiler_leave_shader_phase(). */ return; @@ -4798,13 +4769,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil FIXME("Unhandled shader phase input register %#x.\n", reg->type); return; } - - vkd3d_symbol_make_register(®_symbol, reg); - vkd3d_symbol_set_register_info(®_symbol, val_id, - SpvStorageClassMax /* Intermediate value */, - VKD3D_SHADER_COMPONENT_UINT, VKD3DSP_WRITEMASK_0); - spirv_compiler_put_symbol(compiler, ®_symbol); - spirv_compiler_emit_register_debug_name(builder, val_id, reg); }
static unsigned int spirv_compiler_get_output_variable_index( @@ -6560,20 +6524,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, } } } - - if (phase->instance_count) - { - memset(®, 0, sizeof(reg)); - reg.type = phase->type == VKD3DSIH_HS_FORK_PHASE ? VKD3DSPR_FORKINSTID : VKD3DSPR_JOININSTID; - reg.idx[0].offset = ~0u; - reg.idx[1].offset = ~0u; - vkd3d_symbol_make_register(®_symbol, ®); - if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) - { - rb_remove(&compiler->symbol_table, entry); - vkd3d_symbol_free(entry, NULL); - } - } }
static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, @@ -6592,34 +6542,12 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
phase->type = instruction->handler_idx; phase->idx = compiler->shader_phase_count; - phase->instance_count = 0; phase->function_id = 0; - phase->instance_id = 0; phase->function_location = 0;
++compiler->shader_phase_count; }
-static int spirv_compiler_emit_shader_phase_instance_count(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) -{ - struct vkd3d_shader_phase *phase = &compiler->shader_phases[compiler->shader_phase_count - 1]; - - if (!compiler->shader_phase_count - || (phase->type != VKD3DSIH_HS_FORK_PHASE && phase->type != VKD3DSIH_HS_JOIN_PHASE) - || phase->function_id) - { - WARN("Unexpected dcl_hs_{fork,join}_phase_instance_count instruction.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - phase->instance_count = instruction->declaration.count; - - spirv_compiler_begin_shader_phase(compiler, phase); - - return VKD3D_OK; -} - static const struct vkd3d_shader_phase *spirv_compiler_get_control_point_phase( struct spirv_compiler *compiler) { @@ -6851,12 +6779,27 @@ static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler } }
+static const struct vkd3d_shader_phase *spirv_compiler_get_fork_or_join_phase( + struct spirv_compiler *compiler) +{ + const struct vkd3d_shader_phase *phase; + + assert(compiler->shader_phase_count); + + phase = &compiler->shader_phases[0]; + if (is_control_point_phase(phase)) + { + assert(compiler->shader_phase_count > 1); + phase = &compiler->shader_phases[1]; + } + + return phase; +} + static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_phase *control_point_phase, *phase; - uint32_t phase_instance_id; - unsigned int i, j; + const struct vkd3d_shader_phase *control_point_phase; uint32_t void_id;
vkd3d_spirv_builder_begin_main_function(builder); @@ -6873,26 +6816,11 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler if (compiler->use_vocp) spirv_compiler_emit_hull_shader_barrier(compiler);
- for (i = 0; i < compiler->shader_phase_count; ++i) - { - phase = &compiler->shader_phases[i]; - if (is_control_point_phase(phase)) - continue; - - if (phase->instance_count) - { - for (j = 0; j < phase->instance_count; ++j) - { - phase_instance_id = spirv_compiler_get_constant_uint(compiler, j); - vkd3d_spirv_build_op_function_call(builder, - void_id, phase->function_id, &phase_instance_id, 1); - } - } - else - { - vkd3d_spirv_build_op_function_call(builder, void_id, phase->function_id, NULL, 0); - } - } + /* TODO: only call the patch constant function for invocation 0. The simplest way + * is to avoid use of private variables there, otherwise we would need a separate + * patch constant epilogue also only called from invocation 0. */ + vkd3d_spirv_build_op_function_call(builder, void_id, spirv_compiler_get_fork_or_join_phase(compiler)->function_id, + NULL, 0);
spirv_compiler_emit_shader_epilogue_invocation(compiler); vkd3d_spirv_build_op_return(builder); @@ -9699,10 +9627,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_THREAD_GROUP: spirv_compiler_emit_dcl_thread_group(compiler, instruction); break; - case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT: - case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT: - ret = spirv_compiler_emit_shader_phase_instance_count(compiler, instruction); - break; case VKD3DSIH_HS_CONTROL_POINT_PHASE: case VKD3DSIH_HS_FORK_PHASE: case VKD3DSIH_HS_JOIN_PHASE: @@ -9951,20 +9875,31 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *spirv) { - const struct vkd3d_shader_instruction_array *instructions = &parser->instructions; 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_normaliser normaliser; const struct vkd3d_shader_phase *phase; enum vkd3d_result result = VKD3D_OK; unsigned int i;
- for (i = 0; i < instructions->count; ++i) + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { - if ((result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i])) < 0) - return result; + shader_normaliser_init(&normaliser, instructions); + result = shader_normaliser_flatten_hull_shader_phases(&normaliser); + instructions = &normaliser.instructions; }
+ for (i = 0; i < instructions->count && result >= 0; ++i) + result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]); + + if (instructions == &normaliser.instructions) + shader_normaliser_destroy(&normaliser); + + if (result < 0) + return result; + if ((phase = spirv_compiler_get_current_shader_phase(compiler))) spirv_compiler_leave_shader_phase(compiler, phase); else @@ -10034,7 +9969,6 @@ void spirv_compiler_destroy(struct spirv_compiler *compiler)
rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
- vkd3d_free(compiler->shader_phases); vkd3d_free(compiler->spec_constants);
vkd3d_string_buffer_cache_cleanup(&compiler->string_buffers); diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 1244fb48..1d852894 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1644,6 +1644,84 @@ bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *ins return true; }
+static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( + struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_src_param *params, + unsigned int count); + +static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, + struct vkd3d_shader_instruction_array *instructions) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (!reg->idx[i].rel_addr) + continue; + + if (!(reg->idx[i].rel_addr = shader_instruction_array_clone_src_params(instructions, reg->idx[i].rel_addr, 1))) + return false; + } + + return true; +} + +static struct vkd3d_shader_dst_param *shader_instruction_array_clone_dst_params( + struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_dst_param *params, + unsigned int count) +{ + struct vkd3d_shader_dst_param *dst_params; + unsigned int i; + + if (!(dst_params = shader_dst_param_allocator_get(&instructions->dst_params, count))) + return NULL; + + memcpy(dst_params, params, count * sizeof(*params)); + for (i = 0; i < count; ++i) + { + if (!shader_register_clone_relative_addresses(&dst_params[i].reg, instructions)) + return NULL; + } + + return dst_params; +} + +static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( + struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_src_param *params, + unsigned int count) +{ + struct vkd3d_shader_src_param *src_params; + unsigned int i; + + if (!(src_params = shader_src_param_allocator_get(&instructions->src_params, count))) + return NULL; + + memcpy(src_params, params, count * sizeof(*params)); + for (i = 0; i < count; ++i) + { + if (!shader_register_clone_relative_addresses(&src_params[i].reg, instructions)) + return NULL; + } + + return src_params; +} + +/* NOTE: Immediate constant buffers are not cloned, so the source must not be destroyed while the + * destination is in use. This seems like a reasonable requirement given how this is currently used. */ +bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, unsigned int src) +{ + struct vkd3d_shader_instruction *ins = &instructions->elements[dst]; + + *ins = instructions->elements[src]; + + if (ins->dst_count && ins->dst && !(ins->dst = shader_instruction_array_clone_dst_params(instructions, + ins->dst, ins->dst_count))) + return false; + + return !ins->src_count || !!(ins->src = shader_instruction_array_clone_src_params(instructions, + ins->src, ins->src_count)); +} + void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions) { unsigned int i; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6c5a1917..6006c531 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -978,6 +978,8 @@ bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instru bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve); bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_immediate_constant_buffer *icb); +bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, unsigned int src); void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions);
struct vkd3d_shader_parser @@ -1327,4 +1329,21 @@ 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; +}; + +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); +void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser); + #endif /* __VKD3D_SHADER_PRIVATE_H */
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 3 +++ libs/vkd3d-shader/trace.c | 17 +++++++++-------- libs/vkd3d-shader/vkd3d_shader_main.c | 6 +++--- libs/vkd3d-shader/vkd3d_shader_private.h | 8 +++++--- 4 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 3564c951..c38f5df5 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9889,6 +9889,9 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, shader_normaliser_init(&normaliser, instructions); result = shader_normaliser_flatten_hull_shader_phases(&normaliser); instructions = &normaliser.instructions; + + if (result >= 0 && TRACE_ON()) + vkd3d_shader_trace(instructions, &parser->shader_version); }
for (i = 0; i < instructions->count && result >= 0; ++i) diff --git a/libs/vkd3d-shader/trace.c b/libs/vkd3d-shader/trace.c index f32f26a7..eeee2e6a 100644 --- a/libs/vkd3d-shader/trace.c +++ b/libs/vkd3d-shader/trace.c @@ -1851,11 +1851,11 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, shader_addline(buffer, "\n"); }
-enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out) +enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, + const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out) { enum vkd3d_shader_compile_option_formatting_flags formatting; - struct vkd3d_shader_version *shader_version; struct vkd3d_d3d_asm_compiler compiler; enum vkd3d_result result = VKD3D_OK; struct vkd3d_string_buffer *buffer; @@ -1913,16 +1913,16 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, buffer = &compiler.buffer; vkd3d_string_buffer_init(buffer);
+ compiler.shader_version = *shader_version; shader_version = &compiler.shader_version; - *shader_version = parser->shader_version; vkd3d_string_buffer_printf(buffer, "%s%s_%u_%u%s\n", compiler.colours.version, shader_get_type_prefix(shader_version->type), shader_version->major, shader_version->minor, compiler.colours.reset);
indent = 0; - for (i = 0; i < parser->instructions.count; ++i) + for (i = 0; i < instructions->count; ++i) { - struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i]; + struct vkd3d_shader_instruction *ins = &instructions->elements[i];
switch (ins->handler_idx) { @@ -1975,12 +1975,13 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, return result; }
-void vkd3d_shader_trace(struct vkd3d_shader_parser *parser) +void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instructions, + const struct vkd3d_shader_version *shader_version) { const char *p, *q, *end; struct vkd3d_shader_code code;
- if (vkd3d_dxbc_binary_to_text(parser, NULL, &code) != VKD3D_OK) + if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, &code) != VKD3D_OK) return;
end = (const char *)code.code + code.size; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 1d852894..0709f4f7 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1072,7 +1072,7 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
if (TRACE_ON()) { - vkd3d_shader_trace(parser); + vkd3d_shader_trace(&parser->instructions, &parser->shader_version); }
for (i = 0; i < parser->instructions.count; ++i) @@ -1198,7 +1198,7 @@ static int compile_dxbc_tpf(const struct vkd3d_shader_compile_info *compile_info if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_ASM) { vkd3d_shader_free_scan_descriptor_info(&scan_descriptor_info); - ret = vkd3d_dxbc_binary_to_text(parser, compile_info, out); + ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out); vkd3d_shader_parser_destroy(parser); return ret; } @@ -1272,7 +1272,7 @@ static int compile_d3d_bytecode(const struct vkd3d_shader_compile_info *compile_
if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_ASM) { - ret = vkd3d_dxbc_binary_to_text(parser, compile_info, out); + ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out); vkd3d_shader_parser_destroy(parser); return ret; } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6006c531..6fcf3426 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1027,7 +1027,8 @@ static inline void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parse parser->ops->parser_destroy(parser); }
-void vkd3d_shader_trace(struct vkd3d_shader_parser *parser); +void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instructions, + const struct vkd3d_shader_version *shader_version);
const char *shader_get_type_prefix(enum vkd3d_shader_type type);
@@ -1043,8 +1044,9 @@ struct vkd3d_string_buffer_cache size_t count, max_count, capacity; };
-enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out); +enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, + const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out); void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer); struct vkd3d_string_buffer *vkd3d_string_buffer_get(struct vkd3d_string_buffer_cache *list); void vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer);
From: Conor McCarthy cmccarthy@codeweavers.com
With no more than one phase each of control point and fork/join type, an array is not required. --- libs/vkd3d-shader/spirv.c | 143 +++++++++++++------------------------- 1 file changed, 50 insertions(+), 93 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index c38f5df5..5f2475a5 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2197,8 +2197,6 @@ struct vkd3d_push_constant_buffer_binding
struct vkd3d_shader_phase { - enum vkd3d_shader_opcode type; - unsigned int idx; uint32_t function_id; size_t function_location; }; @@ -2274,9 +2272,9 @@ struct spirv_compiler unsigned int output_control_point_count; bool use_vocp;
- unsigned int shader_phase_count; - struct vkd3d_shader_phase *shader_phases; - size_t shader_phases_size; + enum vkd3d_shader_opcode phase; + struct vkd3d_shader_phase control_point_phase; + struct vkd3d_shader_phase patch_constant_phase;
uint32_t current_spec_constant_id; unsigned int spec_constant_count; @@ -2288,9 +2286,19 @@ struct spirv_compiler struct vkd3d_string_buffer_cache string_buffers; };
-static bool is_control_point_phase(const struct vkd3d_shader_phase *phase) +static bool is_in_default_phase(const struct spirv_compiler *compiler) +{ + return compiler->phase == VKD3DSIH_INVALID; +} + +static bool is_in_control_point_phase(const struct spirv_compiler *compiler) { - return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE; + return compiler->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +} + +static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler) +{ + return compiler->phase == VKD3DSIH_HS_FORK_PHASE || compiler->phase == VKD3DSIH_HS_JOIN_PHASE; }
static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler); @@ -2435,6 +2443,8 @@ struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_version *
compiler->scan_descriptor_info = scan_descriptor_info;
+ compiler->phase = VKD3DSIH_INVALID; + vkd3d_string_buffer_cache_init(&compiler->string_buffers);
spirv_compiler_emit_initial_declarations(compiler); @@ -4294,7 +4304,7 @@ static uint32_t spirv_compiler_emit_load_invocation_id(struct spirv_compiler *co }
static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compiler, - uint32_t id, const struct vkd3d_shader_phase *phase, const char *suffix) + uint32_t id, const char *suffix) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const char *name; @@ -4302,7 +4312,7 @@ static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compile if (!suffix) suffix = "";
- switch (phase->type) + switch (compiler->phase) { case VKD3DSIH_HS_CONTROL_POINT_PHASE: name = "control"; @@ -4314,10 +4324,10 @@ static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compile name = "join"; break; default: - ERR("Invalid phase type %#x.\n", phase->type); + ERR("Invalid phase type %#x.\n", compiler->phase); return; } - vkd3d_spirv_build_op_name(builder, id, "%s%u%s", name, phase->idx, suffix); + vkd3d_spirv_build_op_name(builder, id, "%s%s", name, suffix); }
static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler, @@ -4337,7 +4347,7 @@ static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler, vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
- spirv_compiler_emit_shader_phase_name(compiler, phase->function_id, phase, NULL); + spirv_compiler_emit_shader_phase_name(compiler, phase->function_id, NULL); }
static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( @@ -4345,10 +4355,10 @@ static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( { struct vkd3d_shader_phase *phase;
- if (!compiler->shader_phase_count) + if (is_in_default_phase(compiler)) return NULL;
- phase = &compiler->shader_phases[compiler->shader_phase_count - 1]; + phase = is_in_control_point_phase(compiler) ? &compiler->control_point_phase : &compiler->patch_constant_phase; if (!phase->function_id) spirv_compiler_begin_shader_phase(compiler, phase); return phase; @@ -4748,7 +4758,7 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler, }
static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compiler, - const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst) + const struct vkd3d_shader_dst_param *dst) { const struct vkd3d_shader_register *reg = &dst->reg;
@@ -4941,7 +4951,7 @@ static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_compiler *compiler, - const struct vkd3d_shader_phase *phase, const struct vkd3d_spirv_builtin *builtin) + const struct vkd3d_spirv_builtin *builtin) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t *variable_id, id; @@ -4957,7 +4967,7 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c return *variable_id;
id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0); - if (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE) + if (is_in_fork_or_join_phase(compiler)) vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
if (variable_id) @@ -4975,7 +4985,6 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, unsigned int component_idx, output_component_count; enum vkd3d_shader_component_type component_type; const struct vkd3d_spirv_builtin *builtin; - const struct vkd3d_shader_phase *phase; struct vkd3d_symbol *symbol = NULL; bool use_private_variable = false; struct vkd3d_symbol reg_symbol; @@ -4987,12 +4996,11 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, bool is_patch_constant; uint32_t id, var_id;
- phase = spirv_compiler_get_current_shader_phase(compiler); - is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE); + is_patch_constant = is_in_fork_or_join_phase(compiler);
shader_signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
- array_size = is_control_point_phase(phase) ? compiler->output_control_point_count : 0; + 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))) @@ -5047,8 +5055,8 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, } else if (builtin) { - if (phase) - id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, phase, builtin); + if (spirv_compiler_get_current_shader_phase(compiler)) + id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, builtin); else id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
@@ -5107,7 +5115,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, 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 (!use_private_variable && is_control_point_phase(phase)) + if (!use_private_variable && is_in_control_point_phase(compiler)) { reg_symbol.info.reg.member_idx = spirv_compiler_get_invocation_id(compiler); reg_symbol.info.reg.is_dynamically_indexed = true; @@ -5259,7 +5267,6 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_signature *signature; - const struct vkd3d_shader_phase *phase; uint32_t output_index_id = 0; bool is_patch_constant; unsigned int i, count; @@ -5270,8 +5277,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_array_idx)); STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_write_mask));
- phase = spirv_compiler_get_current_shader_phase(compiler); - is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE); + is_patch_constant = is_in_fork_or_join_phase(compiler);
signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
@@ -5304,7 +5310,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone); }
- if (is_control_point_phase(phase)) + if (is_in_control_point_phase(compiler)) output_index_id = spirv_compiler_emit_load_invocation_id(compiler);
for (i = 0; i < signature->element_count; ++i) @@ -6149,10 +6155,9 @@ static void spirv_compiler_emit_dcl_input(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst; - const struct vkd3d_shader_phase *phase;
- if ((phase = spirv_compiler_get_current_shader_phase(compiler))) - spirv_compiler_emit_shader_phase_input(compiler, phase, dst); + if (spirv_compiler_get_current_shader_phase(compiler)) + spirv_compiler_emit_shader_phase_input(compiler, dst); else if (vkd3d_shader_register_is_input(&dst->reg) || dst->reg.type == VKD3DSPR_PATCHCONST) spirv_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE); else @@ -6459,8 +6464,7 @@ static void spirv_compiler_emit_dcl_thread_group(struct spirv_compiler *compiler SpvExecutionModeLocalSize, local_size, ARRAY_SIZE(local_size)); }
-static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, - const struct vkd3d_shader_phase *phase) +static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) { const struct vkd3d_shader_signature *signature = compiler->output_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; @@ -6479,11 +6483,11 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, * point phase. Reinsert symbols for vocp registers while leaving the * control point phase. */ - if (is_control_point_phase(phase)) + if (is_in_control_point_phase(compiler)) { if (compiler->epilogue_function_id) { - spirv_compiler_emit_shader_phase_name(compiler, compiler->epilogue_function_id, phase, "_epilogue"); + spirv_compiler_emit_shader_phase_name(compiler, compiler->epilogue_function_id, "_epilogue"); spirv_compiler_emit_shader_epilogue_function(compiler); }
@@ -6529,38 +6533,12 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_phase *previous_phase; - struct vkd3d_shader_phase *phase; - - if ((previous_phase = spirv_compiler_get_current_shader_phase(compiler))) - spirv_compiler_leave_shader_phase(compiler, previous_phase); - - if (!vkd3d_array_reserve((void **)&compiler->shader_phases, &compiler->shader_phases_size, - compiler->shader_phase_count + 1, sizeof(*compiler->shader_phases))) - return; - phase = &compiler->shader_phases[compiler->shader_phase_count]; + assert(compiler->phase != instruction->handler_idx);
- phase->type = instruction->handler_idx; - phase->idx = compiler->shader_phase_count; - phase->function_id = 0; - phase->function_location = 0; + if (spirv_compiler_get_current_shader_phase(compiler)) + spirv_compiler_leave_shader_phase(compiler);
- ++compiler->shader_phase_count; -} - -static const struct vkd3d_shader_phase *spirv_compiler_get_control_point_phase( - struct spirv_compiler *compiler) -{ - const struct vkd3d_shader_phase *phase; - - if (compiler->shader_phase_count < 1) - return NULL; - - phase = &compiler->shader_phases[0]; - if (is_control_point_phase(phase)) - return phase; - - return NULL; + compiler->phase = instruction->handler_idx; }
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) @@ -6779,27 +6757,9 @@ static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler } }
-static const struct vkd3d_shader_phase *spirv_compiler_get_fork_or_join_phase( - struct spirv_compiler *compiler) -{ - const struct vkd3d_shader_phase *phase; - - assert(compiler->shader_phase_count); - - phase = &compiler->shader_phases[0]; - if (is_control_point_phase(phase)) - { - assert(compiler->shader_phase_count > 1); - phase = &compiler->shader_phases[1]; - } - - return phase; -} - static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_phase *control_point_phase; uint32_t void_id;
vkd3d_spirv_builder_begin_main_function(builder); @@ -6808,8 +6768,8 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler
void_id = vkd3d_spirv_get_op_type_void(builder);
- if ((control_point_phase = spirv_compiler_get_control_point_phase(compiler))) - vkd3d_spirv_build_op_function_call(builder, void_id, control_point_phase->function_id, NULL, 0); + if (compiler->control_point_phase.function_id) + vkd3d_spirv_build_op_function_call(builder, void_id, compiler->control_point_phase.function_id, NULL, 0); else spirv_compiler_emit_default_control_point_phase(compiler);
@@ -6819,9 +6779,7 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler /* TODO: only call the patch constant function for invocation 0. The simplest way * is to avoid use of private variables there, otherwise we would need a separate * patch constant epilogue also only called from invocation 0. */ - vkd3d_spirv_build_op_function_call(builder, void_id, spirv_compiler_get_fork_or_join_phase(compiler)->function_id, - NULL, 0); - + vkd3d_spirv_build_op_function_call(builder, void_id, compiler->patch_constant_phase.function_id, NULL, 0); spirv_compiler_emit_shader_epilogue_invocation(compiler); vkd3d_spirv_build_op_return(builder); vkd3d_spirv_build_op_function_end(builder); @@ -7503,10 +7461,10 @@ static uint32_t spirv_compiler_emit_conditional_branch(struct spirv_compiler *co static void spirv_compiler_emit_return(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_phase *phase = spirv_compiler_get_current_shader_phase(compiler); struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (!phase || is_control_point_phase(phase))) + if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (is_in_default_phase(compiler) + || is_in_control_point_phase(compiler))) spirv_compiler_emit_shader_epilogue_invocation(compiler);
vkd3d_spirv_build_op_return(builder); @@ -9880,7 +9838,6 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_shader_normaliser normaliser; - const struct vkd3d_shader_phase *phase; enum vkd3d_result result = VKD3D_OK; unsigned int i;
@@ -9903,8 +9860,8 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if (result < 0) return result;
- if ((phase = spirv_compiler_get_current_shader_phase(compiler))) - spirv_compiler_leave_shader_phase(compiler, phase); + if (!is_in_default_phase(compiler)) + spirv_compiler_leave_shader_phase(compiler); else vkd3d_spirv_build_op_function_end(builder);
From: Conor McCarthy cmccarthy@codeweavers.com
The convoluted code path is no longer needed. --- libs/vkd3d-shader/spirv.c | 48 +++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 27 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 5f2475a5..f4acb304 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -4330,38 +4330,13 @@ static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compile vkd3d_spirv_build_op_name(builder, id, "%s%s", name, suffix); }
-static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler, - struct vkd3d_shader_phase *phase) -{ - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t void_id, function_type_id; - uint32_t param_type_id; - - phase->function_id = vkd3d_spirv_alloc_id(builder); - - void_id = vkd3d_spirv_get_op_type_void(builder); - function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, 0); - vkd3d_spirv_build_op_function(builder, void_id, phase->function_id, - SpvFunctionControlMaskNone, function_type_id); - - vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); - phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); - - spirv_compiler_emit_shader_phase_name(compiler, phase->function_id, NULL); -} - static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( struct spirv_compiler *compiler) { - struct vkd3d_shader_phase *phase; - if (is_in_default_phase(compiler)) return NULL;
- phase = is_in_control_point_phase(compiler) ? &compiler->control_point_phase : &compiler->patch_constant_phase; - if (!phase->function_id) - spirv_compiler_begin_shader_phase(compiler, phase); - return phase; + return is_in_control_point_phase(compiler) ? &compiler->control_point_phase : &compiler->patch_constant_phase; }
static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, @@ -6533,12 +6508,31 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t function_id, void_id, function_type_id; + struct vkd3d_shader_phase *phase; + assert(compiler->phase != instruction->handler_idx);
- if (spirv_compiler_get_current_shader_phase(compiler)) + if (!is_in_default_phase(compiler)) spirv_compiler_leave_shader_phase(compiler);
+ function_id = vkd3d_spirv_alloc_id(builder); + + void_id = vkd3d_spirv_get_op_type_void(builder); + function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, NULL, 0); + vkd3d_spirv_build_op_function(builder, void_id, function_id, + SpvFunctionControlMaskNone, function_type_id); + + vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); + compiler->phase = instruction->handler_idx; + spirv_compiler_emit_shader_phase_name(compiler, function_id, NULL); + + phase = (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE) + ? &compiler->control_point_phase : &compiler->patch_constant_phase; + phase->function_id = function_id; + phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); }
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler)
On Wed Mar 1 02:06:02 2023 +0000, Henri Verbeet wrote:
From patch 1/4:
+static void shader_instruction_eliminate_phase_instance_id(struct
vkd3d_shader_instruction *ins,
unsigned int instance_id)
+{
- struct vkd3d_shader_register *reg;
- enum vkd3d_data_type data_type;
- unsigned int i;
- /* The dst always seems to be a TEMP, which are declared as
FLOAT. FLOAT always works in tests, but check
* for UINT for robustness. We assume the constant type should
equal the dst type, which is not true for
* all instructions, but the compiler apparently never does
anything fancy with a fork/join instance id. */
- data_type = (ins->dst_count && ins->dst[0].reg.data_type ==
VKD3D_DATA_UINT) ? VKD3D_DATA_UINT : VKD3D_DATA_FLOAT;
Why do we care about the destination data type at all? Shouldn't we simply keep the existing reg->data_type of the source parameter we're replacing? More concretely, suppose vForkInstanceId is "1", what should the value of r0/1/2 be after the following instructions? mov r0, vForkInstanceId utof r1, vForkInstanceId ftou r2, vForkInstanceId I'd expect 0x00000001, 0x3f800000, and 0x00000000 respectively; is that incorrect? The critical—though perhaps subtle—thing to understand here is that vkd3d_shader_instruction registers don't have an inherent type, but are instead containers of raw bits; the "data_type" fields of the instruction's sources and destinations are a property of the instruction, not of the registers being referenced.
TBH I don't know why I was doing it this way; it's a legacy of the original which had SPIR-V type mismatches from this code. The data type is now left unchanged.
I think this looks good, although we'll probably want to wait until after the 1.7 release to commit it.
There is one thought that occurred to me, although it may not be quite critical enough to block this series: ideally we would preserve the original source locations when doing transformations like this. That may mean recording the original vkd3d_shader_location in the vkd3d_shader_instruction structure, or at least the index of a particular instruction in the original vkd3d_shader_instruction_array.
(Incidentally, location information is currently more broken than that; we can no longer rely on the parser to update the current location while processing instructions.)