diff options
-rw-r--r-- | src/gallium/drivers/panfrost/pan_blit.c | 10 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_context.c | 75 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_job.c | 11 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_job.h | 5 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_resource.c | 80 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_resource.h | 13 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_screen.c | 1 |
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; |