[Mesa-dev] [PATCH v5 5/5] panfrost: Add support for KHR_partial_update()
Alyssa Rosenzweig
alyssa.rosenzweig at collabora.com
Tue Jul 2 16:47:43 UTC 2019
Very nice work!
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig at collabora.com>
On Tue, Jul 02, 2019 at 03:50:02PM +0200, Boris Brezillon wrote:
> Implement ->set_damage_region() region to support partial updates.
>
> This is a dummy implementation in that it does not try to merge
> damage rects. It also does not deal with distinct regions and instead
> pick the largest quad as the only damage rect and generate up to 4
> reload rects out of it (the left/right/top/bottom regions surrounding
> the biggest damage rect).
>
> We also do not try to reduce the number of draws by passing all quad
> vertices to the blit request (would require extending u_blitter)
>
> Signed-off-by: Boris Brezillon <boris.brezillon at collabora.com>
> ---
> Changes in v5:
> - rename the second panfrost_blit_wallpaper() argument
> - add extra comment to explain how the set_damage_region() logic works
> - clarify why checking for negative box->{width,heigh} is not needed in
> panfrost_draw_wallpaper()
> ---
> src/gallium/drivers/panfrost/pan_blit.c | 10 +--
> src/gallium/drivers/panfrost/pan_context.c | 63 +++++++++++++-
> src/gallium/drivers/panfrost/pan_job.c | 11 +++
> src/gallium/drivers/panfrost/pan_job.h | 5 ++
> src/gallium/drivers/panfrost/pan_resource.c | 91 +++++++++++++++++++++
> src/gallium/drivers/panfrost/pan_resource.h | 12 ++-
> src/gallium/drivers/panfrost/pan_screen.c | 1 +
> 7 files changed, 186 insertions(+), 7 deletions(-)
>
> diff --git a/src/gallium/drivers/panfrost/pan_blit.c b/src/gallium/drivers/panfrost/pan_blit.c
> index 67912a4b130f..226f67e674f5 100644
> --- a/src/gallium/drivers/panfrost/pan_blit.c
> +++ b/src/gallium/drivers/panfrost/pan_blit.c
> @@ -103,7 +103,7 @@ panfrost_blit(struct pipe_context *pipe,
> */
>
> void
> -panfrost_blit_wallpaper(struct panfrost_context *ctx)
> +panfrost_blit_wallpaper(struct panfrost_context *ctx, struct pipe_box *box)
> {
> struct pipe_blit_info binfo = { };
>
> @@ -116,11 +116,11 @@ panfrost_blit_wallpaper(struct panfrost_context *ctx)
>
> binfo.src.resource = binfo.dst.resource = ctx->pipe_framebuffer.cbufs[0]->texture;
> binfo.src.level = binfo.dst.level = level;
> - binfo.src.box.x = binfo.dst.box.x = 0;
> - binfo.src.box.y = binfo.dst.box.y = 0;
> + binfo.src.box.x = binfo.dst.box.x = box->x;
> + binfo.src.box.y = binfo.dst.box.y = box->y;
> binfo.src.box.z = binfo.dst.box.z = layer;
> - binfo.src.box.width = binfo.dst.box.width = ctx->pipe_framebuffer.width;
> - binfo.src.box.height = binfo.dst.box.height = ctx->pipe_framebuffer.height;
> + binfo.src.box.width = binfo.dst.box.width = box->width;
> + binfo.src.box.height = binfo.dst.box.height = box->height;
> binfo.src.box.depth = binfo.dst.box.depth = 1;
>
> binfo.src.format = binfo.dst.format = ctx->pipe_framebuffer.cbufs[0]->format;
> diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c
> index 88e70c978818..7462e490e229 100644
> --- a/src/gallium/drivers/panfrost/pan_context.c
> +++ b/src/gallium/drivers/panfrost/pan_context.c
> @@ -1472,7 +1472,68 @@ panfrost_draw_wallpaper(struct pipe_context *pipe)
> struct panfrost_job *batch = panfrost_get_job_for_fbo(ctx);
>
> ctx->wallpaper_batch = batch;
> - panfrost_blit_wallpaper(ctx);
> +
> + /* Clamp the rendering area to the damage extent. The
> + * KHR_partial_update() spec states that trying to render outside of
> + * the damage region is "undefined behavior", so we should be safe.
> + */
> + panfrost_job_intersection_scissor(batch, rsrc->damage.extent.minx,
> + rsrc->damage.extent.miny,
> + rsrc->damage.extent.maxx,
> + rsrc->damage.extent.maxy);
> +
> + struct pipe_scissor_state damage;
> + struct pipe_box rects[4];
> +
> + /* Clamp the damage box to the rendering area. */
> + damage.minx = MAX2(batch->minx, rsrc->damage.biggest_rect.x);
> + damage.miny = MAX2(batch->miny, rsrc->damage.biggest_rect.y);
> + damage.maxx = MIN2(batch->maxx,
> + rsrc->damage.biggest_rect.x +
> + rsrc->damage.biggest_rect.width);
> + damage.maxy = MIN2(batch->maxy,
> + rsrc->damage.biggest_rect.y +
> + rsrc->damage.biggest_rect.height);
> +
> + /* One damage rectangle means we can end up with at most 4 reload
> + * regions:
> + * 1: left region, only exists if damage.x > 0
> + * 2: right region, only exists if damage.x + damage.width < fb->width
> + * 3: top region, only exists if damage.y > 0. The intersection with
> + * the left and right regions are dropped
> + * 4: bottom region, only exists if damage.y + damage.height < fb->height.
> + * The intersection with the left and right regions are dropped
> + *
> + * ____________________________
> + * | | 3 | |
> + * | |___________| |
> + * | | damage | |
> + * | 1 | rect | 2 |
> + * | |___________| |
> + * | | 4 | |
> + * |_______|___________|______|
> + */
> + u_box_2d(batch->minx, batch->miny, damage.minx - batch->minx,
> + batch->maxy - batch->miny, &rects[0]);
> + u_box_2d(damage.maxx, batch->miny, batch->maxx - damage.maxx,
> + batch->maxy - batch->miny, &rects[1]);
> + u_box_2d(damage.minx, batch->miny, damage.maxx - damage.minx,
> + damage.miny - batch->miny, &rects[2]);
> + u_box_2d(damage.minx, damage.maxy, damage.maxx - damage.minx,
> + batch->maxy - damage.maxy, &rects[3]);
> +
> + for (unsigned i = 0; i < 4; i++) {
> + /* Width and height are always >= 0 even if width is declared as a
> + * signed integer: u_box_2d() helper takes unsigned args and
> + * panfrost_set_damage_region() is taking care of clamping
> + * negative values.
> + */
> + if (!rects[i].width || !rects[i].height)
> + continue;
> +
> + /* Blit the wallpaper in */
> + panfrost_blit_wallpaper(ctx, &rects[i]);
> + }
> ctx->wallpaper_batch = NULL;
> }
>
> diff --git a/src/gallium/drivers/panfrost/pan_job.c b/src/gallium/drivers/panfrost/pan_job.c
> index 2f7fe9e3cc3d..4f855c9935a4 100644
> --- a/src/gallium/drivers/panfrost/pan_job.c
> +++ b/src/gallium/drivers/panfrost/pan_job.c
> @@ -300,6 +300,17 @@ panfrost_job_union_scissor(struct panfrost_job *job,
> job->maxy = MAX2(job->maxy, maxy);
> }
>
> +void
> +panfrost_job_intersection_scissor(struct panfrost_job *job,
> + unsigned minx, unsigned miny,
> + unsigned maxx, unsigned maxy)
> +{
> + job->minx = MAX2(job->minx, minx);
> + job->miny = MAX2(job->miny, miny);
> + job->maxx = MIN2(job->maxx, maxx);
> + job->maxy = MIN2(job->maxy, maxy);
> +}
> +
> void
> panfrost_job_init(struct panfrost_context *ctx)
> {
> diff --git a/src/gallium/drivers/panfrost/pan_job.h b/src/gallium/drivers/panfrost/pan_job.h
> index b4c9db9828e2..f98572387ed0 100644
> --- a/src/gallium/drivers/panfrost/pan_job.h
> +++ b/src/gallium/drivers/panfrost/pan_job.h
> @@ -152,6 +152,11 @@ panfrost_job_union_scissor(struct panfrost_job *job,
> unsigned minx, unsigned miny,
> unsigned maxx, unsigned maxy);
>
> +void
> +panfrost_job_intersection_scissor(struct panfrost_job *job,
> + unsigned minx, unsigned miny,
> + unsigned maxx, unsigned maxy);
> +
> /* Scoreboarding */
>
> void
> diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c
> index 8db7e45af1b6..50155f8b68df 100644
> --- a/src/gallium/drivers/panfrost/pan_resource.c
> +++ b/src/gallium/drivers/panfrost/pan_resource.c
> @@ -364,6 +364,95 @@ panfrost_create_bo(struct panfrost_screen *screen, const struct pipe_resource *t
> return bo;
> }
>
> +static void
> +panfrost_resource_reset_damage(struct panfrost_resource *pres)
> +{
> + /* We set the damage extent to the full resource size but keep the
> + * damage box empty so that the FB content is reloaded by default.
> + */
> + memset(&pres->damage, 0, sizeof(pres->damage));
> + pres->damage.extent.maxx = pres->base.width0;
> + pres->damage.extent.maxy = pres->base.height0;
> +}
> +
> +void
> +panfrost_resource_set_damage_region(struct pipe_screen *screen,
> + struct pipe_resource *res,
> + unsigned int nrects, int *rects)
> +{
> + struct panfrost_resource *pres = pan_resource(res);
> + struct pipe_box *damage_rect = &pres->damage.biggest_rect;
> + struct pipe_scissor_state *damage_extent = &pres->damage.extent;
> + unsigned int i;
> +
> + if (!nrects) {
> + panfrost_resource_reset_damage(pres);
> + return;
> + }
> +
> + /* We keep track of 2 different things here:
> + * 1 the damage extent: the quad including all damage regions. Will be
> + * used restrict the rendering area
> + * 2 the biggest damage rectangle: when there are more than one damage
> + * rect we keep the biggest one and will generate 4 wallpaper quads
> + * out of it (see panfrost_draw_wallpaper() for more details). We
> + * might want to do something smarter at some point.
> + *
> + * _________________________________
> + * | |
> + * | _________________________ |
> + * | | rect1| _________| |
> + * | |______|_____ | rect 3: | |
> + * | | | rect2 | | biggest | |
> + * | | |_______| | rect | |
> + * | |_______________|_________| |
> + * | damage extent |
> + * |_______________________________|
> + * resource
> + */
> + memset(&pres->damage, 0, sizeof(pres->damage));
> + damage_extent->minx = 0xffff;
> + damage_extent->miny = 0xffff;
> + for (i = 0; i < nrects; i++) {
> + struct pipe_scissor_state ss;
> + int *rect = &rects[i * 4];
> + int x = rect[0], w = rect[2];
> + int y = res->height0 - (rect[1] + rect[3]), h = rect[3];
> +
> + /* Clamp x,y,w,h to prevent negative values. */
> + if (x < 0) {
> + h += x;
> + x = 0;
> + }
> + if (y < 0) {
> + w += y;
> + y = 0;
> + }
> + w = MAX2(w, 0);
> + h = MAX2(h, 0);
> +
> + if (damage_rect->width * damage_rect->height < w * h)
> + u_box_2d(x, y, w, h, damage_rect);
> +
> + /* FIXME: Looks like aligning on a tile is not enough, but
> + * aligning on twice the tile size seems to works. We don't
> + * know exactly what happens here but this deserves extra
> + * investigation to figure it out.
> + */
> + ss.minx = x & ~((MALI_TILE_LENGTH * 2) - 1);
> + ss.miny = y & ~((MALI_TILE_LENGTH * 2) - 1);
> + ss.maxx = MIN2(ALIGN(x + w, MALI_TILE_LENGTH * 2),
> + res->width0);
> + ss.maxy = MIN2(ALIGN(y + h, MALI_TILE_LENGTH * 2),
> + res->height0);
> +
> + damage_extent->minx = MIN2(damage_extent->minx, ss.minx);
> + damage_extent->miny = MIN2(damage_extent->miny, ss.miny);
> + damage_extent->maxx = MAX2(damage_extent->maxx, ss.maxx);
> + damage_extent->maxy = MAX2(damage_extent->maxy, ss.maxy);
> + }
> +}
> +
> static struct pipe_resource *
> panfrost_resource_create(struct pipe_screen *screen,
> const struct pipe_resource *template)
> @@ -420,6 +509,8 @@ panfrost_resource_create(struct pipe_screen *screen,
> so->bo = panfrost_create_bo(pscreen, template);
> }
>
> + panfrost_resource_reset_damage(so);
> +
> return (struct pipe_resource *)so;
> }
>
> diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h
> index 89a4396c0939..c9fc9f691518 100644
> --- a/src/gallium/drivers/panfrost/pan_resource.h
> +++ b/src/gallium/drivers/panfrost/pan_resource.h
> @@ -95,6 +95,10 @@ panfrost_bo_unreference(struct pipe_screen *screen, struct panfrost_bo *bo);
>
> struct panfrost_resource {
> struct pipe_resource base;
> + struct {
> + struct pipe_box biggest_rect;
> + struct pipe_scissor_state extent;
> + } damage;
>
> struct panfrost_bo *bo;
> struct renderonly_scanout *scanout;
> @@ -146,6 +150,12 @@ panfrost_blit(struct pipe_context *pipe,
> const struct pipe_blit_info *info);
>
> void
> -panfrost_blit_wallpaper(struct panfrost_context *ctx);
> +panfrost_blit_wallpaper(struct panfrost_context *ctx,
> + struct pipe_box *box);
> +
> +void
> +panfrost_resource_set_damage_region(struct pipe_screen *screen,
> + struct pipe_resource *res,
> + unsigned int nrects, int *rects);
>
> #endif /* PAN_RESOURCE_H */
> diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
> index d6b1bc89fc19..31497a6a7bee 100644
> --- a/src/gallium/drivers/panfrost/pan_screen.c
> +++ b/src/gallium/drivers/panfrost/pan_screen.c
> @@ -600,6 +600,7 @@ panfrost_create_screen(int fd, struct renderonly *ro)
> screen->base.get_compiler_options = panfrost_screen_get_compiler_options;
> screen->base.fence_reference = panfrost_fence_reference;
> screen->base.fence_finish = panfrost_fence_finish;
> + screen->base.set_damage_region = panfrost_resource_set_damage_region;
>
> screen->last_fragment_flushed = true;
> screen->last_job = NULL;
> --
> 2.21.0
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20190702/64b92a78/attachment-0001.sig>
More information about the mesa-dev
mailing list