etnaviv: Use shader R/B swap for LINEAR_PE shared resources

On LINEAR_PE GPUs, shared linear resources are render-compatible so
no render shadow exists - the PE renders directly into the shared
buffer. Rather than adding a dedicated flush-time blit to swap R/B
(which would introduce bandwidth that doesn't exist today), use the
frag_rb_swap shader key to swap channels at render time.

In etna_draw_vbo, detect LINEAR_PE + shared + linear + RB_SWAP format
and set the per-RT frag_rb_swap bits. Track shared_native_order so
etna_flush_resource can skip the dedicated blit when the shader
already produced correct byte order.

Fixes: a5766e75e48 ("etnaviv: Use BGRA-internal texture format with BLT/RS R/B swizzle")
Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40029>
This commit is contained in:
Christian Gmeiner 2026-04-15 20:27:18 +02:00 committed by Marge Bot
parent 99bf43dd08
commit 567a65bbbf
2 changed files with 40 additions and 21 deletions

View file

@ -283,27 +283,28 @@ etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
}
} else if (flush_rb_swap) {
/* No render shadow and no TS — PE rendered directly into the shared
* buffer. We still need to R<->B swap the contents.
* Can't use etna_copy_resource(src==dst) here because it skips levels
* without valid TS, so issue the blit directly. */
assert(prsc->last_level == 0);
struct etna_resource_level *lev = &rsc->levels[0];
struct pipe_blit_info blit = {
.mask = util_format_get_mask(prsc->format),
.filter = PIPE_TEX_FILTER_NEAREST,
.src.resource = blit.dst.resource = prsc,
.src.format = blit.dst.format = prsc->format,
.src.box.width = blit.dst.box.width = lev->width,
.src.box.height = blit.dst.box.height = lev->height,
.src.box.depth = blit.dst.box.depth = 1,
};
* buffer. If the fragment shader already swapped R/B (LINEAR_PE),
* bytes are already correct. Otherwise we need to swap here. */
if (!rsc->shared_native_order) {
assert(prsc->last_level == 0);
struct etna_resource_level *lev = &rsc->levels[0];
struct pipe_blit_info blit = {
.mask = util_format_get_mask(prsc->format),
.filter = PIPE_TEX_FILTER_NEAREST,
.src.resource = blit.dst.resource = prsc,
.src.format = blit.dst.format = prsc->format,
.src.box.width = blit.dst.box.width = lev->width,
.src.box.height = blit.dst.box.height = lev->height,
.src.box.depth = blit.dst.box.depth = 1,
};
ctx->blit_rb_swap = true;
ctx->blit(pctx, &blit);
ctx->blit_rb_swap = false;
ctx->blit_rb_swap = true;
ctx->blit(pctx, &blit);
ctx->blit_rb_swap = false;
rsc->shared_native_order = true;
etna_resource_level_mark_changed(&rsc->levels[0]);
rsc->shared_native_order = true;
etna_resource_level_mark_changed(&rsc->levels[0]);
}
}
}

View file

@ -33,6 +33,7 @@
#include "etnaviv_debug.h"
#include "etnaviv_emit.h"
#include "etnaviv_fence.h"
#include "etnaviv_format.h"
#include "etnaviv_ml.h"
#include "etnaviv_query.h"
#include "etnaviv_query_acc.h"
@ -417,6 +418,22 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
if (screen->info->halti >= 5)
key.flatshade = ctx->rasterizer->flatshade;
/* On LINEAR_PE GPUs rendering directly to a linear shared resource,
* use shader-based R/B swap so bytes in memory have the correct order
* for external consumers. This avoids a dedicated flush-time blit.
* Per-RT bitmask so MRT with mixed shared/non-shared targets works. */
if (VIV_FEATURE(screen, ETNA_FEATURE_LINEAR_PE)) {
for (i = 0; i < pfb->nr_cbufs; i++) {
if (pfb->cbufs[i].texture) {
struct etna_resource *rsc = etna_resource(pfb->cbufs[i].texture);
if (rsc->shared && rsc->layout == ETNA_LAYOUT_LINEAR &&
translate_pe_format_rb_swap(pfb->cbufs[i].format)) {
key.frag_rb_swap |= (1 << i);
}
}
}
}
if (!etna_get_vs(ctx, &key) || !etna_get_fs(ctx, &key)) {
BUG("compiled shaders are not okay");
return;
@ -563,9 +580,10 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
etna_resource_level_mark_changed(level);
/* PE rendered directly to the shared buffer (no render shadow).
* Data is now in PE-internal byte order (BGRA for RB_SWAP formats). */
* If the shader swapped R/B, data is in native byte order.
* Otherwise it's in PE-internal order (BGRA for RB_SWAP formats). */
if (rsc->shared && res == rsc)
rsc->shared_native_order = false;
rsc->shared_native_order = !!(key.frag_rb_swap & (1 << i));
}
}