From 41b08a2040f650c672ccf65dcb14f3903da4b3ee Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 23 Jun 2025 23:45:28 +0200 Subject: [PATCH] etnaviv: allow 0 back stencil valuemask on new cores Older cores have a hardware bug where the stencil test misbehaves when the valuemask is 0 in the back stencil. The workaround is to effectively switch to single sided stencil and hope for the best. This seems to be okay for most actual use-cases and tests, as a 0 valuemask is quite rare. However, as 0 is a valid value for the mask the workaround breaks some edge cases. Newer cores don't seem to require the workaround and operate correctly with all stencil valuemasks, so drop the workaround for them. I don't know which feature bit tells us about the bugfix. I made an educated guess by checking behavior on multiple GPUs: GC880r5106 and GC2000r5108 need the workaround, GC3000r5450, GC7000r6204 and GC600r4653 work fine without it. By comparing the set BugFixes feature bits between the cores and the fact that BugFixes15 already fixes some PE issues, I think this one is the most likely candidate. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner Part-of: --- src/gallium/drivers/etnaviv/etnaviv_emit.c | 3 ++- src/gallium/drivers/etnaviv/etnaviv_internal.h | 2 ++ src/gallium/drivers/etnaviv/etnaviv_screen.c | 3 +++ src/gallium/drivers/etnaviv/etnaviv_zsa.c | 12 ++++++++++-- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/gallium/drivers/etnaviv/etnaviv_emit.c b/src/gallium/drivers/etnaviv/etnaviv_emit.c index 2c95464455e..9e741ac3bf2 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_emit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_emit.c @@ -532,7 +532,8 @@ etna_emit_state(struct etna_context *ctx) } if (unlikely(dirty & (ETNA_DIRTY_STENCIL_REF | ETNA_DIRTY_RASTERIZER | ETNA_DIRTY_ZSA))) { uint32_t val = etna_zsa_state(ctx->zsa)->PE_STENCIL_CONFIG_EXT; - if (!ctx->zsa->stencil[1].enabled && ctx->zsa->stencil[0].valuemask) + if (!ctx->zsa->stencil[1].enabled && + (screen->specs.correct_stencil_valuemask || ctx->zsa->stencil[0].valuemask)) val |= ctx->stencil_ref.PE_STENCIL_CONFIG_EXT[!ccw]; else val |= ctx->stencil_ref.PE_STENCIL_CONFIG_EXT[ccw]; diff --git a/src/gallium/drivers/etnaviv/etnaviv_internal.h b/src/gallium/drivers/etnaviv/etnaviv_internal.h index da92eea73e2..9e86a893fcc 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_internal.h +++ b/src/gallium/drivers/etnaviv/etnaviv_internal.h @@ -89,6 +89,8 @@ struct etna_specs { unsigned tex_astc : 1; /* has BLT engine instead of RS */ unsigned use_blt : 1; + /* has correct stencil 0 valuemask */ + unsigned correct_stencil_valuemask : 1; /* number of bits per TS tile */ unsigned bits_per_tile; /* clear value for TS (dependent on bits_per_tile) */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c index 48aaaad2f3d..88c03e1b2d8 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.c +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c @@ -829,6 +829,9 @@ etna_get_specs(struct etna_screen *screen) screen->specs.v4_compression = VIV_FEATURE(screen, ETNA_FEATURE_V4_COMPRESSION); + /* XXX: The feature bit gating the bugfix is an educated guess */ + screen->specs.correct_stencil_valuemask = VIV_FEATURE(screen, ETNA_FEATURE_PE_DITHER_FIX); + if (screen->info->halti >= 5) { /* GC7000 - this core must load shaders from memory. */ screen->specs.vs_offset = 0; diff --git a/src/gallium/drivers/etnaviv/etnaviv_zsa.c b/src/gallium/drivers/etnaviv/etnaviv_zsa.c index 2d3c99f1541..98c7db1411e 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_zsa.c +++ b/src/gallium/drivers/etnaviv/etnaviv_zsa.c @@ -100,8 +100,16 @@ etna_zsa_state_create(struct pipe_context *pctx, VIVS_PE_ALPHA_OP_ALPHA_REF(float_to_ubyte(so->alpha_ref_value)); for (unsigned i = 0; i < 2; i++) { - const struct pipe_stencil_state *stencil_front = (so->stencil[1].enabled && so->stencil[1].valuemask) ? &so->stencil[i] : &so->stencil[0]; - const struct pipe_stencil_state *stencil_back = (so->stencil[1].enabled && so->stencil[1].valuemask) ? &so->stencil[!i] : &so->stencil[0]; + const struct pipe_stencil_state *stencil_front, *stencil_back; + + if (so->stencil[1].enabled && + (screen->specs.correct_stencil_valuemask || so->stencil[1].valuemask)) { + stencil_front = &so->stencil[i]; + stencil_back = &so->stencil[!i]; + } else { + stencil_front = stencil_back = &so->stencil[0]; + } + cs->PE_STENCIL_OP[i] = VIVS_PE_STENCIL_OP_FUNC_FRONT(stencil_front->func) | VIVS_PE_STENCIL_OP_FUNC_BACK(stencil_back->func) |