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.
-- v8: vkd3d-shader/normalise: Insert hull shader control point input declarations if no control point phase is defined. vkd3d-shader/normalise: Normalise control point phase output registers to include the control point id. vkd3d-shader: Introduce an internal sm6 signature structure. vkd3d-shader/spirv: Move the function declaration from spirv_compiler_begin_shader_phase() to spirv_compiler_enter_shader_phase(). vkd3d-shader/spirv: Remove the hull shader phase array. vkd3d-shader/normalise: Merge all shader IR fork and join phases into a single phase. vkd3d-shader/normalise: Introduce a normaliser structure.
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
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 | 25 ++++---- libs/vkd3d-shader/vkd3d_shader_private.h | 12 +++- 3 files changed, 105 insertions(+), 13 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 204db5a6..0bb42ca9 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) @@ -6576,6 +6580,8 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile spirv_compiler_emit_store(compiler, dst_id, output->mask, component_type, SpvStorageClassOutput, VKD3DSP_WRITEMASK_ALL, src_id); } + + vkd3d_spirv_build_op_return(builder); }
static void spirv_compiler_emit_barrier(struct spirv_compiler *compiler, @@ -6743,10 +6749,7 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *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 @@ -9816,7 +9819,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 */