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/ir.c | 87 ++++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 32 ++------- libs/vkd3d-shader/vkd3d_shader_private.h | 3 + 3 files changed, 97 insertions(+), 25 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index a077a05d..1e6dd46b 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -84,6 +84,11 @@ static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_i shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, instance_id); }
+static bool normaliser_is_in_control_point_phase(const struct vkd3d_shader_normaliser *normaliser) +{ + 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; @@ -217,6 +222,22 @@ static enum vkd3d_result shader_normaliser_flatten_phases(struct vkd3d_shader_no 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 void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx) { memset(ins, 0, sizeof(*ins)); @@ -258,6 +279,72 @@ enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shad return result; }
+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_normalise_outpointid(struct vkd3d_shader_dst_param *dst_param, + struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_register *reg = &dst_param->reg; + + if (normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) + { + assert(reg->idx[1].offset == ~0u); + 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; + } +} + +enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_instruction_array *instructions = &normaliser->instructions; + struct vkd3d_shader_instruction *ins; + unsigned int i, j; + + if (!(normaliser->outpointid_param = shader_normaliser_create_outpointid_param(normaliser))) + { + ERR("Failed to allocate src param.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + normaliser->phase = VKD3DSIH_INVALID; + for (i = 0; i < normaliser->instructions.count; ++i) + { + ins = &instructions->elements[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 (j = 0; j < ins->dst_count; ++j) + shader_dst_param_normalise_outpointid((struct vkd3d_shader_dst_param *)&ins->dst[j], + normaliser); + break; + } + } + + return VKD3D_OK; +} + void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser) { shader_instruction_array_destroy(&normaliser->instructions); diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index ddd77ffb..c60f32f7 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))) { @@ -9841,7 +9822,8 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { shader_normaliser_init(&normaliser, instructions); - result = shader_normaliser_flatten_hull_shader_phases(&normaliser); + if ((result = shader_normaliser_flatten_hull_shader_phases(&normaliser)) >= 0) + result = shader_normaliser_normalise_hull_shader_control_point_io(&normaliser); instructions = &normaliser.instructions;
if (result >= 0 && TRACE_ON()) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index d1a4aa1d..c3f1219e 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1337,11 +1337,14 @@ 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; };
void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser, struct vkd3d_shader_instruction_array *instructions); enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shader_normaliser *normaliser); +enum vkd3d_result shader_normaliser_normalise_hull_shader_control_point_io(struct vkd3d_shader_normaliser *normaliser); void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser);
#endif /* __VKD3D_SHADER_PRIVATE_H */