etnaviv: improve dither enable conditions

Take into account the alpha blend state of all render targets when deciding
whether it is okay to enable dithering. Do not dither render targets with
less than 5 bits of precision per channel as this leads to visible artifacts.

GC7000 fails to blend RGBA4444 correctly when dithering is disabled but
PE_LOGIC_OP_DITHER_MODE is set to anything other than 0, so set this state
depending on whether dithering is actually enabled.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Christian Gmeiner <cgmeiner@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35673>
This commit is contained in:
Lucas Stach
2025-06-21 15:00:37 +02:00
committed by Marge Bot
parent 07af41b0a2
commit 46cb190944
2 changed files with 27 additions and 17 deletions
+26 -14
View File
@@ -77,6 +77,13 @@ etna_blend_state_create(struct pipe_context *pctx,
rt->alpha_dst_factor == PIPE_BLENDFACTOR_ZERO &&
rt->alpha_func == PIPE_BLEND_ADD);
/* Dithering together with alpha blending and without feature
* ETNA_FEATURE_PE_DITHER_FIX leads to visibly altered colors.
*/
if (co->rt[i].alpha_enable &&
!VIV_FEATURE(ctx->screen, ETNA_FEATURE_PE_DITHER_FIX))
co->base.dither = 0;
/* Enable separate alpha if
* - Blending enabled (see above)
* - NOT source/destination factor and eq is same for both rgb and alpha
@@ -92,23 +99,9 @@ etna_blend_state_create(struct pipe_context *pctx,
co->PE_LOGIC_OP =
VIVS_PE_LOGIC_OP_OP(logicop_enable ? so->logicop_func : LOGIC_OP_COPY) |
VIVS_PE_LOGIC_OP_DITHER_MODE(3) | /* TODO: related to dithering, sometimes 2 */
0x000E4000 /* ??? */;
/* XXX alpha_to_coverage / alpha_to_one? */
/* Set dither registers based on dither status. These registers set the
* dither pattern,
* for now, set the same values as the blob.
*/
if (so->dither &&
(!co->rt[0].alpha_enable ||
VIV_FEATURE(ctx->screen, ETNA_FEATURE_PE_DITHER_FIX))) {
co->PE_DITHER[0] = 0x6e4ca280;
co->PE_DITHER[1] = 0x5d7f91b3;
} else {
co->PE_DITHER[0] = 0xffffffff;
co->PE_DITHER[1] = 0xffffffff;
}
return co;
}
@@ -120,6 +113,7 @@ etna_update_blend(struct etna_context *ctx)
struct pipe_blend_state *pblend = ctx->blend;
struct etna_blend_state *blend = etna_blend_state(pblend);
unsigned current_rt = 0;
bool dither_allow = true;
for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
if (!pfb->cbufs[i].texture)
@@ -143,6 +137,13 @@ etna_update_blend(struct etna_context *ctx)
colormask = rt->colormask;
}
/* Dithering a 4bpc format leads to visible artifacts due to the low
* precision of the color channels.
*/
if (pfb->cbufs[i].format == PIPE_FORMAT_B4G4R4A4_UNORM ||
pfb->cbufs[i].format == PIPE_FORMAT_B4G4R4X4_UNORM)
dither_allow = false;
/* If the complete render target is written, set full_overwrite:
* - The color mask covers all channels of the render target
* - No blending or logicop is used
@@ -181,6 +182,17 @@ etna_update_blend(struct etna_context *ctx)
if (current_rt == 0)
blend->rt[0].PE_COLOR_FORMAT = VIVS_PE_COLOR_FORMAT_OVERWRITE;
/* Use same dither pattern as the blob */
if (blend->base.dither && dither_allow) {
blend->PE_DITHER[0] = 0x6e4ca280;
blend->PE_DITHER[1] = 0x5d7f91b3;
blend->PE_LOGIC_OP |= VIVS_PE_LOGIC_OP_DITHER_MODE(3); /* TODO: sometimes 2 */
} else {
blend->PE_DITHER[0] = 0xffffffff;
blend->PE_DITHER[1] = 0xffffffff;
blend->PE_LOGIC_OP &= ~VIVS_PE_LOGIC_OP_DITHER_MODE__MASK;
}
return true;
}
+1 -3
View File
@@ -543,9 +543,7 @@ etna_emit_state(struct etna_context *ctx)
if (unlikely(dirty & (ETNA_DIRTY_BLEND | ETNA_DIRTY_FRAMEBUFFER))) {
struct etna_blend_state *blend = etna_blend_state(ctx->blend);
/*014A4*/ EMIT_STATE(PE_LOGIC_OP, blend->PE_LOGIC_OP | ctx->framebuffer.PE_LOGIC_OP);
}
if (unlikely(dirty & (ETNA_DIRTY_BLEND))) {
struct etna_blend_state *blend = etna_blend_state(ctx->blend);
for (int x = 0; x < 2; ++x) {
/*014A8*/ EMIT_STATE(PE_DITHER(x), blend->PE_DITHER[x]);
}