From 377f2ec49ce074c4577f885a422589ca501d0eda Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Sat, 21 Feb 2026 00:41:07 +0100 Subject: [PATCH] etnaviv: Bypass BGRA-internal optimization for shared resources The rb-swap rework (commit a5766e75e48) uses A8R8G8B8 as the texture format for RB_SWAP pipe formats and performs R<->B conversion during transfer blits. This breaks dmabuf import/export: external producers write RGBA bytes, but A8R8G8B8 interprets them as BGRA; transfer blits incorrectly swap R<->B on data already in the correct byte order. For shared/imported resources, bypass the optimization: use the native texture format (A8B8G8R8) so the sampler reads RGBA bytes correctly in both the descriptor and state-based texture paths, skip the R<->B swizzle in BLT and RS transfer blits since shared resources already store data in standard byte order, and re-enable the texture shadow shortcut for shared RB_SWAP resources since the BLT swap is no longer applied. Internal-only resources continue using the BGRA-internal optimization unchanged. Fixes: a5766e75e48 ("etnaviv: Use BGRA-internal texture format with BLT/RS R/B swizzle") Signed-off-by: Christian Gmeiner Part-of: --- src/gallium/drivers/etnaviv/etnaviv_blt.c | 3 ++- src/gallium/drivers/etnaviv/etnaviv_format.c | 15 +++++++++++++++ src/gallium/drivers/etnaviv/etnaviv_format.h | 3 +++ src/gallium/drivers/etnaviv/etnaviv_rs.c | 3 ++- .../drivers/etnaviv/etnaviv_texture_desc.c | 9 ++++++++- .../drivers/etnaviv/etnaviv_texture_state.c | 9 ++++++++- src/gallium/drivers/etnaviv/etnaviv_transfer.c | 2 +- 7 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.c b/src/gallium/drivers/etnaviv/etnaviv_blt.c index f1f0690c15c..9aab726f206 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.c +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.c @@ -791,7 +791,8 @@ etna_try_blt_blit(struct pipe_context *pctx, /* For transfer blits of RB_SWAP formats, apply R<->B swizzle on the * linear side to convert between GPU-internal BGRA and CPU RGBA. */ if (ctx->in_transfer_blit && - translate_pe_format_rb_swap(blit_info->src.format)) { + translate_pe_format_rb_swap(blit_info->src.format) && + !src->shared && !dst->shared) { bool src_linear = src->layout == ETNA_LAYOUT_LINEAR; bool dst_linear = dst->layout == ETNA_LAYOUT_LINEAR; diff --git a/src/gallium/drivers/etnaviv/etnaviv_format.c b/src/gallium/drivers/etnaviv/etnaviv_format.c index 95acf794cda..547eee49b4d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_format.c +++ b/src/gallium/drivers/etnaviv/etnaviv_format.c @@ -395,6 +395,21 @@ translate_pe_format_rb_swap(enum pipe_format fmt) return formats[fmt].pe & PE_FORMAT_RB_SWAP; } +/* For shared resources with RB_SWAP formats, remaps the HW texture format + * back to the one matching the actual byte order in memory (e.g., A8B8G8R8 + * for RGBA data). Normally we use A8R8G8B8 to match PE-internal BGRA byte + * order, but shared resources store data in the standard byte order. + */ +uint32_t +remap_texture_format_rb_swap(uint32_t format) +{ + switch (format) { + case TEXTURE_FORMAT_A8R8G8B8: return TEXTURE_FORMAT_A8B8G8R8; + case TEXTURE_FORMAT_X8R8G8B8: return TEXTURE_FORMAT_X8B8G8R8; + default: return format; + } +} + enum pipe_format translate_pe_internal_format(enum pipe_format fmt) { diff --git a/src/gallium/drivers/etnaviv/etnaviv_format.h b/src/gallium/drivers/etnaviv/etnaviv_format.h index 824ae70c6d1..d8ef4ca3467 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_format.h +++ b/src/gallium/drivers/etnaviv/etnaviv_format.h @@ -56,6 +56,9 @@ translate_pe_format(enum pipe_format fmt); int translate_pe_format_rb_swap(enum pipe_format fmt); +uint32_t +remap_texture_format_rb_swap(uint32_t format); + enum pipe_format translate_pe_internal_format(enum pipe_format fmt); diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.c b/src/gallium/drivers/etnaviv/etnaviv_rs.c index 64cf2ec7bc6..9d8b9b5f26d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_rs.c +++ b/src/gallium/drivers/etnaviv/etnaviv_rs.c @@ -884,7 +884,8 @@ etna_try_rs_blit(struct pipe_context *pctx, .downsample_x = downsample_x, .downsample_y = downsample_y, .swap_rb = ctx->in_transfer_blit && - translate_pe_format_rb_swap(blit_info->src.format), + translate_pe_format_rb_swap(blit_info->src.format) && + !src->shared && !dst->shared, .dither = {0xffffffff, 0xffffffff}, // XXX dither when going from 24 to 16 bit? .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_DISABLED, .width = width, diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture_desc.c b/src/gallium/drivers/etnaviv/etnaviv_texture_desc.c index 950897cc4f3..013872d6c0f 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture_desc.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture_desc.c @@ -137,7 +137,14 @@ etna_create_sampler_view_desc(struct pipe_context *pctx, struct pipe_resource *p const struct util_format_description *desc = util_format_description(so->format); struct etna_sampler_view_desc *sv = CALLOC_STRUCT(etna_sampler_view_desc); struct etna_context *ctx = etna_context(pctx); - const uint32_t format = translate_texture_format(so->format); + uint32_t format = translate_texture_format(so->format); + + /* Shared resources store data in standard byte order (e.g., RGBA for + * R8G8B8A8_UNORM). Use the native texture format to read them correctly, + * bypassing the BGRA-internal optimization used for internal resources. */ + if (etna_resource(prsc)->shared && translate_pe_format_rb_swap(so->format)) + format = remap_texture_format_rb_swap(format); + const bool ext = !!(format & EXT_FORMAT); const bool astc = !!(format & ASTC_FORMAT); const uint32_t swiz = get_texture_swiz(so->format, so->swizzle_r, diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture_state.c b/src/gallium/drivers/etnaviv/etnaviv_texture_state.c index 2ccfef15af1..ddde0dd8152 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture_state.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture_state.c @@ -164,7 +164,14 @@ etna_create_sampler_view_state(struct pipe_context *pctx, struct pipe_resource * struct etna_sampler_view *sv = CALLOC_STRUCT(etna_sampler_view); struct etna_context *ctx = etna_context(pctx); struct etna_screen *screen = ctx->screen; - const uint32_t format = translate_texture_format(so->format); + uint32_t format = translate_texture_format(so->format); + + /* Shared resources store data in standard byte order (e.g., RGBA for + * R8G8B8A8_UNORM). Use the native texture format to read them correctly, + * bypassing the BGRA-internal optimization used for internal resources. */ + if (etna_resource(prsc)->shared && translate_pe_format_rb_swap(so->format)) + format = remap_texture_format_rb_swap(format); + const bool ext = !!(format & EXT_FORMAT); const bool astc = !!(format & ASTC_FORMAT); const bool srgb = util_format_is_srgb(so->format); diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c index ea8e57ed063..6f1dd1d05d1 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c +++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c @@ -347,7 +347,7 @@ etna_texture_map(struct pipe_context *pctx, struct pipe_resource *prsc, } if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture)) && - !translate_pe_format_rb_swap(prsc->format)) { + (!translate_pe_format_rb_swap(prsc->format) || rsc->shared)) { /* We have a texture resource which is the same age or newer than the * render resource. Use the texture resource, which avoids bouncing * pixels between the two resources, and we can de-tile it in s/w. */