From d77f2784aa7ea7edf2faada7c680f62f29bb7ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Molinari?= Date: Thu, 12 Mar 2026 15:24:47 +0100 Subject: [PATCH] panfrost: Legalize blit feedback loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A feedback loop exists when the data store of a texture object is used both as a source texture and as a destination color, depth or stencil buffer for a draw call. While this can't work when the source and destination are from intersecting sets of texels, it is supported for disjoint sets by letting users emit texture barriers between writes and reads. u_blitter allows blits with src == dst with disjoint texel sets with no texture barrier enforcement. Mali tile-based architecture can't guarantee that a disjoint read from the dst texture will fetch up-to-date values because it depends on the tile processing order. This commit adds a feedback loop check for blits and fixes the forced full flushing regression for blits introduced when de-pointerizing pipe_surface. This was necessary because the framebuffer comparison used when looking up batches for such blits stopped failing (no different pointers anymore) and the same batch was returned. It also enforces the draw_vbo fallback for blits with a feedback loop to work around a glCopyPixels() issue and it introduces another workaround for depth/stencil blits on v9. Fixes: 2eb45daa9c8 ("gallium: de-pointerize pipe_surface") Signed-off-by: Loïc Molinari Reviewed-by: Ashley Smith Part-of: --- src/gallium/drivers/panfrost/pan_blitter.c | 34 ++++++++++++++++++++-- src/gallium/drivers/panfrost/pan_context.h | 1 + 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_blitter.c b/src/gallium/drivers/panfrost/pan_blitter.c index f41061ff769..53d8c3f7dec 100644 --- a/src/gallium/drivers/panfrost/pan_blitter.c +++ b/src/gallium/drivers/panfrost/pan_blitter.c @@ -34,6 +34,32 @@ panfrost_blitter_draw_rectangle(struct blitter_context *blitter, struct panfrost_context *pctx = pan_context(ctx); struct panfrost_screen *scr = pan_screen(ctx->screen); + /* u_blitter allows src == dst for disjoint texel sets without any texture + * barrier enforcement. Mali tile-based architecture can't guarantee that a + * read from the dst texture will fetch up-to-date values since it depends + * on the tile processing order. Request a fresh batch to ensure any writes + * to the resource are flushed. Doing so in this callback ensures that the + * framebuffer state is set for the current blit. + * + * XXX This should ideally be done at the draw call handling level when it + * requests a batch for the current framebuffer (see prepare_draw) by first + * submitting any batches writing to the draw call's sampler views. This + * check (along with resource accesses handling) is currently done when + * emitting texture descriptors but it explicitly discards the special case + * where the batch writing to the draw call's sampler views is the current + * batch because it can't be submitted at this time of the draw call + * handling (see panfrost_batch_update_access). + */ + if (pctx->has_blit_loop) { + panfrost_get_fresh_batch_for_fbo(pctx, "Pre-blit flush"); + + /* XXX On all arch, Piglit's copy-pixels test sometimes fails to copy a + * block of pixels. Most easily reproducible at image size + * 50x38. Fallback to draw_vbo for now. + */ + goto fallback; + } + if (scr->dev.arch <= 8 || depth != 0.0f || num_instances > 1) goto fallback; @@ -77,6 +103,10 @@ panfrost_blitter_draw_rectangle(struct blitter_context *blitter, /* Fallback to draw_vbo. */ util_blitter_draw_rectangle(blitter, vertex_elements_cso, get_vs, x1, y1, x2, y2, depth, num_instances, type, attrib); + + /* XXX Depth/Stencil blits on v9 need that too. Not sure why. */ + if (pctx->has_blit_loop && scr->dev.arch == 9) + panfrost_flush_all_batches(pctx, "Post-blit flush"); } struct blitter_context * @@ -157,7 +187,9 @@ panfrost_blitter_blit_legalized(struct pipe_context *pipe, } panfrost_blitter_save(ctx, states); + ctx->has_blit_loop = info->src.resource == info->dst.resource; util_blitter_blit(ctx->blitter, info, NULL); + ctx->has_blit_loop = false; } void @@ -183,9 +215,7 @@ panfrost_blitter_blit(struct pipe_context *pipe, util_format_linear(info->src.format), false, false); pan_legalize_format(ctx, pan_resource(info->dst.resource), util_format_linear(info->dst.format), true, false); - panfrost_flush_all_batches(ctx, "Blit"); panfrost_blitter_blit_legalized(pipe, info); - panfrost_flush_all_batches(ctx, "Blit"); } /* Setup HW tile buffer clears if the batch for the current FBO doesn't have diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h index 6470921f16b..91e3d89bf9c 100644 --- a/src/gallium/drivers/panfrost/pan_context.h +++ b/src/gallium/drivers/panfrost/pan_context.h @@ -192,6 +192,7 @@ struct panfrost_context { } texture_buffer[MESA_SHADER_STAGES]; struct blitter_context *blitter; + bool has_blit_loop; struct pan_mod_convert_shaders mod_convert_shaders;