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.
-- v10: vkd3d-shader/normalise: Insert hull shader control point input declarations if no control point phase is defined. vkd3d-shader/spirv: Delete an unnecessary call to spirv_compiler_get_register_id().
From: Conor McCarthy cmccarthy@codeweavers.com
The normaliser only clones the instruction array. No normalisation is done. --- Makefile.am | 1 + libs/vkd3d-shader/normalise.c | 121 +++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 15 ++- libs/vkd3d-shader/vkd3d_shader_private.h | 9 ++ 4 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 libs/vkd3d-shader/normalise.c
diff --git a/Makefile.am b/Makefile.am index f9199472..7a3b18c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -242,6 +242,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/normalise.c \ libs/vkd3d-shader/preproc.h \ libs/vkd3d-shader/sm4.h \ libs/vkd3d-shader/spirv.c \ diff --git a/libs/vkd3d-shader/normalise.c b/libs/vkd3d-shader/normalise.c new file mode 100644 index 00000000..cb0c48a0 --- /dev/null +++ b/libs/vkd3d-shader/normalise.c @@ -0,0 +1,121 @@ +/* + * 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_normaliser_new_instructions(struct vkd3d_shader_normaliser *normaliser, unsigned int extra) +{ + return shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + extra); +} + +static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, + struct vkd3d_shader_instruction_array *instructions) +{ + struct vkd3d_shader_src_param *src; + 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 (!(src = shader_src_param_allocator_get(&instructions->src_params, 1))) + return false; + + memcpy(src, reg->idx[i].rel_addr, sizeof(*src)); + reg->idx[i].rel_addr = src; + assert(!src->reg.idx[0].rel_addr && src->reg.idx[1].offset == ~0u); + } + + return true; +} + +static bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, const struct vkd3d_shader_instruction *src) +{ + struct vkd3d_shader_instruction *ins = &instructions->elements[dst]; + struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_src_param *src_params; + unsigned int i; + + *ins = *src; + + if (ins->dst_count && ins->dst) + { + if (!(dst_params = shader_dst_param_allocator_get(&instructions->dst_params, ins->dst_count))) + return false; + + memcpy(dst_params, ins->dst, ins->dst_count * sizeof(*ins->dst)); + ins->dst = dst_params; + for (i = 0; i < ins->dst_count; ++i) + { + if (!shader_register_clone_relative_addresses(&dst_params[i].reg, instructions)) + return false; + } + } + if (ins->src_count) + { + if (!(src_params = shader_src_param_allocator_get(&instructions->src_params, ins->src_count))) + return false; + + memcpy(src_params, ins->src, ins->src_count * sizeof(*ins->src)); + ins->src = src_params; + for (i = 0; i < ins->src_count; ++i) + { + if (!shader_register_clone_relative_addresses(&src_params[i].reg, instructions)) + return false; + } + } + + return true; +} + +enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_parser *parser) +{ + const struct vkd3d_shader_instruction_array *instructions = &parser->instructions; + const struct vkd3d_shader_instruction *ins; + enum vkd3d_result result = VKD3D_OK; + unsigned int i; + + if (!shader_instruction_array_init(&normaliser->instructions, instructions->count)) + { + ERR("Failed to allocate instructions.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < instructions->count; ++i) + { + if (!shader_normaliser_new_instructions(normaliser, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &instructions->elements[i]; + + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, normaliser->instructions.count, ins)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ++normaliser->instructions.count; + } + + 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..aed6b51c 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9955,16 +9955,27 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; 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) + if ((result = shader_normaliser_normalise(&normaliser, parser)) < 0) return result; + instructions = &normaliser.instructions; }
+ for (i = 0; i < instructions->count && result >= 0; ++i) + result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]); + + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + 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 diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6c5a1917..c23c4475 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1327,4 +1327,13 @@ 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; +}; + +enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_parser *parser); +void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser); + #endif /* __VKD3D_SHADER_PRIVATE_H */
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. --- libs/vkd3d-shader/normalise.c | 195 ++++++++++++++++++++++- libs/vkd3d-shader/spirv.c | 130 +++------------ libs/vkd3d-shader/vkd3d_shader_private.h | 8 + 3 files changed, 226 insertions(+), 107 deletions(-)
diff --git a/libs/vkd3d-shader/normalise.c b/libs/vkd3d-shader/normalise.c index cb0c48a0..23c25514 100644 --- a/libs/vkd3d-shader/normalise.c +++ b/libs/vkd3d-shader/normalise.c @@ -18,11 +18,79 @@
#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 inline bool shader_normaliser_new_instructions(struct vkd3d_shader_normaliser *normaliser, unsigned int extra) { return shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + extra); }
+static inline bool shader_src_param_is_phase_instance_id(const struct vkd3d_shader_src_param *param, + const struct vkd3d_shader_normaliser *normaliser) +{ + const struct vkd3d_shader_register *reg = ¶m->reg; + return shader_register_is_phase_instance_id(reg) || (reg->type == VKD3DSPR_TEMP + && !vkd3d_swizzle_get_component(param->swizzle, 0) + && (normaliser->temp_is_instance_id & (1ull << reg->idx[0].offset))); +} + +static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg, + unsigned int instance_id, const struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (reg->idx[i].rel_addr && shader_src_param_is_phase_instance_id(reg->idx[i].rel_addr, normaliser)) + { + 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, const struct vkd3d_shader_normaliser *normaliser) +{ + 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_src_param_is_phase_instance_id(&ins->src[i], normaliser)) + { + reg->type = VKD3DSPR_IMMCONST; + reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + reg->non_uniform = false; + reg->data_type = VKD3D_DATA_UINT; + 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, normaliser); + } + + for (i = 0; i < ins->dst_count; ++i) + shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, + instance_id, normaliser); +} + static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, struct vkd3d_shader_instruction_array *instructions) { @@ -85,14 +153,123 @@ static bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instr return true; }
+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; +} + +static enum vkd3d_result shader_normaliser_eliminate_phase_instance_id(struct vkd3d_shader_normaliser *normaliser, + unsigned int *instruction_count) +{ + struct vkd3d_shader_instruction *ins = &normaliser->instructions.elements[normaliser->instructions.count]; + unsigned int i, j, count; + + if (ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) + { + /* Leave the first occurrence and delete the rest. */ + *instruction_count = !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; + normaliser->temp_is_instance_id = 0; + return VKD3D_OK; + } + 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; + *instruction_count = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_INPUT && shader_register_is_phase_instance_id( + &ins->declaration.dst.reg)) + { + *instruction_count = 0; + return VKD3D_OK; + } + 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 = normaliser->instructions.count; + else + *instruction_count = 0; + normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count); + return VKD3D_OK; + } + + if (normaliser->phase == VKD3DSIH_INVALID || shader_instruction_is_dcl(ins)) + return VKD3D_OK; + + if (ins->handler_idx == VKD3DSIH_MOV && shader_register_is_phase_instance_id(&ins->src->reg)) + { + if (ins->dst->reg.type != VKD3DSPR_TEMP) + { + FIXME("Instance id not assigned to temp register.\n"); + return VKD3D_OK; + } + /* Instance id always seems to be assigned to r{n}.x */ + if (ins->dst->write_mask != VKD3DSP_WRITEMASK_0) + FIXME("Unsupported write mask %#x.\n", ins->dst->write_mask); + if (ins->dst->reg.idx[0].offset >= sizeof(normaliser->temp_is_instance_id) * CHAR_BIT) + FIXME("Unsupported temp idx %u.\n", ins->dst->reg.idx[0].offset); + else + normaliser->temp_is_instance_id |= 1ull << ins->dst->reg.idx[0].offset; + *instruction_count = 0; + return VKD3D_OK; + } + + if (normaliser->phase_body_idx == ~0u) + normaliser->phase_body_idx = normaliser->instructions.count; + + if (ins->handler_idx != VKD3DSIH_RET) + return VKD3D_OK; + + count = normaliser->instructions.count - normaliser->phase_body_idx; + + if (!shader_instruction_array_reserve(&normaliser->instructions, count * (normaliser->instance_count - 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + /* Make a copy of the non-dcl instructions for each instance. */ + ins = &normaliser->instructions.elements[normaliser->phase_body_idx]; + for (i = 1; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + { + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, + normaliser->phase_body_idx + count * i + j, &ins[j])) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + } + /* Replace each reference to the instance id with a constant instance id. */ + for (i = 0; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + shader_instruction_eliminate_phase_instance_id( + &normaliser->instructions.elements[normaliser->phase_body_idx + count * i + j], i, normaliser); + } + + *instruction_count = count * (normaliser->instance_count - 1); + 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; +} + enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, const struct vkd3d_shader_parser *parser) { const struct vkd3d_shader_instruction_array *instructions = &parser->instructions; const struct vkd3d_shader_instruction *ins; enum vkd3d_result result = VKD3D_OK; - unsigned int i; + unsigned int i, instruction_count;
+ memset(normaliser, 0, sizeof(*normaliser)); + normaliser->phase = VKD3DSIH_INVALID; if (!shader_instruction_array_init(&normaliser->instructions, instructions->count)) { ERR("Failed to allocate instructions.\n"); @@ -109,7 +286,21 @@ enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *no if (!shader_instruction_array_clone_instruction(&normaliser->instructions, normaliser->instructions.count, ins)) return VKD3D_ERROR_OUT_OF_MEMORY;
- ++normaliser->instructions.count; + instruction_count = 1; + if ((result = shader_normaliser_eliminate_phase_instance_id(normaliser, &instruction_count)) < 0) + return result; + + normaliser->instructions.count += instruction_count; + } + + if (normaliser->phase != VKD3DSIH_INVALID) + { + if (normaliser->temp_dcl_idx) + normaliser->instructions.elements[normaliser->temp_dcl_idx].declaration.count = normaliser->max_temp_count; + + if (!shader_normaliser_new_instructions(normaliser, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + shader_instruction_init(&normaliser->instructions.elements[normaliser->instructions.count++], VKD3DSIH_RET); }
return result; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index aed6b51c..68591c31 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); @@ -6870,30 +6813,12 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler else spirv_compiler_emit_default_control_point_phase(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. */ + spirv_compiler_emit_hull_shader_barrier(compiler); + 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); vkd3d_spirv_build_op_function_end(builder); @@ -9699,10 +9624,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: @@ -10045,7 +9966,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_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c23c4475..dbe182b5 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1330,6 +1330,14 @@ 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; + uint64_t temp_is_instance_id; + + unsigned int instance_count; + unsigned int phase_body_idx; + enum vkd3d_shader_opcode phase; };
enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser,
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 | 142 ++++++++++++++------------------------ 1 file changed, 50 insertions(+), 92 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 68591c31..819681e4 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 compiler->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +} + +static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler) { - return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE; + 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]; - - phase->type = instruction->handler_idx; - phase->idx = compiler->shader_phase_count; - phase->function_id = 0; - phase->function_location = 0; - - ++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; + assert(compiler->phase != instruction->handler_idx);
- phase = &compiler->shader_phases[0]; - if (is_control_point_phase(phase)) - return phase; + if (spirv_compiler_get_current_shader_phase(compiler)) + spirv_compiler_leave_shader_phase(compiler);
- 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);
@@ -6817,8 +6777,7 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler * is to avoid use of private variables there, otherwise we would need a separate * patch constant epilogue also only called from invocation 0. */ spirv_compiler_emit_hull_shader_barrier(compiler); - 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); @@ -7500,10 +7459,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); @@ -9877,7 +9836,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;
@@ -9897,8 +9855,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
A 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 819681e4..3def1abf 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)
From: Conor McCarthy cmccarthy@codeweavers.com
A register count is required for Shader Model 6 signatures, including those normalised from earlier models. --- libs/vkd3d-shader/dxbc.c | 21 ++++---- libs/vkd3d-shader/spirv.c | 68 ++++++++++++------------ libs/vkd3d-shader/vkd3d_shader_main.c | 49 ++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 30 +++++++++-- 4 files changed, 119 insertions(+), 49 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 4041e0f5..045fa873 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -1591,7 +1591,7 @@ static const struct vkd3d_shader_parser_ops shader_sm4_parser_ops = };
static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t *byte_code, - size_t byte_code_size, const char *source_name, const struct vkd3d_shader_signature *output_signature, + size_t byte_code_size, const char *source_name, const struct vkd3d_shader_sm6_signature *output_signature, struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_version version; @@ -1659,7 +1659,7 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t memset(sm4->output_map, 0xff, sizeof(sm4->output_map)); for (i = 0; i < output_signature->element_count; ++i) { - struct vkd3d_shader_signature_element *e = &output_signature->elements[i]; + struct vkd3d_shader_sm6_signature_element *e = &output_signature->elements[i];
if (version.type == VKD3D_SHADER_TYPE_PIXEL && ascii_strcasecmp(e->semantic_name, "SV_Target")) @@ -1830,10 +1830,10 @@ static int parse_dxbc(const char *data, size_t data_size, }
static int shader_parse_signature(DWORD tag, const char *data, DWORD data_size, - struct vkd3d_shader_signature *s) + struct vkd3d_shader_sm6_signature *s) { + struct vkd3d_shader_sm6_signature_element *e; bool has_stream_index, has_min_precision; - struct vkd3d_shader_signature_element *e; const char *ptr = data; unsigned int i; uint32_t count; @@ -1884,6 +1884,7 @@ static int shader_parse_signature(DWORD tag, const char *data, DWORD data_size, read_dword(&ptr, &e[i].sysval_semantic); read_dword(&ptr, &e[i].component_type); read_dword(&ptr, &e[i].register_index); + e[i].register_count = 1; read_dword(&ptr, &mask); e[i].mask = mask & 0xff; e[i].used_mask = (mask >> 8) & 0xff; @@ -1917,7 +1918,7 @@ static int shader_parse_signature(DWORD tag, const char *data, DWORD data_size,
static int isgn_handler(const char *data, DWORD data_size, DWORD tag, void *ctx) { - struct vkd3d_shader_signature *is = ctx; + struct vkd3d_shader_sm6_signature *is = ctx;
if (tag != TAG_ISGN) return VKD3D_OK; @@ -1925,13 +1926,13 @@ static int isgn_handler(const char *data, DWORD data_size, DWORD tag, void *ctx) if (is->elements) { FIXME("Multiple input signatures.\n"); - vkd3d_shader_free_shader_signature(is); + vkd3d_shader_sm6_free_shader_signature(is); } return shader_parse_signature(tag, data, data_size, is); }
int shader_parse_input_signature(const void *dxbc, size_t dxbc_length, - struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_signature *signature) + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_sm6_signature *signature) { int ret;
@@ -2009,9 +2010,9 @@ static int shdr_handler(const char *data, DWORD data_size, DWORD tag, void *cont
void free_shader_desc(struct vkd3d_shader_desc *desc) { - vkd3d_shader_free_shader_signature(&desc->input_signature); - vkd3d_shader_free_shader_signature(&desc->output_signature); - vkd3d_shader_free_shader_signature(&desc->patch_constant_signature); + vkd3d_shader_sm6_free_shader_signature(&desc->input_signature); + vkd3d_shader_sm6_free_shader_signature(&desc->output_signature); + vkd3d_shader_sm6_free_shader_signature(&desc->patch_constant_signature); }
static int shader_extract_from_dxbc(const void *dxbc, size_t dxbc_length, diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 3def1abf..4e104d95 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2250,9 +2250,9 @@ struct spirv_compiler const struct vkd3d_shader_spirv_target_info *spirv_target_info;
bool after_declarations_section; - const struct vkd3d_shader_signature *input_signature; - const struct vkd3d_shader_signature *output_signature; - const struct vkd3d_shader_signature *patch_constant_signature; + const struct vkd3d_shader_sm6_signature *input_signature; + const struct vkd3d_shader_sm6_signature *output_signature; + const struct vkd3d_shader_sm6_signature *patch_constant_signature; const struct vkd3d_shader_transform_feedback_info *xfb_info; struct vkd3d_shader_output_info { @@ -2315,8 +2315,8 @@ struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_version * const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info, struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location) { - const struct vkd3d_shader_signature *patch_constant_signature = &shader_desc->patch_constant_signature; - const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature; + const struct vkd3d_shader_sm6_signature *patch_constant_signature = &shader_desc->patch_constant_signature; + const struct vkd3d_shader_sm6_signature *output_signature = &shader_desc->output_signature; const struct vkd3d_shader_interface_info *shader_interface; const struct vkd3d_shader_descriptor_offset_info *offset_info; const struct vkd3d_shader_spirv_target_info *target_info; @@ -4256,8 +4256,8 @@ static const struct vkd3d_spirv_builtin *vkd3d_get_spirv_builtin(const struct sp return NULL; }
-static const struct vkd3d_shader_signature_element *vkd3d_find_signature_element_for_reg( - const struct vkd3d_shader_signature *signature, unsigned int *signature_element_index, +static const struct vkd3d_shader_sm6_signature_element *vkd3d_find_signature_element_for_reg( + const struct vkd3d_shader_sm6_signature *signature, unsigned int *signature_element_index, unsigned int reg_idx, DWORD write_mask) { unsigned int signature_idx; @@ -4340,7 +4340,7 @@ static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( }
static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, - uint32_t id, unsigned int component_count, const struct vkd3d_shader_signature_element *signature_element) + uint32_t id, unsigned int component_count, const struct vkd3d_shader_sm6_signature_element *signature_element) { const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info; const struct vkd3d_shader_transform_feedback_element *xfb_element; @@ -4421,7 +4421,7 @@ static uint32_t spirv_compiler_emit_builtin_variable(struct spirv_compiler *comp return id; }
-static bool needs_private_io_variable(const struct vkd3d_shader_signature *signature, +static bool needs_private_io_variable(const struct vkd3d_shader_sm6_signature *signature, unsigned int reg_idx, const struct vkd3d_spirv_builtin *builtin, unsigned int *component_count, unsigned int *out_write_mask) { @@ -4441,7 +4441,7 @@ static bool needs_private_io_variable(const struct vkd3d_shader_signature *signa
for (i = 0, count = 0; i < signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *current = &signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *current = &signature->elements[i];
if (current->register_index != reg_idx) continue; @@ -4475,9 +4475,9 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval, enum vkd3d_shader_interpolation_mode interpolation_mode) { + const struct vkd3d_shader_sm6_signature_element *signature_element; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature_element *signature_element; - const struct vkd3d_shader_signature *shader_signature; + const struct vkd3d_shader_sm6_signature *shader_signature; const struct vkd3d_shader_register *reg = &dst->reg; unsigned int component_idx, input_component_count; enum vkd3d_shader_component_type component_type; @@ -4784,7 +4784,7 @@ static bool is_dual_source_blending(const struct spirv_compiler *compiler) return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->dual_source_blending; }
-static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signature_element *e, +static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_sm6_signature_element *e, uint32_t *mask) { if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE) @@ -4797,9 +4797,9 @@ static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signa }
static uint32_t calculate_sysval_array_mask(struct spirv_compiler *compiler, - const struct vkd3d_shader_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval) + const struct vkd3d_shader_sm6_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval) { - const struct vkd3d_shader_signature_element *e; + const struct vkd3d_shader_sm6_signature_element *e; const struct vkd3d_spirv_builtin *sig_builtin; const struct vkd3d_spirv_builtin *builtin; uint32_t signature_idx, mask = 0; @@ -4827,7 +4827,7 @@ static uint32_t calculate_sysval_array_mask(struct spirv_compiler *compiler, /* Emits arrayed SPIR-V built-in variables. */ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *output_signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *output_signature = compiler->output_signature; uint32_t clip_distance_mask = 0, clip_distance_id = 0; uint32_t cull_distance_mask = 0, cull_distance_id = 0; const struct vkd3d_spirv_builtin *builtin; @@ -4835,7 +4835,7 @@ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *
for (i = 0; i < output_signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *e = &output_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *e = &output_signature->elements[i];
switch (e->sysval_semantic) { @@ -4870,7 +4870,7 @@ static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *
for (i = 0; i < output_signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *e = &output_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *e = &output_signature->elements[i];
switch (e->sysval_semantic) { @@ -4953,9 +4953,9 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval) { + const struct vkd3d_shader_sm6_signature_element *signature_element; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature_element *signature_element; - const struct vkd3d_shader_signature *shader_signature; + const struct vkd3d_shader_sm6_signature *shader_signature; const struct vkd3d_shader_register *reg = &dst->reg; unsigned int component_idx, output_component_count; enum vkd3d_shader_component_type component_type; @@ -5126,7 +5126,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *compiler, - const struct vkd3d_shader_signature_element *e) + const struct vkd3d_shader_sm6_signature_element *e) { enum vkd3d_shader_input_sysval_semantic sysval; const struct vkd3d_spirv_builtin *builtin; @@ -5145,14 +5145,14 @@ static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *com }
static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compiler, - const struct vkd3d_shader_signature *signature, const struct vkd3d_shader_signature_element *output, + const struct vkd3d_shader_sm6_signature *signature, const struct vkd3d_shader_sm6_signature_element *output, const struct vkd3d_shader_output_info *output_info, uint32_t output_index_id, uint32_t val_id, unsigned int write_mask) { unsigned int dst_write_mask, use_mask, uninit_mask, swizzle, mask; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id; - const struct vkd3d_shader_signature_element *element; + const struct vkd3d_shader_sm6_signature_element *element; unsigned int i, index, array_idx; uint32_t output_id;
@@ -5241,7 +5241,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * uint32_t param_type_id[MAX_REG_OUTPUT + 1], param_id[MAX_REG_OUTPUT + 1] = {0}; uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature *signature; + const struct vkd3d_shader_sm6_signature *signature; uint32_t output_index_id = 0; bool is_patch_constant; unsigned int i, count; @@ -5326,7 +5326,7 @@ static void spirv_compiler_emit_hull_shader_builtins(struct spirv_compiler *comp
static void spirv_compiler_emit_hull_shader_patch_constants(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *signature = compiler->patch_constant_signature; + const struct vkd3d_shader_sm6_signature *signature = compiler->patch_constant_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t register_count = 0; unsigned int signature_idx; @@ -6441,7 +6441,7 @@ static void spirv_compiler_emit_dcl_thread_group(struct spirv_compiler *compiler
static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *signature = compiler->output_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_symbol reg_symbol, *symbol; struct vkd3d_shader_register reg; @@ -6478,7 +6478,7 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler)
for (i = 0; i < signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *e = &signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *e = &signature->elements[i];
reg.type = VKD3DSPR_OUTPUT; reg.idx[0].offset = e->register_index; @@ -6537,8 +6537,8 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *output_signature = compiler->output_signature; - const struct vkd3d_shader_signature *input_signature = compiler->input_signature; + const struct vkd3d_shader_sm6_signature *output_signature = compiler->output_signature; + const struct vkd3d_shader_sm6_signature *input_signature = compiler->input_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; enum vkd3d_shader_component_type component_type; uint32_t input_id, output_id, dst_id, src_id; @@ -6569,8 +6569,8 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile assert(input_signature->element_count == output_signature->element_count); for (i = 0; i < output_signature->element_count; ++i) { - const struct vkd3d_shader_signature_element *output = &output_signature->elements[i]; - const struct vkd3d_shader_signature_element *input = &input_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *output = &output_signature->elements[i]; + const struct vkd3d_shader_sm6_signature_element *input = &input_signature->elements[i];
assert(input->mask == output->mask); assert(input->component_type == output->component_type); @@ -6626,10 +6626,10 @@ static void spirv_compiler_emit_hull_shader_barrier(struct spirv_compiler *compi static void spirv_compiler_emit_hull_shader_input_initialisation(struct spirv_compiler *compiler) { uint32_t type_id, length_id, register_index_id, src_array_id, dst_array_id, vicp_id, tmp_id; - const struct vkd3d_shader_signature *signature = compiler->input_signature; + const struct vkd3d_shader_sm6_signature *signature = compiler->input_signature; uint32_t src_type_id, dst_type_id, src_id, dst_id, point_index_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_signature_element *element; + const struct vkd3d_shader_sm6_signature_element *element; enum vkd3d_shader_input_sysval_semantic sysval; const struct vkd3d_spirv_builtin *builtin; struct vkd3d_symbol *symbol, symbol_key; @@ -9401,7 +9401,7 @@ static void spirv_compiler_emit_cut_stream(struct spirv_compiler *compiler,
static void spirv_compiler_emit_hull_shader_inputs(struct spirv_compiler *compiler) { - const struct vkd3d_shader_signature *signature = compiler->input_signature; + const struct vkd3d_shader_sm6_signature *signature = compiler->input_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, length_id, vicp_id, vicp_type_id; unsigned int register_count, register_idx, i; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index f5038eb7..3a775e82 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1390,10 +1390,53 @@ void vkd3d_shader_free_root_signature(struct vkd3d_shader_versioned_root_signatu desc->version = 0; }
+static bool shader_signature_from_shader_sm6_signature(struct vkd3d_shader_signature *signature, + const struct vkd3d_shader_sm6_signature *src) +{ + unsigned int i; + + signature->element_count = src->element_count; + if (!src->elements) + { + signature->elements = NULL; + return true; + } + + if (!(signature->elements = vkd3d_malloc(signature->element_count * sizeof(*signature->elements)))) + return false; + + for (i = 0; i < signature->element_count; ++i) + { + struct vkd3d_shader_sm6_signature_element *e = &src->elements[i]; + struct vkd3d_shader_signature_element *d = &signature->elements[i]; + + d->semantic_name = e->semantic_name; + d->semantic_index = e->semantic_index; + d->stream_index = e->stream_index; + d->sysval_semantic = e->sysval_semantic; + d->component_type = e->component_type; + d->register_index = e->register_index; + if (e->register_count > 1) + FIXME("Arrayed elements are not supported yet.\n"); + d->mask = e->mask; + d->used_mask = e->used_mask; + d->min_precision = e->min_precision; + } + + return true; +} + +void vkd3d_shader_sm6_free_shader_signature(struct vkd3d_shader_sm6_signature *signature) +{ + vkd3d_free(signature->elements); + signature->elements = NULL; +} + int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_signature *signature, char **messages) { struct vkd3d_shader_message_context message_context; + struct vkd3d_shader_sm6_signature sm6_signature; int ret;
TRACE("dxbc {%p, %zu}, signature %p, messages %p.\n", dxbc->code, dxbc->size, signature, messages); @@ -1402,13 +1445,17 @@ int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, *messages = NULL; vkd3d_shader_message_context_init(&message_context, VKD3D_SHADER_LOG_INFO);
- ret = shader_parse_input_signature(dxbc->code, dxbc->size, &message_context, signature); + ret = shader_parse_input_signature(dxbc->code, dxbc->size, &message_context, &sm6_signature); vkd3d_shader_message_context_trace_messages(&message_context); if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) ret = VKD3D_ERROR_OUT_OF_MEMORY;
vkd3d_shader_message_context_cleanup(&message_context);
+ if (!shader_signature_from_shader_sm6_signature(signature, &sm6_signature)) + ret = VKD3D_ERROR_OUT_OF_MEMORY; + + vkd3d_shader_sm6_free_shader_signature(&sm6_signature); return ret; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index dbe182b5..79758369 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -771,13 +771,35 @@ enum vkd3d_shader_input_sysval_semantic VKD3D_SIV_LINE_DENSITY_TESS_FACTOR = 22, };
+struct vkd3d_shader_sm6_signature_element +{ + const char *semantic_name; + unsigned int semantic_index; + unsigned int stream_index; + enum vkd3d_shader_sysval_semantic sysval_semantic; + enum vkd3d_shader_component_type component_type; + unsigned int register_index; + unsigned int register_count; + unsigned int mask; + unsigned int used_mask; + enum vkd3d_shader_minimum_precision min_precision; +}; + +struct vkd3d_shader_sm6_signature +{ + struct vkd3d_shader_sm6_signature_element *elements; + unsigned int element_count; +}; + +void vkd3d_shader_sm6_free_shader_signature(struct vkd3d_shader_sm6_signature *signature); + struct vkd3d_shader_desc { const uint32_t *byte_code; size_t byte_code_size; - struct vkd3d_shader_signature input_signature; - struct vkd3d_shader_signature output_signature; - struct vkd3d_shader_signature patch_constant_signature; + struct vkd3d_shader_sm6_signature input_signature; + struct vkd3d_shader_sm6_signature output_signature; + struct vkd3d_shader_sm6_signature patch_constant_signature; };
struct vkd3d_shader_register_semantic @@ -1126,7 +1148,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi void free_shader_desc(struct vkd3d_shader_desc *desc);
int shader_parse_input_signature(const void *dxbc, size_t dxbc_length, - struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_signature *signature); + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_sm6_signature *signature);
struct vkd3d_glsl_generator;
From: Conor McCarthy cmccarthy@codeweavers.com
In SPIR-V the address must include the invocation id, but in TPF it is implicit. Move the register index up one slot and insert an OUTPOINTID relative address. --- libs/vkd3d-shader/normalise.c | 85 ++++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 29 ++------ libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 3 files changed, 92 insertions(+), 24 deletions(-)
diff --git a/libs/vkd3d-shader/normalise.c b/libs/vkd3d-shader/normalise.c index 23c25514..22773eb3 100644 --- a/libs/vkd3d-shader/normalise.c +++ b/libs/vkd3d-shader/normalise.c @@ -153,6 +153,11 @@ static bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instr return true; }
+static bool normaliser_is_in_control_point_phase(const struct vkd3d_shader_normaliser *normaliser) +{ + return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +} + 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; @@ -254,12 +259,82 @@ static enum vkd3d_result shader_normaliser_eliminate_phase_instance_id(struct vk return VKD3D_OK; }
+static void shader_register_init(struct vkd3d_shader_register *reg, + enum vkd3d_shader_register_type reg_type, enum vkd3d_data_type data_type) +{ + reg->type = reg_type; + reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + reg->non_uniform = false; + reg->data_type = data_type; + 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; +} + +static struct vkd3d_shader_src_param *shader_normaliser_create_outpointid_param(struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_src_param *rel_addr; + + if (!(rel_addr = shader_src_param_allocator_get(&normaliser->instructions.src_params, 1))) + return NULL; + + shader_register_init(&rel_addr->reg, VKD3DSPR_OUTPOINTID, VKD3D_DATA_UINT); + rel_addr->swizzle = 0; + rel_addr->modifiers = 0; + + return rel_addr; +} + +static void shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_param, + struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_register *reg = &dst_param->reg; + unsigned int id_idx; + + id_idx = reg->idx[1].offset != ~0u ? 1 : 0; + + if (normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) + { + assert(!id_idx); + reg->idx[1] = reg->idx[0]; + /* The control point id param is implicit here. Avoid later complications by inserting it. */ + reg->idx[0].offset = 0; + reg->idx[0].rel_addr = normaliser->outpointid_param; + } +} + 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; }
+static void shader_instruction_normalise_io_params(struct vkd3d_shader_instruction *ins, + struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i; + + switch (ins->handler_idx) + { + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + normaliser->phase = ins->handler_idx; + 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], + normaliser); + break; + } +} + enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, const struct vkd3d_shader_parser *parser) { @@ -275,6 +350,12 @@ enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *no ERR("Failed to allocate instructions.\n"); return VKD3D_ERROR_OUT_OF_MEMORY; } + if (parser->shader_version.type == VKD3D_SHADER_TYPE_HULL + && !(normaliser->outpointid_param = shader_normaliser_create_outpointid_param(normaliser))) + { + ERR("Failed to allocate src param.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + }
for (i = 0; i < instructions->count; ++i) { @@ -303,6 +384,10 @@ enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *no shader_instruction_init(&normaliser->instructions.elements[normaliser->instructions.count++], VKD3DSIH_RET); }
+ normaliser->phase = VKD3DSIH_INVALID; + for (i = 0; i < normaliser->instructions.count; ++i) + shader_instruction_normalise_io_params(&normaliser->instructions.elements[i], normaliser); + return result; }
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 4e104d95..204db5a6 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1971,7 +1971,6 @@ struct vkd3d_symbol_register_data unsigned int structure_stride; unsigned int binding_base_idx; bool is_aggregate; /* An aggregate, i.e. a structure or an array. */ - bool is_dynamically_indexed; /* If member_idx is a variable ID instead of a constant. */ };
struct vkd3d_symbol_resource_data @@ -2064,7 +2063,7 @@ 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) && reg->idx[1].offset != ~0u) + 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; else if (reg->type != VKD3DSPR_IMMCONSTBUFFER) symbol->key.reg.idx = reg->idx[0].offset; @@ -2084,7 +2083,6 @@ static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol, symbol->info.reg.structure_stride = 0; symbol->info.reg.binding_base_idx = 0; symbol->info.reg.is_aggregate = false; - symbol->info.reg.is_dynamically_indexed = false; }
static void vkd3d_symbol_make_resource(struct vkd3d_symbol *symbol, @@ -3171,7 +3169,6 @@ struct vkd3d_shader_register_info unsigned int structure_stride; unsigned int binding_base_idx; bool is_aggregate; - bool is_dynamically_indexed; };
static bool spirv_compiler_get_register_info(const struct spirv_compiler *compiler, @@ -3194,7 +3191,6 @@ static bool spirv_compiler_get_register_info(const struct spirv_compiler *compil register_info->structure_stride = 0; register_info->binding_base_idx = 0; register_info->is_aggregate = false; - register_info->is_dynamically_indexed = false; return true; }
@@ -3216,7 +3212,6 @@ static bool spirv_compiler_get_register_info(const struct spirv_compiler *compil register_info->structure_stride = symbol->info.reg.structure_stride; register_info->binding_base_idx = symbol->info.reg.binding_base_idx; register_info->is_aggregate = symbol->info.reg.is_aggregate; - register_info->is_dynamically_indexed = symbol->info.reg.is_dynamically_indexed;
return true; } @@ -3361,17 +3356,8 @@ static void spirv_compiler_emit_dereference_register(struct spirv_compiler *comp if (reg->idx[1].rel_addr) FIXME("Relative addressing not implemented.\n");
- if (register_info->is_dynamically_indexed) - { - indexes[index_count++] = vkd3d_spirv_build_op_load(builder, - vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1), - register_info->member_idx, SpvMemoryAccessMaskNone); - } - else - { - reg_idx.offset = register_info->member_idx; - indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®_idx); - } + reg_idx.offset = register_info->member_idx; + indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®_idx); } } else @@ -5090,12 +5076,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_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; - } - else if (is_patch_constant) + if (is_patch_constant) { reg_symbol.info.reg.member_idx = reg->idx[0].offset; } @@ -6467,7 +6448,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) }
memset(®, 0, sizeof(reg)); - reg.idx[1].offset = ~0u;
/* Fork and join phases share output registers (patch constants). * Control point phase has separate output registers. */ @@ -6482,6 +6462,7 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler)
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))) { diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 79758369..e9b8b04d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1360,6 +1360,8 @@ struct vkd3d_shader_normaliser unsigned int instance_count; unsigned int phase_body_idx; enum vkd3d_shader_opcode phase; + + struct vkd3d_shader_src_param *outpointid_param; };
enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 204db5a6..0c56e8fb 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -6545,7 +6545,6 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile input_reg.data_type = VKD3D_DATA_FLOAT; input_reg.idx[0].rel_addr = &invocation; input_reg.idx[2].offset = ~0u; - input_id = spirv_compiler_get_register_id(compiler, &input_reg);
assert(input_signature->element_count == output_signature->element_count); for (i = 0; i < output_signature->element_count; ++i)
From: Conor McCarthy cmccarthy@codeweavers.com
The SPIR-V backend will emit a default control point phase. Inserting inputs into the IR allows handling of declarations via the usual path instead of an ad hoc implementation which may not match later changes to input handling. --- libs/vkd3d-shader/normalise.c | 81 +++++++++- libs/vkd3d-shader/spirv.c | 179 +++-------------------- libs/vkd3d-shader/vkd3d_shader_private.h | 12 +- 3 files changed, 108 insertions(+), 164 deletions(-)
diff --git a/libs/vkd3d-shader/normalise.c b/libs/vkd3d-shader/normalise.c index 22773eb3..0bd05e3f 100644 --- a/libs/vkd3d-shader/normalise.c +++ b/libs/vkd3d-shader/normalise.c @@ -29,6 +29,11 @@ static bool shader_instruction_is_dcl(const struct vkd3d_shader_instruction *ins || ins->handler_idx == VKD3DSIH_HS_DECLS; }
+static bool shader_instruction_is_fork_or_join_phase(const struct vkd3d_shader_instruction *ins) +{ + return ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE; +} + static inline bool shader_normaliser_new_instructions(struct vkd3d_shader_normaliser *normaliser, unsigned int extra) { return shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + extra); @@ -313,6 +318,61 @@ static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum v ins->handler_idx = handler_idx; }
+static inline void shader_dst_param_io_init(struct vkd3d_shader_dst_param *param, + const struct vkd3d_shader_sm6_signature_element *e, enum vkd3d_shader_register_type reg_type) +{ + param->write_mask = e->mask; + param->modifiers = 0; + param->shift = 0; + shader_register_init(¶m->reg, reg_type, vkd3d_data_type_from_component_type(e->component_type)); +} + +static enum vkd3d_result shader_normaliser_emit_hs_input(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_sm6_signature *s) +{ + const struct vkd3d_shader_sm6_signature_element *e; + struct vkd3d_shader_instruction *ins; + struct vkd3d_shader_dst_param *param; + unsigned int i; + + if (!shader_normaliser_new_instructions(normaliser, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &normaliser->instructions.elements[normaliser->instructions.count++]; + shader_instruction_init(ins, VKD3DSIH_HS_CONTROL_POINT_PHASE); + ins->flags = 1; + + for (i = 0; i < s->element_count; ++i) + { + e = &s->elements[i]; + if (!e->used_mask) + continue; + + if (!shader_normaliser_new_instructions(normaliser, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &normaliser->instructions.elements[normaliser->instructions.count++]; + + if (e->sysval_semantic != VKD3D_SHADER_SV_NONE) + { + shader_instruction_init(ins, VKD3DSIH_DCL_INPUT_SIV); + param = &ins->declaration.register_semantic.reg; + ins->declaration.register_semantic.sysval_semantic = vkd3d_siv_from_sysval(e->sysval_semantic); + } + else + { + shader_instruction_init(ins, VKD3DSIH_DCL_INPUT); + param = &ins->declaration.dst; + } + + shader_dst_param_io_init(param, e, VKD3DSPR_INPUT); + param->reg.idx[0].offset = normaliser->input_control_point_count; + param->reg.idx[1].offset = i; + } + + return VKD3D_OK; +} + static void shader_instruction_normalise_io_params(struct vkd3d_shader_instruction *ins, struct vkd3d_shader_normaliser *normaliser) { @@ -336,7 +396,7 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi }
enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, - const struct vkd3d_shader_parser *parser) + const struct vkd3d_shader_parser *parser, const struct vkd3d_shader_sm6_signature *input_signature) { const struct vkd3d_shader_instruction_array *instructions = &parser->instructions; const struct vkd3d_shader_instruction *ins; @@ -364,6 +424,13 @@ enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *no
ins = &instructions->elements[i];
+ if (shader_instruction_is_fork_or_join_phase(ins) + && !normaliser->has_control_point_phase && !normaliser_is_in_fork_or_join_phase(normaliser) + && (result = shader_normaliser_emit_hs_input(normaliser, input_signature)) < 0) + { + return result; + } + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, normaliser->instructions.count, ins)) return VKD3D_ERROR_OUT_OF_MEMORY;
@@ -371,6 +438,18 @@ enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *no if ((result = shader_normaliser_eliminate_phase_instance_id(normaliser, &instruction_count)) < 0) return result;
+ switch (ins->handler_idx) + { + case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT: + normaliser->input_control_point_count = ins->declaration.count; + break; + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + normaliser->has_control_point_phase = true; + break; + default: + break; + } + normaliser->instructions.count += instruction_count; }
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 0c56e8fb..2166a73f 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -168,7 +168,7 @@ static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv,
#endif /* HAVE_SPIRV_TOOLS */
-static enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d_shader_sysval_semantic sysval, +enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d_shader_sysval_semantic sysval, unsigned int index) { switch (sysval) @@ -199,11 +199,6 @@ static enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enu } }
-static enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval(enum vkd3d_shader_sysval_semantic sysval) -{ - return vkd3d_siv_from_sysval_indexed(sysval, 0); -} - #define VKD3D_SPIRV_VERSION 0x00010000 #define VKD3D_SPIRV_GENERATOR_ID 18 #define VKD3D_SPIRV_GENERATOR_VERSION 6 @@ -2271,6 +2266,7 @@ struct spirv_compiler bool use_vocp;
enum vkd3d_shader_opcode phase; + bool emit_default_control_point_phase; struct vkd3d_shader_phase control_point_phase; struct vkd3d_shader_phase patch_constant_phase;
@@ -6420,6 +6416,8 @@ static void spirv_compiler_emit_dcl_thread_group(struct spirv_compiler *compiler SpvExecutionModeLocalSize, local_size, ARRAY_SIZE(local_size)); }
+static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler); + static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) { const struct vkd3d_shader_sm6_signature *signature = compiler->output_signature; @@ -6429,6 +6427,9 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) 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); + vkd3d_spirv_build_op_function_end(builder);
compiler->temp_id = 0; @@ -6514,6 +6515,9 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, ? &compiler->control_point_phase : &compiler->patch_constant_phase; phase->function_id = function_id; phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); + + if (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE) + compiler->emit_default_control_point_phase = instruction->flags; }
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) @@ -6522,10 +6526,10 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile const struct vkd3d_shader_sm6_signature *input_signature = compiler->input_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; enum vkd3d_shader_component_type component_type; - uint32_t input_id, output_id, dst_id, src_id; struct vkd3d_shader_src_param invocation; struct vkd3d_shader_register input_reg; uint32_t type_id, output_ptr_type_id; + uint32_t output_id, dst_id, src_id; unsigned int component_count; uint32_t invocation_id; unsigned int i; @@ -6556,9 +6560,7 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile assert(input->component_type == output->component_type);
input_reg.idx[1].offset = input->register_index; - input_id = spirv_compiler_get_register_id(compiler, &input_reg); - type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 4); - src_id = vkd3d_spirv_build_op_load(builder, type_id, input_id, SpvMemoryAccessMaskNone); + src_id = spirv_compiler_get_register_id(compiler, &input_reg);
component_type = output->component_type; component_count = vkd3d_write_mask_component_count(output->mask); @@ -6572,9 +6574,10 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile 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);
- spirv_compiler_emit_store(compiler, dst_id, output->mask, - component_type, SpvStorageClassOutput, VKD3DSP_WRITEMASK_ALL, src_id); + vkd3d_spirv_build_op_copy_memory(builder, dst_id, src_id, SpvMemoryAccessMaskNone); } + + vkd3d_spirv_build_op_return(builder); }
static void spirv_compiler_emit_barrier(struct spirv_compiler *compiler, @@ -6603,95 +6606,6 @@ static void spirv_compiler_emit_hull_shader_barrier(struct spirv_compiler *compi SpvScopeWorkgroup, SpvScopeInvocation, SpvMemorySemanticsMaskNone); }
-static void spirv_compiler_emit_hull_shader_input_initialisation(struct spirv_compiler *compiler) -{ - uint32_t type_id, length_id, register_index_id, src_array_id, dst_array_id, vicp_id, tmp_id; - const struct vkd3d_shader_sm6_signature *signature = compiler->input_signature; - uint32_t src_type_id, dst_type_id, src_id, dst_id, point_index_id; - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_sm6_signature_element *element; - enum vkd3d_shader_input_sysval_semantic sysval; - const struct vkd3d_spirv_builtin *builtin; - struct vkd3d_symbol *symbol, symbol_key; - unsigned int register_count, i, j; - struct vkd3d_shader_register r; - struct rb_entry *entry; - uint32_t indices[2]; - - for (i = 0, register_count = 0; i < signature->element_count; ++i) - { - register_count = max(register_count, signature->elements[i].register_index + 1); - } - - type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 4); - length_id = spirv_compiler_get_constant_uint(compiler, compiler->input_control_point_count); - type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); - type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id); - - memset(&r, 0, sizeof(r)); - r.type = VKD3DSPR_INPUT; - r.idx[0].offset = 0; - r.idx[1].offset = ~0u; - vkd3d_symbol_make_register(&symbol_key, &r); - - for (i = 0; i < signature->element_count; ++i) - { - element = &signature->elements[i]; - - symbol_key.key.reg.idx = element->register_index; - entry = rb_get(&compiler->symbol_table, &symbol_key); - symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - - vicp_id = symbol->id; - register_index_id = spirv_compiler_get_constant_uint(compiler, element->register_index); - dst_array_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, type_id, vicp_id, register_index_id); - - if (element->sysval_semantic) - { - sysval = vkd3d_siv_from_sysval(element->sysval_semantic); - builtin = get_spirv_builtin_for_sysval(compiler, sysval); - src_array_id = spirv_compiler_emit_builtin_variable(compiler, builtin, - SpvStorageClassInput, compiler->input_control_point_count); - - if (builtin->component_count == 4) - { - vkd3d_spirv_build_op_copy_memory(builder, dst_array_id, src_array_id, SpvMemoryAccessMaskNone); - } - else - { - tmp_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, builtin->component_count); - src_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, tmp_id); - dst_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, tmp_id); - - for (j = 0; j < compiler->input_control_point_count; ++j) - { - point_index_id = spirv_compiler_get_constant_uint(compiler, j); - src_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, - src_type_id, src_array_id, point_index_id); - - indices[0] = point_index_id; - indices[1] = spirv_compiler_get_constant_uint(compiler, 0); - dst_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder, - dst_type_id, dst_array_id, indices, 2); - - vkd3d_spirv_build_op_copy_memory(builder, dst_id, src_id, SpvMemoryAccessMaskNone); - } - } - } - else - { - src_array_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, - SpvStorageClassInput, VKD3D_SHADER_COMPONENT_FLOAT, 4, compiler->input_control_point_count); - vkd3d_spirv_add_iface_variable(builder, src_array_id); - vkd3d_spirv_build_op_decorate1(builder, src_array_id, SpvDecorationLocation, element->register_index); - vkd3d_spirv_build_op_name(builder, src_array_id, "v%u", element->register_index); - - vkd3d_spirv_build_op_copy_memory(builder, dst_array_id, src_array_id, SpvMemoryAccessMaskNone); - } - symbol->info.reg.dcl_mask |= element->mask; - } -} - static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler *compiler) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; @@ -6738,14 +6652,9 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler
vkd3d_spirv_builder_begin_main_function(builder);
- spirv_compiler_emit_hull_shader_input_initialisation(compiler); - void_id = vkd3d_spirv_get_op_type_void(builder);
- 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); + vkd3d_spirv_build_op_function_call(builder, void_id, compiler->control_point_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 @@ -9379,58 +9288,6 @@ static void spirv_compiler_emit_cut_stream(struct spirv_compiler *compiler, vkd3d_spirv_build_op_end_primitive(builder); }
-static void spirv_compiler_emit_hull_shader_inputs(struct spirv_compiler *compiler) -{ - const struct vkd3d_shader_sm6_signature *signature = compiler->input_signature; - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t type_id, length_id, vicp_id, vicp_type_id; - unsigned int register_count, register_idx, i; - struct vkd3d_shader_register r; - struct vkd3d_symbol symbol; - struct rb_entry *entry; - - for (i = 0, register_count = 0; i < signature->element_count; ++i) - { - register_count = max(register_count, signature->elements[i].register_index + 1); - } - - type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 4); - length_id = spirv_compiler_get_constant_uint(compiler, compiler->input_control_point_count); - type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); - length_id = spirv_compiler_get_constant_uint(compiler, register_count); - type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); - vicp_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id); - - vicp_id = vkd3d_spirv_build_op_variable(builder, - &builder->global_stream, vicp_type_id, SpvStorageClassPrivate, 0); - vkd3d_spirv_build_op_name(builder, vicp_id, "vicp"); - - memset(&r, 0, sizeof(r)); - r.type = VKD3DSPR_INPUT; - r.idx[0].offset = 0; - r.idx[1].offset = ~0u; - vkd3d_symbol_make_register(&symbol, &r); - - for (i = 0; i < signature->element_count; ++i) - { - register_idx = signature->elements[i].register_index; - - symbol.key.reg.idx = register_idx; - if ((entry = rb_get(&compiler->symbol_table, &symbol))) - { - struct vkd3d_symbol *s = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - s->info.reg.dcl_mask |= signature->elements[i].mask; - continue; - } - - vkd3d_symbol_set_register_info(&symbol, vicp_id, SpvStorageClassPrivate, - VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL); - symbol.info.reg.dcl_mask = signature->elements[i].mask; - symbol.info.reg.is_aggregate = true; - spirv_compiler_put_symbol(compiler, &symbol); - } -} - /* This function is called after declarations are processed. */ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler) { @@ -9439,8 +9296,6 @@ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler) if (compiler->xfb_info && compiler->xfb_info->element_count && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY) spirv_compiler_emit_point_size(compiler); - if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) - spirv_compiler_emit_hull_shader_inputs(compiler); }
static bool is_dcl_instruction(enum vkd3d_shader_opcode handler_idx) @@ -9815,7 +9670,7 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { - if ((result = shader_normaliser_normalise(&normaliser, parser)) < 0) + if ((result = shader_normaliser_normalise(&normaliser, parser, compiler->input_signature)) < 0) return result; instructions = &normaliser.instructions; } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index e9b8b04d..501f122f 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1221,6 +1221,14 @@ static inline enum vkd3d_data_type vkd3d_data_type_from_component_type( } }
+enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d_shader_sysval_semantic sysval, + unsigned int index); + +static inline enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval(enum vkd3d_shader_sysval_semantic sysval) +{ + return vkd3d_siv_from_sysval_indexed(sysval, 0); +} + static inline unsigned int vkd3d_write_mask_get_component_idx(DWORD write_mask) { unsigned int i; @@ -1360,12 +1368,14 @@ struct vkd3d_shader_normaliser unsigned int instance_count; unsigned int phase_body_idx; enum vkd3d_shader_opcode phase; + bool has_control_point_phase; + unsigned int input_control_point_count;
struct vkd3d_shader_src_param *outpointid_param; };
enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, - const struct vkd3d_shader_parser *parser); + const struct vkd3d_shader_parser *parser, const struct vkd3d_shader_sm6_signature *input_signature); void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser);
#endif /* __VKD3D_SHADER_PRIVATE_H */
I revised the last patch to remove some unnecessary changes, and inserted another patch to delete a line which does nothing useful. That should be the end of the edits.
Patch 7/8 ("vkd3d-shader/spirv: Delete an unnecessary call to spirv_compiler_get_register_id().") is pretty much independent from this series, and could just go in as a separate MR.
Patches 8/8 ("vkd3d-shader/normalise: Insert hull shader control point input declarations if no control point phase is defined.") and 6/8 ("vkd3d-shader/normalise: Normalise control point phase output registers to include the control point id.") are probably significant enough on their own that they could be split off as well.
The changes from patch 5/8 ("vkd3d-shader: Introduce an internal sm6 signature structure.") don't seem needed by this series, and I imagine they won't be needed until the actual shader model 6 bits start getting introduced.
That leaves the first four patches in this series.
From patch 1/8:
diff --git a/libs/vkd3d-shader/normalise.c b/libs/vkd3d-shader/normalise.c new file mode 100644 index 00000000..cb0c48a0 --- /dev/null +++ b/libs/vkd3d-shader/normalise.c @@ -0,0 +1,121 @@
I imagine the scope of this file may end up being a bit broader than normalisation; it seems like we'd want to put (LL)IR transformations in general in here. I don't think we necessarily need to get the naming right on the first try though; I just wanted to mention it.
+static inline bool shader_normaliser_new_instructions(struct vkd3d_shader_normaliser *normaliser, unsigned int extra) +{ + return shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + extra); +}
I'd argue for shader_normaliser_reserve_instructions() instead, analogous to shader_instruction_array_reserve() and vkd3d_array_reserve(). Mostly for internal consistency of interfaces.
+static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, + struct vkd3d_shader_instruction_array *instructions) +{ + struct vkd3d_shader_src_param *src; + 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 (!(src = shader_src_param_allocator_get(&instructions->src_params, 1))) + return false; + + memcpy(src, reg->idx[i].rel_addr, sizeof(*src)); + reg->idx[i].rel_addr = src; + assert(!src->reg.idx[0].rel_addr && src->reg.idx[1].offset == ~0u); + } + + return true; +}
Should we perhaps introduce _clone_src_param() and _clone_dst_param() helpers? We could then just use those to (recursively) clone the "rel_addr" parameters. I.e.: ```c reg->idx[i].rel_addr = shader_register_clone_src_param(reg->idx[i].rel_addr); ```
+static bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, const struct vkd3d_shader_instruction *src) +{ + struct vkd3d_shader_instruction *ins = &instructions->elements[dst]; [...] +}
I don't like how we're passing "dst" as the location of the instruction to clone to here. There are probably different ways to address that; one approach would to make this function always append to the end of the instruction array. This ties a bit into some of the later comments about the general structure of the normaliser code as well.
+enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_parser *parser) +{ + const struct vkd3d_shader_instruction_array *instructions = &parser->instructions; [...] +}
Do we need "parser" here? It might be nicer to directly pass in an instruction array. The other thing I find awkward about this function is that it takes an uninitialised normaliser and initialises it, but it's not an _init() or _create() function. One way to address that would be to separate initialisation and cloning from the actual transformations. Another approach would be to do something like "struct vkd3d_shader_instruction_array *dst = shader_instruction_array_normalise(&parser->instructions);". That would imply keeping the vkd3d_shader_normaliser structure internal to normalise.c, which may not be a bad thing.
Relatedly, exposing a single shader_normaliser_normalise() function means that users of this code can't decide to only run some passes but not others, something that is possible with the different transformation passes in the HLSL compiler. That's not a problem as long as the SPIR-V backend is the only user of this code, but it seems like a desirable property regardless.
@@ -9955,16 +9955,27 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, [...] + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { - if ((result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i])) < 0) + if ((result = shader_normaliser_normalise(&normaliser, parser)) < 0) return result; + instructions = &normaliser.instructions; } [...] + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + shader_normaliser_destroy(&normaliser);
I'd propose ```c if (instructions != &parser->instructions) shader_normaliser_destroy(&normaliser); ``` avoiding the need to have matching conditions in the two if-statements.
From patch 2/8:
@@ -109,7 +286,21 @@ enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *no if (!shader_instruction_array_clone_instruction(&normaliser->instructions, normaliser->instructions.count, ins)) return VKD3D_ERROR_OUT_OF_MEMORY; - ++normaliser->instructions.count; + instruction_count = 1; + if ((result = shader_normaliser_eliminate_phase_instance_id(normaliser, &instruction_count)) < 0) + return result; + + normaliser->instructions.count += instruction_count; + }
Something that's a bit ugly here is that we first clone the instruction (including source and destination parameters), but then essentially orphan it if shader_normaliser_eliminate_phase_instance_id() decides to skip it. That ends up working out because destroying the allocators also frees anything allocated from them, but it's not very pretty and feels a bit fragile.
+static enum vkd3d_result shader_normaliser_eliminate_phase_instance_id(struct vkd3d_shader_normaliser *normaliser, + unsigned int *instruction_count) +{ [...] + if (ins->handler_idx == VKD3DSIH_MOV && shader_register_is_phase_instance_id(&ins->src->reg)) + { + if (ins->dst->reg.type != VKD3DSPR_TEMP) + { + FIXME("Instance id not assigned to temp register.\n"); + return VKD3D_OK; + } + /* Instance id always seems to be assigned to r{n}.x */ + if (ins->dst->write_mask != VKD3DSP_WRITEMASK_0) + FIXME("Unsupported write mask %#x.\n", ins->dst->write_mask); + if (ins->dst->reg.idx[0].offset >= sizeof(normaliser->temp_is_instance_id) * CHAR_BIT) + FIXME("Unsupported temp idx %u.\n", ins->dst->reg.idx[0].offset); + else + normaliser->temp_is_instance_id |= 1ull << ins->dst->reg.idx[0].offset; + *instruction_count = 0; + return VKD3D_OK; + } [...] + if (ins->handler_idx != VKD3DSIH_RET) + return VKD3D_OK; + + count = normaliser->instructions.count - normaliser->phase_body_idx; + + if (!shader_instruction_array_reserve(&normaliser->instructions, count * (normaliser->instance_count - 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + /* Make a copy of the non-dcl instructions for each instance. */ + ins = &normaliser->instructions.elements[normaliser->phase_body_idx]; + for (i = 1; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + { + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, + normaliser->phase_body_idx + count * i + j, &ins[j])) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + } [...] +}
Relatedly, the "*instruction_count" handling above feels awkward to me; it seems preferable to either just clone instructions inside shader_normaliser_eliminate_phase_instance_id() if we don't skip them, or always clone them on the outside and replace them with e.g. NOPs in shader_normaliser_eliminate_phase_instance_id() is we do skip them. Note that we do clone instructions for phase bodies inside shader_normaliser_eliminate_phase_instance_id().
Why do we have explicitly handling for MOVs above? Does shader_instruction_eliminate_phase_instance_id() not catch those? Or is this an attempt at doing constant propagation? In the latter case, I'm not sure that's worth it, but it should probably be a separate patch.
@@ -6870,30 +6813,12 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler else spirv_compiler_emit_default_control_point_phase(compiler); - if (compiler->use_vocp) - spirv_compiler_emit_hull_shader_barrier(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. */ + spirv_compiler_emit_hull_shader_barrier(compiler);
This eliminates the "use_vocp" condition on spirv_compiler_emit_hull_shader_barrier(). Is that intentional?
From patch 4/8:
Subject: [PATCH 4/8] vkd3d-shader/spirv: Move the function declaration from spirv_compiler_begin_shader_phase() to spirv_compiler_enter_shader_phase().
The subject line probably has some room for improvement. Specifically, this patch is about the phase function declarations in the generated SPIR-V, not C function declarations in the vkd3d-shader source.
In DXIL handling there will be many more cases analogous to those which shader_normaliser_new_instructions() serves. I think it's less hazardous to eliminate the need to repeat the `count + 1` formula every time.
The special MOV handler tracks the fork/join instance id. Theoretically fxc could use a FORKINSTID register directly as a register address, but instead it emits `mov r0, vForkInstanceId` and then uses r0 as the address.
In DXIL handling there will be many more cases analogous to those which shader_normaliser_new_instructions() serves. I think it's less hazardous to eliminate the need to repeat the `count + 1` formula every time.
We could perhaps also rename shader_normaliser_new_instructions() to something that makes the difference more obvious.
Either way, I think the more fundamental discussion is about what we want the interface for IR manipulation to look like. We can talk about the implementation later, but I'd like to be able to argue about transformation passes on the level of "replace these instructions with these other instructions", "insert these instructions after this one", "delete these instructions", and so on, rather than on the level of carefully manipulating entries in an array.
I'm sure the people working on the HLSL parts of vkd3d-shader could provide some suggestions about what works and what doesn't, but for a comparison, look at e.g. lower_abs() for a trivial example, or lower_return() and lower_calls() for more complicated examples that are perhaps conceptually closer to what we're doing here. HLSL IR is a bit higher level than what we have here, and of course stored in a different way, but I imagine that in terms of API it's in the general direction of where we'd like to go.
The special MOV handler tracks the fork/join instance id. Theoretically fxc could use a FORKINSTID register directly as a register address, but instead it emits `mov r0, vForkInstanceId` and then uses r0 as the address.
Sure, but why is that a problem? Wouldn't "mov r0, vForkInstanceId" be replaced with "mov r0, <constant>", after which using "r0" for addressing should do the right thing?
HLSL is arguably very different, because (1) we do not put effort into optimizing compilation speed at all, (2) we have to do a *lot* of optimization and lowering passes.
If we want the cleanest and safest approach, at the cost of speed, we'd obviously just have helpers that add one instruction at a time, or even helpers that build a "block" of multiple instructions that you can add all at once. That might be less efficient than reserving space and then initialising the instructions as they're done here, though, although I don't know if the difference matters. If it's cases like what's in this patch, just adding one instruction at a time, it probably doesn't...
HLSL is arguably very different, because (1) we do not put effort into optimizing compilation speed at all, (2) we have to do a *lot* of optimization and lowering passes.
I'm not sure I'd go as far as saying it's very different, but it does have different priorities and emphasis, sure.
If we want the cleanest and safest approach, at the cost of speed, we'd obviously just have helpers that add one instruction at a time, or even helpers that build a "block" of multiple instructions that you can add all at once. That might be less efficient than reserving space and then initialising the instructions as they're done here, though, although I don't know if the difference matters. If it's cases like what's in this patch, just adding one instruction at a time, it probably doesn't...
I don't think it has to be inefficient; for shader_normaliser_eliminate_phase_instance_id() in particular, there are essentially three kinds of modification we do:
- Modifying existing instructions in-place. - Deleting instructions. - Splicing in clones of a range of instructions.
In-place modification is trivial. Deletion can be done by (in-place) replacement of instructions with NOPs. We could do a subsequent cleanup pass to consolidate non-NOP instructions, but for the SPIR-V backend that's not even needed. Splicing is less trivial, but we could essentially just clone instructions into a temporary buffer first, and then memmove() them in. memmove() is not free, but it's not clear to me that it would necessarily be worse than cloning the entire shader one instruction at a time. Going a step further, we could allow ownership of the instruction array to be transferred from the parser to the backend on parser destruction, and avoid the initial copy the normaliser does as well.
That said, if the general consensus is "we'll cross that bridge when we'll get to it", I won't object; "when we'll get to it" does have the unfortunate tendency to be some inopportune time though.
It's tempting to allow transfer of instruction array ownership, and clone phases into a temporary buffer while making an array of {index, count} so the insertion can start with the last and move backwards. But it's hard to justify the extra time to develop it versus cleaning up what we have.