diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c index 8b90d220fc4..7fb17e53c14 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c @@ -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]); + } } } diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c index afceda7861d..a96ea998516 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.c +++ b/src/gallium/drivers/etnaviv/etnaviv_context.c @@ -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)); } }