mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-07 04:58:05 +02:00
etnaviv: Convert PE-internal BGRA to RGBA when flushing shared resources
The PE renders RB_SWAP formats (e.g. R8G8B8A8_UNORM) using the A8R8G8B8
hardware format, which stores data in BGRA byte order internally. For
shared/dmabuf resources, external consumers expect the byte order
mandated by the DRM FourCC.
Hook into flush_resource to apply an R<->B swap during the existing
shadow-to-base copy, using the BLT dest swizzle or RS SWAP_RB.
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:
parent
377f2ec49c
commit
4172e9a918
8 changed files with 92 additions and 25 deletions
|
|
@ -728,7 +728,8 @@ etna_try_blt_blit(struct pipe_context *pctx,
|
|||
/* Flush destination, as the blit will invalidate any pending TS changes. */
|
||||
if (dst != src && etna_resource_level_needs_flush(dst_lev))
|
||||
etna_copy_resource(pctx, &dst->base, &dst->base,
|
||||
blit_info->dst.level, blit_info->dst.level);
|
||||
blit_info->dst.level, blit_info->dst.level,
|
||||
false);
|
||||
|
||||
/* Kick off BLT here */
|
||||
if (src == dst && src_lev->ts_compress_fmt < 0) {
|
||||
|
|
@ -788,11 +789,17 @@ etna_try_blt_blit(struct pipe_context *pctx,
|
|||
for (unsigned x=0; x<4; ++x)
|
||||
op.dest.swizzle[x] = x;
|
||||
|
||||
/* 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) &&
|
||||
!src->shared && !dst->shared) {
|
||||
/* Apply R<->B swizzle when needed:
|
||||
* - Transfer blits (CPU access): swap on the linear side to convert
|
||||
* between GPU-internal BGRA and CPU RGBA byte order.
|
||||
* - Shared resource flushes: swap dest to convert PE-internal BGRA
|
||||
* back to the standard RGBA byte order for external consumers. */
|
||||
if (ctx->blit_rb_swap) {
|
||||
op.dest.swizzle[0] = 2; /* R from B position */
|
||||
op.dest.swizzle[2] = 0; /* B from R position */
|
||||
} else if (ctx->in_transfer_blit &&
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -251,26 +251,66 @@ etna_resource_copy_region(struct pipe_context *pctx, struct pipe_resource *dst,
|
|||
static void
|
||||
etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
|
||||
{
|
||||
struct etna_context *ctx = etna_context(pctx);
|
||||
struct etna_resource *rsc = etna_resource(prsc);
|
||||
|
||||
/* When flushing a shared resource with an RB_SWAP format, the PE has
|
||||
* written BGRA bytes internally. Convert to RGBA during the flush copy
|
||||
* so the shared buffer has the correct byte order for external consumers. */
|
||||
const bool flush_rb_swap = rsc->shared &&
|
||||
translate_pe_format_rb_swap(prsc->format);
|
||||
|
||||
if (rsc->render) {
|
||||
if (etna_resource_older(rsc, etna_resource(rsc->render))) {
|
||||
if (rsc->damage) {
|
||||
for (unsigned i = 0; i < rsc->num_damage; i++) {
|
||||
etna_copy_resource_box(pctx, prsc, rsc->render, 0, 0, &rsc->damage[i]);
|
||||
etna_copy_resource_box(pctx, prsc, rsc->render, 0, 0,
|
||||
&rsc->damage[i], flush_rb_swap);
|
||||
}
|
||||
} else {
|
||||
etna_copy_resource(pctx, prsc, rsc->render, 0, 0);
|
||||
etna_copy_resource(pctx, prsc, rsc->render, 0, 0, flush_rb_swap);
|
||||
}
|
||||
|
||||
if (flush_rb_swap)
|
||||
rsc->shared_native_order = true;
|
||||
}
|
||||
} else if (!etna_resource_ext_ts(rsc) && etna_resource_needs_flush(rsc)) {
|
||||
etna_copy_resource(pctx, prsc, prsc, 0, 0);
|
||||
etna_copy_resource(pctx, prsc, prsc, 0, 0, flush_rb_swap);
|
||||
|
||||
if (flush_rb_swap) {
|
||||
rsc->shared_native_order = true;
|
||||
etna_resource_level_mark_changed(&rsc->levels[0]);
|
||||
}
|
||||
} 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,
|
||||
};
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst,
|
||||
struct pipe_resource *src, int first_level, int last_level)
|
||||
struct pipe_resource *src, int first_level, int last_level,
|
||||
bool rb_swap)
|
||||
{
|
||||
struct etna_context *ctx = etna_context(pctx);
|
||||
struct etna_resource *src_priv = etna_resource(src);
|
||||
|
|
@ -280,6 +320,8 @@ etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst,
|
|||
assert(src->array_size == dst->array_size);
|
||||
assert(last_level <= dst->last_level && last_level <= src->last_level);
|
||||
|
||||
ctx->blit_rb_swap = rb_swap;
|
||||
|
||||
struct pipe_blit_info blit = {};
|
||||
blit.mask = util_format_get_mask(dst->format);
|
||||
blit.filter = PIPE_TEX_FILTER_NEAREST;
|
||||
|
|
@ -324,12 +366,14 @@ etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst,
|
|||
else
|
||||
etna_resource_level_copy_seqno(&dst_priv->levels[level], &src_priv->levels[level]);
|
||||
}
|
||||
|
||||
ctx->blit_rb_swap = false;
|
||||
}
|
||||
|
||||
void
|
||||
etna_copy_resource_box(struct pipe_context *pctx, struct pipe_resource *dst,
|
||||
struct pipe_resource *src, int dst_level, int src_level,
|
||||
struct pipe_box *box)
|
||||
struct pipe_box *box, bool rb_swap)
|
||||
{
|
||||
struct etna_context *ctx = etna_context(pctx);
|
||||
struct etna_resource *src_priv = etna_resource(src);
|
||||
|
|
@ -339,6 +383,8 @@ etna_copy_resource_box(struct pipe_context *pctx, struct pipe_resource *dst,
|
|||
assert(src->array_size == dst->array_size);
|
||||
assert(!etna_resource_level_needs_flush(&dst_priv->levels[dst_level]));
|
||||
|
||||
ctx->blit_rb_swap = rb_swap;
|
||||
|
||||
struct pipe_blit_info blit = {};
|
||||
blit.mask = util_format_get_mask(dst->format);
|
||||
blit.filter = PIPE_TEX_FILTER_NEAREST;
|
||||
|
|
@ -366,6 +412,8 @@ etna_copy_resource_box(struct pipe_context *pctx, struct pipe_resource *dst,
|
|||
else
|
||||
etna_resource_level_copy_seqno(&dst_priv->levels[dst_level],
|
||||
&src_priv->levels[src_level]);
|
||||
|
||||
ctx->blit_rb_swap = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -35,12 +35,13 @@ struct etna_context;
|
|||
|
||||
void
|
||||
etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst,
|
||||
struct pipe_resource *src, int first_level, int last_level);
|
||||
struct pipe_resource *src, int first_level, int last_level,
|
||||
bool rb_swap);
|
||||
|
||||
void
|
||||
etna_copy_resource_box(struct pipe_context *pctx, struct pipe_resource *dst,
|
||||
struct pipe_resource *src, int dst_level, int src_level,
|
||||
struct pipe_box *box);
|
||||
struct pipe_box *box, bool rb_swap);
|
||||
|
||||
void
|
||||
etna_blit_save_state(struct etna_context *ctx, bool render_cond);
|
||||
|
|
|
|||
|
|
@ -243,6 +243,11 @@ struct etna_context {
|
|||
bool compute_only;
|
||||
bool in_draw_vbo;
|
||||
bool in_transfer_blit;
|
||||
|
||||
/* Set by etna_copy_resource/etna_copy_resource_box when the caller
|
||||
* needs an R<->B swap during the blit. Consumed by BLT/RS because
|
||||
* pipe_blit_info has no driver-private field to carry this through. */
|
||||
bool blit_rb_swap;
|
||||
bool needs_gpu_state_reset;
|
||||
bool alpha_coverage_dither_emitted;
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ etna_blit_clear_zs_rs(struct pipe_context *pctx, struct pipe_surface *dst,
|
|||
/* If the level has valid TS state we need to flush it, as the regular
|
||||
* clear will not update the state and we must therefore invalidate it. */
|
||||
etna_copy_resource(pctx, &dst_res->base, &dst_res->base,
|
||||
dst->level, dst->level);
|
||||
dst->level, dst->level, false);
|
||||
|
||||
etna_rs_gen_clear_cmd(ctx, dst, dst_res, new_clear_value, new_clear_bits, &rs_state);
|
||||
|
||||
|
|
@ -813,7 +813,8 @@ etna_try_rs_blit(struct pipe_context *pctx,
|
|||
/* Flush destination, as the blit will invalidate any pending TS changes. */
|
||||
if (dst != src && etna_resource_level_needs_flush(dst_lev))
|
||||
etna_copy_resource(pctx, &dst->base, &dst->base,
|
||||
blit_info->dst.level, blit_info->dst.level);
|
||||
blit_info->dst.level, blit_info->dst.level,
|
||||
false);
|
||||
|
||||
/* Always flush color and depth cache together before resolving. This makes
|
||||
* sure that all previous cache content written by the PE is flushed out
|
||||
|
|
@ -883,9 +884,12 @@ etna_try_rs_blit(struct pipe_context *pctx,
|
|||
.dest_padded_height = dst_lev->padded_height,
|
||||
.downsample_x = downsample_x,
|
||||
.downsample_y = downsample_y,
|
||||
.swap_rb = ctx->in_transfer_blit &&
|
||||
translate_pe_format_rb_swap(blit_info->src.format) &&
|
||||
!src->shared && !dst->shared,
|
||||
/* Swap R<->B when requested by the caller (shared resource flush) or
|
||||
* for transfer blits of RB_SWAP formats on non-shared resources. */
|
||||
.swap_rb = ctx->blit_rb_swap ||
|
||||
(ctx->in_transfer_blit &&
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ etna_update_render_surface(struct pipe_context *pctx,
|
|||
|
||||
if ((to != from) &&
|
||||
etna_resource_level_older(&to->levels[level], &from->levels[level]))
|
||||
etna_copy_resource(pctx, &to->base, &from->base, level, level);
|
||||
etna_copy_resource(pctx, &to->base, &from->base, level, level, false);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -166,7 +166,7 @@ etna_set_framebuffer_state(struct pipe_context *pctx,
|
|||
|
||||
/* Resolve TS if needed */
|
||||
if (!use_ts) {
|
||||
etna_copy_resource(pctx, &res->base, &res->base, surf->level, surf->level);
|
||||
etna_copy_resource(pctx, &res->base, &res->base, surf->level, surf->level, false);
|
||||
etna_resource_level_ts_mark_invalid(level);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,8 @@ etna_update_sampler_source(struct pipe_sampler_view *view, int num)
|
|||
if ((to != from) && etna_resource_older(to, from)) {
|
||||
etna_copy_resource(view->context, &to->base, &from->base,
|
||||
view->u.tex.first_level,
|
||||
MIN2(view->texture->last_level, view->u.tex.last_level));
|
||||
MIN2(view->texture->last_level, view->u.tex.last_level),
|
||||
false);
|
||||
ctx->dirty |= ETNA_DIRTY_TEXTURE_CACHES;
|
||||
} else if (to == from) {
|
||||
if (etna_can_use_sampler_ts(view, num)) {
|
||||
|
|
@ -191,7 +192,8 @@ etna_update_sampler_source(struct pipe_sampler_view *view, int num)
|
|||
/* Resolve TS if needed */
|
||||
etna_copy_resource(view->context, &to->base, &from->base,
|
||||
view->u.tex.first_level,
|
||||
MIN2(view->texture->last_level, view->u.tex.last_level));
|
||||
MIN2(view->texture->last_level, view->u.tex.last_level),
|
||||
false);
|
||||
ctx->dirty |= ETNA_DIRTY_TEXTURE_CACHES;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ etna_texture_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
|
|||
if (ptrans->usage & ETNA_PIPE_MAP_DISCARD_LEVEL)
|
||||
etna_resource_level_mark_flushed(res_level);
|
||||
else
|
||||
etna_copy_resource(pctx, &rsc->base, &rsc->base, ptrans->level, ptrans->level);
|
||||
etna_copy_resource(pctx, &rsc->base, &rsc->base, ptrans->level, ptrans->level, false);
|
||||
}
|
||||
|
||||
if (trans->rsc) {
|
||||
|
|
@ -227,7 +227,7 @@ etna_texture_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
|
|||
*/
|
||||
ctx->in_transfer_blit = true;
|
||||
etna_copy_resource_box(pctx, ptrans->resource, trans->rsc,
|
||||
ptrans->level, 0, &ptrans->box);
|
||||
ptrans->level, 0, &ptrans->box, false);
|
||||
ctx->in_transfer_blit = false;
|
||||
} else if (trans->staging) {
|
||||
/* map buffer object */
|
||||
|
|
@ -393,7 +393,7 @@ etna_texture_map(struct pipe_context *pctx, struct pipe_resource *prsc,
|
|||
|
||||
if ((usage & PIPE_MAP_READ) || !(usage & ETNA_PIPE_MAP_DISCARD_LEVEL)) {
|
||||
ctx->in_transfer_blit = true;
|
||||
etna_copy_resource_box(pctx, trans->rsc, &rsc->base, 0, level, &ptrans->box);
|
||||
etna_copy_resource_box(pctx, trans->rsc, &rsc->base, 0, level, &ptrans->box, false);
|
||||
ctx->in_transfer_blit = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue