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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user