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 c9ea5746..4d42b920 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); @@ -312,6 +317,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) { @@ -335,7 +395,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; @@ -363,6 +423,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;
@@ -370,6 +437,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 */