From 2ed37033a0847cf0391059818ddb9d01d13011d7 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Wed, 17 Dec 2025 11:21:03 +0100 Subject: [PATCH] ir3/legalize: fix (eq) scheduling for sam.s2en sam.s2en uses the first src for its samp/tex while the coordinates (for which derivatives need to be calculated) are in the second src. We used to unconditionally track needed helpers for the first src causing (eq) to potentially get scheduled too early for sam.s2en. Fix this by using the second src for sam.s2en. Fixes frame instability in Metro Exodus. Signed-off-by: Job Noorman Fixes: 29f82779526 ("ir3/legalize: schedule (eq) more accurately") Part-of: --- src/freedreno/ir3/ir3.h | 12 ++++++++++++ src/freedreno/ir3/ir3_legalize.c | 20 ++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index b22229deccb..875d77052fe 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -1923,6 +1923,18 @@ ir3_src_is_first_in_group(struct ir3_register *src) #define foreach_src_in_alias_group(__alias, __instr, __start) \ foreach_src_in_alias_group_n (__alias, __alias_n, __instr, __start) +static inline unsigned +ir3_alias_group_size(struct ir3_instruction *instr, unsigned src_n) +{ + unsigned size = 0; + + foreach_src_in_alias_group (src, instr, src_n) { + size++; + } + + return size; +} + /* iterator for an instructions's destinations (reg), also returns dst #: */ #define foreach_dst_n(__dstreg, __n, __instr) \ if ((__instr)->dsts_count) \ diff --git a/src/freedreno/ir3/ir3_legalize.c b/src/freedreno/ir3/ir3_legalize.c index e05de9df672..696d9e0ff30 100644 --- a/src/freedreno/ir3/ir3_legalize.c +++ b/src/freedreno/ir3/ir3_legalize.c @@ -1653,10 +1653,21 @@ instr_mark_helpers(struct ir3_mark_helpers_data *bd, * that we can keep them enabled until it is written. */ unsigned nsrcs; + unsigned first_src_n = 0; if (instr->opc == OPC_SAM || instr->opc == OPC_SAMB || instr->opc == OPC_GETLOD) { nsrcs = (instr->flags & IR3_INSTR_3D) ? 3 : 2; + + /* sam.s2en has the samp/tex in the first src; skip over it. */ + if (instr->flags & IR3_INSTR_S2EN) { + if (instr->srcs[0]->flags & IR3_REG_FIRST_ALIAS) { + assert(ir3_alias_group_size(instr, 0) == 2); + first_src_n = 2; + } else { + first_src_n = 1; + } + } } else { /* dsx/dsy: derive the number of sources from the dst wrmask since the * src itself may use aliases. @@ -1664,10 +1675,10 @@ instr_mark_helpers(struct ir3_mark_helpers_data *bd, nsrcs = util_last_bit(instr->dsts[0]->wrmask); } - if (instr->srcs[0]->flags & IR3_REG_FIRST_ALIAS) { - assert(nsrcs <= instr->srcs_count); + if (instr->srcs[first_src_n]->flags & IR3_REG_FIRST_ALIAS) { + assert(first_src_n + nsrcs <= instr->srcs_count); - for (unsigned i = 0; i < nsrcs; i++) { + for (unsigned i = first_src_n; i < first_src_n + nsrcs; i++) { struct ir3_register *src = instr->srcs[i]; if (is_reg_gpr(src)) { @@ -1675,7 +1686,8 @@ instr_mark_helpers(struct ir3_mark_helpers_data *bd, } } } else { - regmask_set_masked(&bd->needs_helpers, instr->srcs[0], MASK(nsrcs)); + regmask_set_masked(&bd->needs_helpers, instr->srcs[first_src_n], + MASK(nsrcs)); } break;