summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/panfrost/pan_blit.c10
-rw-r--r--src/gallium/drivers/panfrost/pan_context.c75
-rw-r--r--src/gallium/drivers/panfrost/pan_job.c11
-rw-r--r--src/gallium/drivers/panfrost/pan_job.h5
-rw-r--r--src/gallium/drivers/panfrost/pan_resource.c80
-rw-r--r--src/gallium/drivers/panfrost/pan_resource.h13
-rw-r--r--src/gallium/drivers/panfrost/pan_screen.c1
7 files changed, 188 insertions, 7 deletions
diff --git a/src/gallium/drivers/panfrost/pan_blit.c b/src/gallium/drivers/panfrost/pan_blit.c
index 461bd8eec35..4be8c044ee2 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 409c852a228..7b80da2795a 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -1379,7 +1379,80 @@ 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);
+
+ /* 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.
+ */
+ batch->minx = batch->minx & ~((MALI_TILE_LENGTH * 2) - 1);
+ batch->miny = batch->miny & ~((MALI_TILE_LENGTH * 2) - 1);
+ batch->maxx = MIN2(ALIGN_POT(batch->maxx, MALI_TILE_LENGTH * 2),
+ rsrc->base.width0);
+ batch->maxy = MIN2(ALIGN_POT(batch->maxy, MALI_TILE_LENGTH * 2),
+ rsrc->base.height0);
+
+ 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 661f8ae154e..bfa73a7f334 100644
--- a/src/gallium/drivers/panfrost/pan_job.c
+++ b/src/gallium/drivers/panfrost/pan_job.c
@@ -420,6 +420,17 @@ panfrost_job_union_scissor(struct panfrost_job *job,
}
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)
{
ctx->jobs = _mesa_hash_table_create(ctx,
diff --git a/src/gallium/drivers/panfrost/pan_job.h b/src/gallium/drivers/panfrost/pan_job.h
index a5ea5bf41cc..0f559b861a0 100644
--- a/src/gallium/drivers/panfrost/pan_job.h
+++ b/src/gallium/drivers/panfrost/pan_job.h
@@ -168,6 +168,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 f74a39555b4..1f5b23145cf 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -403,6 +403,84 @@ panfrost_resource_create_bo(struct panfrost_screen *screen, struct panfrost_reso
pres->bo = panfrost_drm_create_bo(screen, bo_size, PAN_ALLOCATE_DELAY_MMAP);
}
+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,
+ const struct pipe_box *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++) {
+ int x = rects[i].x, w = rects[i].width, h = rects[i].height;
+ int y = res->height0 - (rects[i].y + h);
+
+ /* 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);
+
+ damage_extent->minx = MIN2(damage_extent->minx, x);
+ damage_extent->miny = MIN2(damage_extent->miny, y);
+ damage_extent->maxx = MAX2(damage_extent->maxx,
+ MIN2(x + w, res->width0));
+ damage_extent->maxy = MAX2(damage_extent->maxy,
+ MIN2(y + h, res->height0));
+ }
+}
+
static struct pipe_resource *
panfrost_resource_create(struct pipe_screen *screen,
const struct pipe_resource *template)
@@ -437,6 +515,8 @@ panfrost_resource_create(struct pipe_screen *screen,
util_range_init(&so->valid_buffer_range);
panfrost_resource_create_bo(pscreen, so);
+ 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 e51ba8959c3..6ed3d1fd60e 100644
--- a/src/gallium/drivers/panfrost/pan_resource.h
+++ b/src/gallium/drivers/panfrost/pan_resource.h
@@ -65,6 +65,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;
@@ -134,6 +138,13 @@ 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,
+ const struct pipe_box *rects);
#endif /* PAN_RESOURCE_H */
diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
index 510828ce555..d56897729a3 100644
--- a/src/gallium/drivers/panfrost/pan_screen.c
+++ b/src/gallium/drivers/panfrost/pan_screen.c
@@ -659,6 +659,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;