diff options
author | Alyssa Rosenzweig <[email protected]> | 2020-07-09 13:42:25 -0400 |
---|---|---|
committer | Marge Bot <[email protected]> | 2020-07-16 15:10:55 +0000 |
commit | 293f251871b2fc7fd40d0fcabec4dd8a8324bc47 (patch) | |
tree | 628ac4a83448f365ac83e37bd4723c8851144876 /src/gallium | |
parent | f611af35948e4d1d56daa94f59d5feb7d44d24ce (diff) |
panfrost: Use Midgard-specific reloads
v2: Be more explicit about sampler types. Prefer the term "load" to
"resolve" to match VK convention. Generate shaders for MRT 8x. Blit
shader generation adds about 6ms to startup cost. We could cache thes.
shaders to disk if we needed to (or indeed, ship binaries).
v3: Fallback on u_blitter on Bifrost so Bifrost continues to work.
KHR_partial_update support is mostly no-oped on Bifrost now, but that's
okay for now - compositors are still functional.
v4: Specialize on multisample state as well to enable reloads of MSAA
textures. This requires 2x the shader variants, so I assume we're up to
12ms startup cost for generation. Annoying. Also fix interactions with
depth- or stencil-only clears of combined depth-stencil surfaces.
v5: Cache to the device (screen) instead of the context, reducing
duplicated work in apps that create many contexts (e.g. Chromium)
v6: Squash in KHR_partial_update cleanup to fix intermediate
regressions on a few tests.
Signed-off-by: Alyssa Rosenzweig <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5824>
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/drivers/panfrost/pan_context.c | 5 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_context.h | 2 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_job.c | 240 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_mfbd.c | 4 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_resource.c | 69 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_resource.h | 7 | ||||
-rw-r--r-- | src/gallium/drivers/panfrost/pan_screen.c | 3 |
7 files changed, 181 insertions, 149 deletions
diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index 4ae8ee31229..e63afd8d9cc 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -1567,6 +1567,11 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags) panfrost_batch_init(ctx); panfrost_invalidate_frame(ctx); + if (!(dev->quirks & IS_BIFROST)) { + for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) + ctx->blit_blend.rt[c].shaders = _mesa_hash_table_u64_create(ctx); + } + /* By default mask everything on */ ctx->sample_mask = ~0; diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h index 8e247091c40..7ba1170cdf3 100644 --- a/src/gallium/drivers/panfrost/pan_context.h +++ b/src/gallium/drivers/panfrost/pan_context.h @@ -165,6 +165,8 @@ struct panfrost_context { struct pipe_stencil_ref stencil_ref; unsigned sample_mask; unsigned min_samples; + + struct panfrost_blend_state blit_blend; }; /* Corresponds to the CSO */ diff --git a/src/gallium/drivers/panfrost/pan_job.c b/src/gallium/drivers/panfrost/pan_job.c index 1da37214ab4..365b4ccdb3a 100644 --- a/src/gallium/drivers/panfrost/pan_job.c +++ b/src/gallium/drivers/panfrost/pan_job.c @@ -35,6 +35,7 @@ #include "util/u_pack_color.h" #include "util/rounding.h" #include "pan_util.h" +#include "pan_blending.h" #include "pandecode/decode.h" #include "panfrost-quirks.h" @@ -795,35 +796,19 @@ panfrost_batch_reserve_framebuffer(struct panfrost_batch *batch) static void -panfrost_batch_draw_wallpaper(struct panfrost_batch *batch) +panfrost_load_surface(struct panfrost_batch *batch, struct pipe_surface *surf, unsigned loc) { - /* Color 0 is cleared, no need to draw the wallpaper. - * TODO: MRT wallpapers. - */ - if (batch->clear & PIPE_CLEAR_COLOR0) - return; - - /* Nothing to reload? TODO: MRT wallpapers */ - if (batch->key.cbufs[0] == NULL) - return; - - /* No draw calls, and no clear on the depth/stencil bufs. - * Drawing the wallpaper would be useless. - */ - if (!batch->scoreboard.tiler_dep && - !(batch->clear & PIPE_CLEAR_DEPTHSTENCIL)) + if (!surf) return; - /* Check if the buffer has any content on it worth preserving */ - - struct pipe_surface *surf = batch->key.cbufs[0]; struct panfrost_resource *rsrc = pan_resource(surf->texture); unsigned level = surf->u.tex.level; if (!rsrc->slices[level].initialized) return; - batch->ctx->wallpaper_batch = batch; + if (!rsrc->damage.inverted_len) + return; /* Clamp the rendering area to the damage extent. The * KHR_partial_update() spec states that trying to render outside of @@ -840,73 +825,152 @@ panfrost_batch_draw_wallpaper(struct panfrost_batch *batch) 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.maxx = MAX2(damage.maxx, damage.minx); - damage.maxy = MIN2(batch->maxy, - rsrc->damage.biggest_rect.y + - rsrc->damage.biggest_rect.height); - damage.maxy = MAX2(damage.maxy, damage.miny); - - /* 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; + /* XXX: Native blits on Bifrost */ + if (batch->pool.dev->quirks & IS_BIFROST) { + if (loc != FRAG_RESULT_DATA0) + return; + + /* XXX: why align on *twice* the tile length? */ + 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_box rect; + batch->ctx->wallpaper_batch = batch; + u_box_2d(batch->minx, batch->miny, batch->maxx - batch->minx, + batch->maxy - batch->miny, &rect); + panfrost_blit_wallpaper(batch->ctx, &rect); + batch->ctx->wallpaper_batch = NULL; + return; + } + + enum pipe_format format = rsrc->base.format; + + if (loc == FRAG_RESULT_DEPTH) { + if (!util_format_has_depth(util_format_description(format))) + return; + + format = util_format_get_depth_only(format); + } else if (loc == FRAG_RESULT_STENCIL) { + if (!util_format_has_stencil(util_format_description(format))) + return; + + if (rsrc->separate_stencil) { + rsrc = rsrc->separate_stencil; + format = rsrc->base.format; + } + + format = util_format_stencil_only(format); + } + + enum mali_texture_type type = + panfrost_translate_texture_type(rsrc->base.target); + + unsigned nr_samples = surf->nr_samples; + + if (!nr_samples) + nr_samples = surf->texture->nr_samples; + + struct pan_image img = { + .width0 = rsrc->base.width0, + .height0 = rsrc->base.height0, + .depth0 = rsrc->base.depth0, + .format = format, + .type = type, + .layout = rsrc->layout, + .array_size = rsrc->base.array_size, + .first_level = level, + .last_level = level, + .first_layer = surf->u.tex.first_layer, + .last_layer = surf->u.tex.last_layer, + .nr_samples = nr_samples, + .cubemap_stride = rsrc->cubemap_stride, + .bo = rsrc->bo, + .slices = rsrc->slices + }; - /* Blit the wallpaper in */ - panfrost_blit_wallpaper(batch->ctx, &rects[i]); + mali_ptr blend_shader = 0; + + if (loc >= FRAG_RESULT_DATA0 && !panfrost_can_fixed_blend(rsrc->base.format)) { + struct panfrost_blend_shader *b = + panfrost_get_blend_shader(batch->ctx, &batch->ctx->blit_blend, rsrc->base.format, loc - FRAG_RESULT_DATA0); + + struct panfrost_bo *bo = panfrost_batch_create_bo(batch, b->size, + PAN_BO_EXECUTE, + PAN_BO_ACCESS_PRIVATE | + PAN_BO_ACCESS_READ | + PAN_BO_ACCESS_FRAGMENT); + + memcpy(bo->cpu, b->buffer, b->size); + assert(b->work_count <= 4); + + blend_shader = bo->gpu | b->first_tag; + } + + struct panfrost_transfer transfer = panfrost_pool_alloc(&batch->pool, + 4 * 4 * 6 * rsrc->damage.inverted_len); + + for (unsigned i = 0; i < rsrc->damage.inverted_len; ++i) { + float *o = (float *) (transfer.cpu + (4 * 4 * 6 * i)); + struct pan_rect r = rsrc->damage.inverted_rects[i]; + + float rect[] = { + r.minx, rsrc->base.height0 - r.miny, 0.0, 1.0, + r.maxx, rsrc->base.height0 - r.miny, 0.0, 1.0, + r.minx, rsrc->base.height0 - r.maxy, 0.0, 1.0, + + r.maxx, rsrc->base.height0 - r.miny, 0.0, 1.0, + r.minx, rsrc->base.height0 - r.maxy, 0.0, 1.0, + r.maxx, rsrc->base.height0 - r.maxy, 0.0, 1.0, + }; + + assert(sizeof(rect) == 4 * 4 * 6); + memcpy(o, rect, sizeof(rect)); + } + + panfrost_load_midg(&batch->pool, &batch->scoreboard, + blend_shader, + batch->framebuffer.gpu, transfer.gpu, + rsrc->damage.inverted_len * 6, + &img, loc); + + panfrost_batch_add_bo(batch, batch->pool.dev->blit_shaders.bo, + PAN_BO_ACCESS_SHARED | PAN_BO_ACCESS_READ | PAN_BO_ACCESS_FRAGMENT); +} + +static void +panfrost_batch_draw_wallpaper(struct panfrost_batch *batch) +{ + panfrost_batch_reserve_framebuffer(batch); + + /* Assume combined. If either depth or stencil is written, they will + * both be written so we need to be careful for reloading */ + + unsigned draws = batch->draws; + + if (draws & PIPE_CLEAR_DEPTHSTENCIL) + draws |= PIPE_CLEAR_DEPTHSTENCIL; + + /* Mask of buffers which need reload since they are not cleared and + * they are drawn. (If they are cleared, reload is useless; if they are + * not drawn and also not cleared, we can generally omit the attachment + * at the framebuffer descriptor level */ + + unsigned reload = ~batch->clear & draws; + + for (unsigned i = 0; i < batch->key.nr_cbufs; ++i) { + if (reload & (PIPE_CLEAR_COLOR0 << i)) + panfrost_load_surface(batch, batch->key.cbufs[i], FRAG_RESULT_DATA0 + i); } - batch->ctx->wallpaper_batch = NULL; + + if (reload & PIPE_CLEAR_DEPTH) + panfrost_load_surface(batch, batch->key.zsbuf, FRAG_RESULT_DEPTH); + + if (reload & PIPE_CLEAR_STENCIL) + panfrost_load_surface(batch, batch->key.zsbuf, FRAG_RESULT_STENCIL); } static void @@ -1086,13 +1150,11 @@ panfrost_batch_submit(struct panfrost_batch *batch) * it flushed, the easiest solution is to reload everything. */ for (unsigned i = 0; i < batch->key.nr_cbufs; i++) { - struct panfrost_resource *res; - if (!batch->key.cbufs[i]) continue; - res = pan_resource(batch->key.cbufs[i]->texture); - panfrost_resource_reset_damage(res); + panfrost_resource_set_damage_region(NULL, + batch->key.cbufs[i]->texture, 0, NULL); } out: diff --git a/src/gallium/drivers/panfrost/pan_mfbd.c b/src/gallium/drivers/panfrost/pan_mfbd.c index 247dfd1ae18..4d48f2dcac3 100644 --- a/src/gallium/drivers/panfrost/pan_mfbd.c +++ b/src/gallium/drivers/panfrost/pan_mfbd.c @@ -527,7 +527,7 @@ panfrost_mfbd_fragment(struct panfrost_batch *batch, bool has_draws) for (int cb = 0; cb < rt_descriptors; ++cb) { struct pipe_surface *surf = batch->key.cbufs[cb]; - if (surf) { + if (surf && ((batch->clear | batch->draws) & (PIPE_CLEAR_COLOR0 << cb))) { unsigned nr_samples = surf->nr_samples; if (!nr_samples) @@ -564,7 +564,7 @@ panfrost_mfbd_fragment(struct panfrost_batch *batch, bool has_draws) rts[cb].format.unk1 |= (cb * 0x400); } - if (batch->key.zsbuf) { + if (batch->key.zsbuf && ((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL)) { panfrost_mfbd_set_zsbuf(&fb, &fbx, batch->key.zsbuf); } diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c index b79ebe72850..9440ef7956a 100644 --- a/src/gallium/drivers/panfrost/pan_resource.c +++ b/src/gallium/drivers/panfrost/pan_resource.c @@ -50,17 +50,6 @@ #include "pandecode/decode.h" #include "panfrost-quirks.h" -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; -} - static struct pipe_resource * panfrost_resource_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *templat, @@ -90,7 +79,7 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen, rsc->slices[0].stride = whandle->stride; rsc->slices[0].offset = whandle->offset; rsc->slices[0].initialized = true; - panfrost_resource_reset_damage(rsc); + panfrost_resource_set_damage_region(NULL, &rsc->base, 0, NULL); if (dev->quirks & IS_BIFROST && templat->bind & PIPE_BIND_RENDER_TARGET) { @@ -441,57 +430,29 @@ panfrost_resource_set_damage_region(struct pipe_screen *screen, 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 - */ + if (pres->damage.inverted_rects) + ralloc_free(pres->damage.inverted_rects); + memset(&pres->damage, 0, sizeof(pres->damage)); + + pres->damage.inverted_rects = + pan_subtract_damage(pres, + res->width0, res->height0, + nrects, rects, &pres->damage.inverted_len); + + /* Track the damage extent: the quad including all damage regions. Will + * be used restrict the rendering area */ + 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, @@ -543,7 +504,7 @@ panfrost_resource_create(struct pipe_screen *screen, util_range_init(&so->valid_buffer_range); panfrost_resource_create_bo(dev, so); - panfrost_resource_reset_damage(so); + panfrost_resource_set_damage_region(NULL, &so->base, 0, NULL); if (template->bind & PIPE_BIND_INDEX_BUFFER) so->index_cache = rzalloc(so, struct panfrost_minmax_cache); diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h index baf7604b4f6..8f801473a0b 100644 --- a/src/gallium/drivers/panfrost/pan_resource.h +++ b/src/gallium/drivers/panfrost/pan_resource.h @@ -31,6 +31,7 @@ #include "pan_pool.h" #include "pan_minmax_cache.h" #include "pan_texture.h" +#include "pan_partial_update.h" #include "drm-uapi/drm.h" #include "util/u_range.h" @@ -39,8 +40,9 @@ struct panfrost_resource { struct pipe_resource base; struct { - struct pipe_box biggest_rect; struct pipe_scissor_state extent; + struct pan_rect *inverted_rects; + unsigned inverted_len; } damage; struct panfrost_bo *bo; @@ -118,9 +120,6 @@ panfrost_blit_wallpaper(struct panfrost_context *ctx, struct pipe_box *box); void -panfrost_resource_reset_damage(struct panfrost_resource *pres); - -void panfrost_resource_set_damage_region(struct pipe_screen *screen, struct pipe_resource *res, unsigned int nrects, diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c index b705c362594..b6634955ea9 100644 --- a/src/gallium/drivers/panfrost/pan_screen.c +++ b/src/gallium/drivers/panfrost/pan_screen.c @@ -776,5 +776,8 @@ panfrost_create_screen(int fd, struct renderonly *ro) panfrost_resource_screen_init(&screen->base); + if (!(dev->quirks & IS_BIFROST)) + panfrost_init_blit_shaders(dev); + return &screen->base; } |