Very nice work! Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzw...@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.brezil...@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 >
signature.asc
Description: PGP signature
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev