panfrost: Add infrastructure for fullscreen draw calls

Panfrost blits are implemented using u_blitter which exposes the
draw_rectangle handler for drivers to blit with dedicated GPU
support. By default, it ends up blitting with a draw_vbo call on the
pipe. In Panfrost, draw_vbo then emits a full-featured draw call using
an indexed or malloc vertex shader job on pre-CSF GPUs or a RUN_IDVS
instruction on CSF GPUs. Since v9, Mali GPUs expose a lighter draw
call with the FullScreenJob descriptor on pre-CSF GPUs or with the
RUN_FULLSCREEN instruction on CSF GPUs. These draw calls emit a quad
primitive into the polygon list and run tiling of a fullscreen
fragment job without vertex processing. This commit adds the
infrastructure to implement blits using fullscreen draw calls.

It supports all types of blits apart from the instanced ones. Partial
blits are supported using scissors and textured blits are supported
using varying interpolation and fragment shading.

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Ashley Smith <ashley.smith@collabora.com>
Acked-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40124>
This commit is contained in:
Loïc Molinari 2026-03-31 14:48:37 +02:00 committed by Marge Bot
parent d83e090f12
commit 6ad3944290
9 changed files with 144 additions and 1 deletions

View file

@ -10,6 +10,77 @@
#include "pan_trace.h"
#include "pan_util.h"
static void
panfrost_blitter_draw_rectangle(struct blitter_context *blitter,
void *vertex_elements_cso,
blitter_get_vs_func get_vs,
int x1, int y1, int x2, int y2,
float depth, unsigned num_instances,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib)
{
assert(num_instances);
struct pipe_context *ctx = blitter->pipe;
struct panfrost_context *pctx = pan_context(ctx);
struct panfrost_screen *scr = pan_screen(ctx->screen);
/* Always fallback for now. */
goto fallback;
/* Map viewport to the dest rect of the framebuffer. The tiler will then be
* configured to use it as scissor box in order to clip fullscreen
* fragments lying outside.
*
* Note that: tx = x1 + ((x2 - x1) / 2) = (x2 + x1) / 2
* ty = y1 + ((y2 - y1) / 2) = (y2 + y1) / 2
*/
const struct pipe_viewport_state viewport_state = {
.scale = { 0.5f * (x2 - x1), 0.5f * (y2 - y1), 1.0f },
.translate = { 0.5f * (x2 + x1), 0.5f * (y2 + y1), 0.0f },
.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X,
.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y,
.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z,
.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W
};
ctx->set_viewport_states(ctx, 0, 1, &viewport_state);
/* Map texture coordinates to the fullscreen framebuffer. */
struct blitter_attrib fs_attrib;
if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY ||
type == UTIL_BLITTER_ATTRIB_TEXCOORD_XYZW) {
float dfdx = (attrib->texcoord.x2 - attrib->texcoord.x1) / (x2 - x1);
float dfdy = (attrib->texcoord.y2 - attrib->texcoord.y1) / (y2 - y1);
float w = pctx->pipe_framebuffer.width;
float h = pctx->pipe_framebuffer.height;
fs_attrib = *attrib;
fs_attrib.texcoord.x1 -= dfdx * x1;
fs_attrib.texcoord.y1 -= dfdy * y1;
fs_attrib.texcoord.x2 += dfdx * (w - x2);
fs_attrib.texcoord.y2 += dfdy * (h - y2);
};
scr->vtbl.draw_fullscreen(pan_context(ctx), get_vs(blitter), type,
&fs_attrib);
return;
fallback:
/* Fallback to draw_vbo. */
util_blitter_draw_rectangle(blitter, vertex_elements_cso, get_vs, x1, y1,
x2, y2, depth, num_instances, type, attrib);
}
struct blitter_context *
panfrost_blitter_create(struct pipe_context *pipe)
{
struct blitter_context *blitter;
blitter = util_blitter_create(pipe);
blitter->draw_rectangle = panfrost_blitter_draw_rectangle;
return blitter;
}
void
panfrost_blitter_save(struct panfrost_context *ctx,
const enum panfrost_blitter_op blitter_op)

View file

@ -3665,6 +3665,43 @@ panfrost_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info,
}
}
static void
panfrost_draw_fullscreen(struct panfrost_context *ctx,
struct panfrost_uncompiled_shader *vs,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib)
{
assert(!ctx->active_queries);
assert(!ctx->streamout.num_targets);
PAN_TRACE_FUNC(PAN_TRACE_GL_CMDSTREAM);
ctx->draw_calls++;
struct panfrost_batch *batch = prepare_draw(&ctx->base, MESA_PRIM_QUADS);
if (!batch) {
mesa_loge("prepare_draw failed");
return;
}
/* Fullscreen draw calls don't configure any position or varying shader but
* link info is needed. The active primitive update takes care of the
* fragment shader variant update. */
ctx->uncompiled[MESA_SHADER_VERTEX] = vs;
panfrost_update_shader_variant(ctx, MESA_SHADER_VERTEX);
panfrost_update_active_prim(ctx, MESA_PRIM_QUADS);
/* Clear the dirty vertex flag to ensure the shader state update doesn't
* emit any vertex info. */
ctx->dirty &= ~PAN_DIRTY_VERTEX;
panfrost_update_state_3d(batch);
panfrost_update_shader_state(batch, MESA_SHADER_FRAGMENT);
panfrost_clean_state_3d(ctx);
JOBX(launch_draw_fullscreen)(batch, type, attrib);
batch->draw_count++;
}
/* Launch grid is the compute equivalent of draw_vbo, so in this routine, we
* construct the COMPUTE job and some of its payload.
*/
@ -4683,6 +4720,7 @@ GENX(panfrost_cmdstream_screen_init)(struct panfrost_screen *screen)
screen->vtbl.emit_write_timestamp = emit_write_timestamp;
screen->vtbl.select_tile_size = GENX(pan_select_tile_size);
screen->vtbl.get_conv_desc = get_conv_desc;
screen->vtbl.draw_fullscreen = panfrost_draw_fullscreen;
pan_blend_shader_cache_init(&dev->blend_shaders, panfrost_device_gpu_id(dev),
dev->kmod.dev->props.gpu_variant,

View file

@ -1100,7 +1100,7 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
goto failed;
}
ctx->blitter = util_blitter_create(gallium);
ctx->blitter = panfrost_blitter_create(gallium);
ctx->writers = _mesa_hash_table_create(gallium, _mesa_hash_pointer,
_mesa_key_pointer_equal);

View file

@ -1461,6 +1461,14 @@ GENX(csf_launch_draw_indirect)(struct panfrost_batch *batch,
}
}
void
GENX(csf_launch_draw_fullscreen)(struct panfrost_batch *batch,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib)
{
UNREACHABLE("draw fullscreen not implemented for csf");
}
#define POSITION_FIFO_SIZE (64 * 1024)
static enum drm_panthor_group_priority

View file

@ -83,6 +83,7 @@ struct panfrost_csf_context {
#if defined(PAN_ARCH) && PAN_ARCH >= 10
#include "genxml/gen_macros.h"
#include "util/u_blitter.h"
struct panfrost_batch;
struct panfrost_context;
@ -120,6 +121,9 @@ void GENX(csf_launch_draw_indirect)(struct panfrost_batch *batch,
const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect);
void GENX(csf_launch_draw_fullscreen)(struct panfrost_batch *batch,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib);
void GENX(csf_emit_write_timestamp)(struct panfrost_batch *batch,
struct panfrost_resource *dst,

View file

@ -1020,6 +1020,14 @@ GENX(jm_launch_draw_indirect)(struct panfrost_batch *batch,
UNREACHABLE("draw indirect not implemented for jm");
}
void
GENX(jm_launch_draw_fullscreen)(struct panfrost_batch *batch,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib)
{
UNREACHABLE("draw fullscreen not implemented for jm");
}
void
GENX(jm_emit_write_timestamp)(struct panfrost_batch *batch,
struct panfrost_resource *dst, unsigned offset)

View file

@ -26,6 +26,7 @@ struct panfrost_jm_batch {
#if defined(PAN_ARCH) && PAN_ARCH < 10
#include "genxml/gen_macros.h"
#include "util/u_blitter.h"
struct panfrost_batch;
struct panfrost_context;
@ -75,6 +76,9 @@ void GENX(jm_launch_draw_indirect)(struct panfrost_batch *batch,
const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect);
void GENX(jm_launch_draw_fullscreen)(struct panfrost_batch *batch,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib);
void GENX(jm_emit_write_timestamp)(struct panfrost_batch *batch,
struct panfrost_resource *dst,

View file

@ -167,6 +167,8 @@ enum {
PAN_RENDER_CLEAR = PAN_SAVE_FRAGMENT_STATE | PAN_SAVE_FRAGMENT_CONSTANT,
};
struct blitter_context *panfrost_blitter_create(struct pipe_context *pipe);
/* Callers should ensure that all AFBC/AFRC resources that will be used in the
* blit operation are legalized before calling blitter operations, otherwise
* we may trigger a recursive blit */

View file

@ -15,6 +15,7 @@
#include "util/disk_cache.h"
#include "util/log.h"
#include "util/set.h"
#include "util/u_blitter.h"
#include "util/u_dynarray.h"
#include "pan_device.h"
@ -30,6 +31,7 @@ struct panfrost_batch;
struct panfrost_context;
struct panfrost_resource;
struct panfrost_compiled_shader;
struct panfrost_uncompiled_shader;
struct pan_fb_info;
struct pan_blend_state;
@ -92,6 +94,12 @@ struct panfrost_vtable {
/* construct a render target blend descriptor */
uint64_t (*get_conv_desc)(enum pipe_format fmt, unsigned rt,
unsigned force_size, bool dithered);
/* Run a fullscreen draw call (for blits) */
void (*draw_fullscreen)(struct panfrost_context *ctx,
struct panfrost_uncompiled_shader *vs,
enum blitter_attrib_type type,
const struct blitter_attrib *attrib);
};
struct panfrost_screen {