diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.c b/src/gallium/drivers/etnaviv/etnaviv_blt.c index 9aab726f206..44f4c33b956 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.c +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.c @@ -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; diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c index 711300ca56f..8b90d220fc4 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c @@ -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 diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h index df0323ffdab..73d720fce5d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h @@ -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); diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h index fe13c95698c..0fe64896daa 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.h +++ b/src/gallium/drivers/etnaviv/etnaviv_context.h @@ -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; diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.c b/src/gallium/drivers/etnaviv/etnaviv_rs.c index 9d8b9b5f26d..2a60bdd17b3 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_rs.c +++ b/src/gallium/drivers/etnaviv/etnaviv_rs.c @@ -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, diff --git a/src/gallium/drivers/etnaviv/etnaviv_state.c b/src/gallium/drivers/etnaviv/etnaviv_state.c index 3846d4eaa04..c0cf3957ede 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_state.c +++ b/src/gallium/drivers/etnaviv/etnaviv_state.c @@ -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); } diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c index c0cb283ed0f..3c49ccf19c9 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c @@ -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; } } diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c index 6f1dd1d05d1..839f2d6f376 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c +++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c @@ -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; }