vkd3d-shader/ir: Merge the hull shader phase flattener into a single pass.

This commit is contained in:
Francisco Casas
2025-09-04 04:19:22 -04:00
committed by Henri Verbeet
parent 434d9dd117
commit 1aa6c767ea
Notes: Henri Verbeet 2025-09-09 15:10:17 +02:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1707

View File

@@ -2432,8 +2432,6 @@ struct hull_flattener
{ {
struct vsir_program *program; struct vsir_program *program;
unsigned int instance_count;
unsigned int phase_body_idx;
enum vkd3d_shader_opcode phase; enum vkd3d_shader_opcode phase;
struct vkd3d_shader_location last_ret_location; struct vkd3d_shader_location last_ret_location;
unsigned int *ssa_map; unsigned int *ssa_map;
@@ -2445,68 +2443,6 @@ static bool flattener_is_in_fork_or_join_phase(const struct hull_flattener *flat
return flattener->phase == VSIR_OP_HS_FORK_PHASE || flattener->phase == VSIR_OP_HS_JOIN_PHASE; return flattener->phase == VSIR_OP_HS_FORK_PHASE || flattener->phase == VSIR_OP_HS_JOIN_PHASE;
} }
struct shader_phase_location
{
unsigned int index;
unsigned int instance_count;
unsigned int instruction_count;
};
struct shader_phase_location_array
{
/* Unlikely worst case: one phase for each component of each output register. */
struct shader_phase_location locations[MAX_REG_OUTPUT * VKD3D_VEC4_SIZE];
unsigned int count;
};
static void flattener_eliminate_phase_related_dcls(struct hull_flattener *normaliser, unsigned int index,
struct vkd3d_shader_instruction *ins, struct shader_phase_location_array *locations)
{
struct shader_phase_location *loc;
bool b;
if (ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE)
{
b = flattener_is_in_fork_or_join_phase(normaliser);
/* Reset the phase info. */
normaliser->phase_body_idx = ~0u;
normaliser->phase = ins->opcode;
normaliser->instance_count = 1;
/* Leave the first occurrence and delete the rest. */
if (b)
vkd3d_shader_instruction_make_nop(ins);
return;
}
else if (ins->opcode == VSIR_OP_DCL_HS_FORK_PHASE_INSTANCE_COUNT
|| ins->opcode == VSIR_OP_DCL_HS_JOIN_PHASE_INSTANCE_COUNT)
{
normaliser->instance_count = ins->declaration.count + !ins->declaration.count;
vkd3d_shader_instruction_make_nop(ins);
return;
}
if (normaliser->phase == VSIR_OP_INVALID || vsir_instruction_is_dcl(ins))
return;
if (normaliser->phase_body_idx == ~0u)
normaliser->phase_body_idx = index;
if (ins->opcode == VSIR_OP_RET)
{
normaliser->last_ret_location = ins->location;
vkd3d_shader_instruction_make_nop(ins);
if (locations->count >= ARRAY_SIZE(locations->locations))
{
FIXME("Insufficient space for phase location.\n");
return;
}
loc = &locations->locations[locations->count++];
loc->index = normaliser->phase_body_idx;
loc->instance_count = normaliser->instance_count;
loc->instruction_count = index - normaliser->phase_body_idx;
}
}
static void flattener_fixup_ssa_register(struct hull_flattener *normaliser, static void flattener_fixup_ssa_register(struct hull_flattener *normaliser,
struct vkd3d_shader_register *reg, unsigned int instance_id) struct vkd3d_shader_register *reg, unsigned int instance_id)
{ {
@@ -2569,64 +2505,109 @@ static void flattener_fixup_registers(struct hull_flattener *normaliser,
flattener_fixup_register_indices(normaliser, &ins->dst[i].reg, instance_id); flattener_fixup_register_indices(normaliser, &ins->dst[i].reg, instance_id);
} }
static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser, static enum vkd3d_result flattener_replicate_location(struct hull_flattener *normaliser,
struct shader_phase_location_array *locations) struct vsir_program_iterator *it, size_t instance_count, size_t instruction_count)
{ {
struct vkd3d_shader_instruction_array *instructions = &normaliser->program->instructions; struct vsir_program_iterator dst_it, src_it, first_it;
struct vsir_program_iterator it = vsir_program_iterator(instructions);
unsigned int i, j, k, loc_i, count, added_count;
struct vkd3d_shader_instruction *ins; struct vkd3d_shader_instruction *ins;
struct shader_phase_location *loc; unsigned int i, j;
size_t count;
loc_i = 0; VKD3D_ASSERT(instance_count);
added_count = 0; count = (instance_count - 1) * instruction_count;
for (ins = vsir_program_iterator_head(&it), i = 0; ins; ins = vsir_program_iterator_next(&it), ++i) if (!vsir_program_iterator_insert_before(it, &first_it, count))
return VKD3D_ERROR_OUT_OF_MEMORY;
/* Make a copy of the non-dcl instructions for each instance. */
dst_it = first_it;
for (i = 1; i < instance_count; ++i)
{ {
if (loc_i >= locations->count) src_it = *it;
break; for (j = 0; j < instruction_count; ++j)
loc = &locations->locations[loc_i];
if (i == loc->index + added_count)
{ {
struct vsir_program_iterator dst_it, src_it, first_it; if (!vsir_program_iterator_clone_instruction(&dst_it, vsir_program_iterator_current(&src_it)))
count = (loc->instance_count - 1) * loc->instruction_count;
if (!vsir_program_iterator_insert_before(&it, &first_it, count))
return VKD3D_ERROR_OUT_OF_MEMORY; return VKD3D_ERROR_OUT_OF_MEMORY;
added_count += count;
/* Make a copy of the non-dcl instructions for each instance. */ vsir_program_iterator_next(&dst_it);
dst_it = first_it; vsir_program_iterator_next(&src_it);
for (j = 1; j < loc->instance_count; ++j) }
{ }
src_it = it; /* Replace each reference to the instance id with a constant instance id. */
for (k = 0; k < loc->instruction_count; ++k) *it = first_it;
{ for (i = 0; i < instance_count; ++i)
if (!vsir_program_iterator_clone_instruction(&dst_it, vsir_program_iterator_current(&src_it))) {
return VKD3D_ERROR_OUT_OF_MEMORY; if (i)
memset(normaliser->ssa_map, 0xff, normaliser->orig_ssa_count * sizeof(*normaliser->ssa_map));
vsir_program_iterator_next(&dst_it); for (j = 0; j < instruction_count; ++j)
vsir_program_iterator_next(&src_it); {
} ins = vsir_program_iterator_current(it);
} flattener_fixup_registers(normaliser, ins, i);
/* Replace each reference to the instance id with a constant instance id. */ vsir_program_iterator_next(it);
it = first_it; }
for (j = 0; j < loc->instance_count; ++j) }
{
if (j != 0)
memset(normaliser->ssa_map, 0xff, normaliser->orig_ssa_count * sizeof(*normaliser->ssa_map));
for (k = 0; k < loc->instruction_count; ++k) return VKD3D_OK;
{ }
ins = vsir_program_iterator_current(&it);
flattener_fixup_registers(normaliser, ins, j);
vsir_program_iterator_next(&it);
++i;
}
}
loc->index += added_count - (loc->instance_count - 1) * loc->instruction_count; static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser)
++loc_i; {
struct vsir_program_iterator it = vsir_program_iterator(&normaliser->program->instructions);
struct vsir_program_iterator phase_body_it;
struct vkd3d_shader_instruction *ins;
bool b, phase_body_it_valid = false;
unsigned int instruction_count = 0;
unsigned int instance_count = 0;
enum vkd3d_result res;
normaliser->phase = VSIR_OP_INVALID;
for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
{
if (ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE)
{
b = flattener_is_in_fork_or_join_phase(normaliser);
/* Reset the phase info. */
phase_body_it_valid = false;
normaliser->phase = ins->opcode;
instance_count = 1;
instruction_count = 0;
/* Leave the first occurrence and delete the rest. */
if (b)
vkd3d_shader_instruction_make_nop(ins);
continue;
}
else if (ins->opcode == VSIR_OP_DCL_HS_FORK_PHASE_INSTANCE_COUNT
|| ins->opcode == VSIR_OP_DCL_HS_JOIN_PHASE_INSTANCE_COUNT)
{
instance_count = ins->declaration.count + !ins->declaration.count;
vkd3d_shader_instruction_make_nop(ins);
++instruction_count;
continue;
}
if (normaliser->phase == VSIR_OP_INVALID)
continue;
if (!phase_body_it_valid && !vsir_instruction_is_dcl(ins))
{
phase_body_it_valid = true;
phase_body_it = it;
instruction_count = 0;
}
if (ins->opcode == VSIR_OP_RET)
{
normaliser->last_ret_location = ins->location;
vkd3d_shader_instruction_make_nop(ins);
it = phase_body_it;
if ((res = flattener_replicate_location(normaliser, &it,
instance_count, instruction_count)) < 0)
return res;
phase_body_it_valid = false;
}
else
{
++instruction_count;
} }
} }
@@ -2636,19 +2617,10 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali
static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program, static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program,
struct vsir_transformation_context *ctx) struct vsir_transformation_context *ctx)
{ {
struct vsir_program_iterator it = vsir_program_iterator(&program->instructions);
struct shader_phase_location_array locations;
struct hull_flattener flattener = {program}; struct hull_flattener flattener = {program};
struct vkd3d_shader_instruction *ins; struct vkd3d_shader_instruction *ins;
enum vkd3d_result result = VKD3D_OK; enum vkd3d_result result = VKD3D_OK;
unsigned int i;
flattener.phase = VSIR_OP_INVALID;
locations.count = 0;
for (ins = vsir_program_iterator_head(&it), i = 0; ins; ins = vsir_program_iterator_next(&it), ++i)
{
flattener_eliminate_phase_related_dcls(&flattener, i, ins, &locations);
}
bitmap_clear(program->io_dcls, VKD3DSPR_FORKINSTID); bitmap_clear(program->io_dcls, VKD3DSPR_FORKINSTID);
bitmap_clear(program->io_dcls, VKD3DSPR_JOININSTID); bitmap_clear(program->io_dcls, VKD3DSPR_JOININSTID);
@@ -2656,8 +2628,7 @@ static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_pro
if (!(flattener.ssa_map = vkd3d_calloc(flattener.orig_ssa_count, sizeof(*flattener.ssa_map)))) if (!(flattener.ssa_map = vkd3d_calloc(flattener.orig_ssa_count, sizeof(*flattener.ssa_map))))
return VKD3D_ERROR_OUT_OF_MEMORY; return VKD3D_ERROR_OUT_OF_MEMORY;
result = flattener_flatten_phases(&flattener, &locations); result = flattener_flatten_phases(&flattener);
vkd3d_free(flattener.ssa_map); vkd3d_free(flattener.ssa_map);
flattener.ssa_map = NULL; flattener.ssa_map = NULL;