From 52b9aa416bb4e8be2fb6e28ffd1234cc10db96c6 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Fri, 19 Sep 2025 10:44:09 +0200 Subject: [PATCH] vkd3d-shader/ir: Fix r0 allocation for PS 1.x shaders. In order to allocate it properly we have to ensure it is the first register to be processed. The current algorithm fails to do so, so a more explicit approach is introduced. --- libs/vkd3d-shader/ir.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index c0a5c1e6b..a242f32d8 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -8940,11 +8940,13 @@ struct temp_allocator uint32_t temp_id; enum vkd3d_shader_register_type type; unsigned int idx; + bool force_first; } *ssa_regs, *temp_regs; size_t ssa_count, temp_count; unsigned int new_temp_count; enum vkd3d_result result; uint8_t *current_allocation; + bool ps_1_x; }; static void temp_allocator_set_src(struct temp_allocator *allocator, struct vkd3d_shader_src_param *src) @@ -9092,15 +9094,12 @@ static int temp_allocate_compare_open(const void *ptr1, const void *ptr2) const struct temp_allocator_reg * const *reg1 = ptr1, * const *reg2 = ptr2; int ret; + if ((ret = vkd3d_u32_compare((*reg1)->force_first, (*reg2)->force_first))) + return -ret; if ((ret = vkd3d_u32_compare((*reg1)->liveness_reg->first_write, (*reg2)->liveness_reg->first_write))) return ret; if ((ret = vkd3d_u32_compare((*reg1)->liveness_reg->last_access, (*reg2)->liveness_reg->last_access))) return ret; - /* r0 must compare before everything else for SM 1.x PS (see comment below). */ - if ((*reg1)->type == VKD3DSPR_TEMP && (*reg1)->idx == 0) - return -1; - if ((*reg2)->type == VKD3DSPR_TEMP && (*reg2)->idx == 0) - return 1; return 0; } @@ -9268,6 +9267,17 @@ static enum vkd3d_result temp_allocator_compute_allocation_map(struct temp_alloc { reg->type = VKD3DSPR_TEMP; reg->idx = i - allocator->ssa_count; + + /* For SM 1.x ps we need to ensure that r0 is reallocated to itself, + * because it doubles as the output register. To do so we + * artificially make it alive for the whole program and make it + * compare before anything else. */ + if (reg->idx == 0 && allocator->ps_1_x) + { + reg->force_first = true; + liveness->ssa_regs[i].first_write = 0; + liveness->ssa_regs[i].last_access = UINT_MAX; + } } reg->liveness_reg = &liveness->ssa_regs[i]; @@ -9375,15 +9385,8 @@ enum vkd3d_result vsir_allocate_temp_registers(struct vsir_program *program, allocator.temp_regs = regs + program->ssa_count; allocator.new_temp_count = 0; - /* For SM 1.x ps we need to ensure that r0 is reallocated to itself, because - * it doubles as the output register. To do so we artificially make it - * alive for the whole program. */ - if (program->shader_version.type == VKD3D_SHADER_TYPE_PIXEL - && program->shader_version.major < 2 && allocator.temp_count >= 1) - { - tracker.temp_regs[0].first_write = 0; - tracker.temp_regs[0].last_access = UINT_MAX; - } + if (program->shader_version.type == VKD3D_SHADER_TYPE_PIXEL && program->shader_version.major < 2) + allocator.ps_1_x = true; if ((ret = temp_allocator_compute_allocation_map(&allocator, &tracker)) < 0) {