From: Alyssa Rosenzweig Date: Mon, 15 Jul 2019 21:15:24 +0000 (-0700) Subject: panfrost: Implement opportunistic AFBC X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5ad00fb3ed913599fecbae785284fc883242aaf0;p=mesa.git panfrost: Implement opportunistic AFBC Rather than hardcoding a BO layout at creation-time, we implement the ability to hint layouts at various points in a BO's lifetime, potentially reallocating and switching layouts if it's heuristically deemed useful to do so. In this patch, we add a simple hinting implementation, opportunistically compressing FBOs. Support is hidden behind PAN_MESA_DEBUG=afbc as the implementation is incomplete (software access to AFBC is unimplemented at the moment) and therefore would regress significantly. Signed-off-by: Alyssa Rosenzweig --- diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index aed49311c02..d720f086361 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -2334,6 +2334,32 @@ panfrost_sampler_view_destroy( ralloc_free(view); } +/* Hints that a framebuffer should use AFBC where possible */ + +static void +panfrost_hint_afbc( + struct panfrost_screen *screen, + const struct pipe_framebuffer_state *fb) +{ + /* AFBC implemenation incomplete; hide it */ + if (!(pan_debug & PAN_DBG_AFBC)) return; + + /* Hint AFBC to the resources bound to each color buffer */ + + for (unsigned i = 0; i < fb->nr_cbufs; ++i) { + struct pipe_surface *surf = fb->cbufs[i]; + struct panfrost_resource *rsrc = pan_resource(surf->texture); + panfrost_resource_hint_layout(screen, rsrc, PAN_AFBC, 1); + } + + /* Also hint it to the depth buffer */ + + if (fb->zsbuf) { + struct panfrost_resource *rsrc = pan_resource(fb->zsbuf->texture); + panfrost_resource_hint_layout(screen, rsrc, PAN_AFBC, 1); + } +} + static void panfrost_set_framebuffer_state(struct pipe_context *pctx, const struct pipe_framebuffer_state *fb) @@ -2379,6 +2405,11 @@ panfrost_set_framebuffer_state(struct pipe_context *pctx, } if (needs_reattach) { + /* Given that we're rendering, we'd love to have compression */ + struct panfrost_screen *screen = pan_screen(ctx->base.screen); + + panfrost_hint_afbc(screen, &ctx->pipe_framebuffer); + if (ctx->require_sfbd) ctx->vt_framebuffer_sfbd = panfrost_emit_sfbd(ctx, ~0); else diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c index 7b46acaf58b..d3cbfe70c77 100644 --- a/src/gallium/drivers/panfrost/pan_resource.c +++ b/src/gallium/drivers/panfrost/pan_resource.c @@ -712,6 +712,66 @@ panfrost_get_texture_address( return rsrc->bo->gpu + level_offset + face_offset; } +/* Given a resource that has already been allocated, hint that it should use a + * given layout. These are suggestions, not commands; it is perfectly legal to + * stub out this function, but there will be performance implications. */ + +void +panfrost_resource_hint_layout( + struct panfrost_screen *screen, + struct panfrost_resource *rsrc, + enum panfrost_memory_layout layout, + signed weight) +{ + /* Nothing to do, although a sophisticated implementation might store + * the hint */ + + if (rsrc->layout == layout) + return; + + /* We don't use the weight yet, but we should check that it's positive + * (semantically meaning that we should choose the given `layout`) */ + + if (weight <= 0) + return; + + /* Check if the preferred layout is legal for this buffer */ + + if (layout == PAN_AFBC) { + bool can_afbc = panfrost_format_supports_afbc(rsrc->base.format); + bool is_scanout = rsrc->base.bind & + (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED); + + if (!can_afbc || is_scanout) + return; + } + + /* Simple heuristic so far: if the resource is uninitialized, switch to + * the hinted layout. If it is initialized, keep the original layout. + * This misses some cases where it would be beneficial to switch and + * blit. */ + + bool is_initialized = false; + + for (unsigned i = 0; i < MAX_MIP_LEVELS; ++i) + is_initialized |= rsrc->slices[i].initialized; + + if (is_initialized) + return; + + /* We're uninitialized, so do a layout switch. Reinitialize slices. */ + + size_t new_size; + rsrc->layout = layout; + panfrost_setup_slices(rsrc, &new_size); + + /* If we grew in size, reallocate the BO */ + if (new_size > rsrc->bo->size) { + panfrost_drm_release_bo(screen, rsrc->bo, true); + rsrc->bo = panfrost_drm_create_bo(screen, new_size, PAN_ALLOCATE_DELAY_MMAP); + } +} + static void panfrost_resource_set_stencil(struct pipe_resource *prsrc, struct pipe_resource *stencil) diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h index 3814c2b27eb..e51ba8959c3 100644 --- a/src/gallium/drivers/panfrost/pan_resource.h +++ b/src/gallium/drivers/panfrost/pan_resource.h @@ -112,6 +112,13 @@ void panfrost_resource_screen_init(struct panfrost_screen *screen); void panfrost_resource_context_init(struct pipe_context *pctx); +void +panfrost_resource_hint_layout( + struct panfrost_screen *screen, + struct panfrost_resource *rsrc, + enum panfrost_memory_layout layout, + signed weight); + /* AFBC */ bool diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c index 43a26856f9b..ffd2de4734e 100644 --- a/src/gallium/drivers/panfrost/pan_screen.c +++ b/src/gallium/drivers/panfrost/pan_screen.c @@ -54,7 +54,7 @@ static const struct debug_named_value debug_options[] = { {"msgs", PAN_DBG_MSGS, "Print debug messages"}, {"trace", PAN_DBG_TRACE, "Trace the command stream"}, {"deqp", PAN_DBG_DEQP, "Hacks for dEQP"}, - /* ^^ If Rob can do it, so can I */ + {"afbc", PAN_DBG_AFBC, "Enable non-conformant AFBC impl"}, DEBUG_NAMED_VALUE_END }; diff --git a/src/gallium/drivers/panfrost/pan_util.h b/src/gallium/drivers/panfrost/pan_util.h index 3ae70218606..24c71d59ba0 100644 --- a/src/gallium/drivers/panfrost/pan_util.h +++ b/src/gallium/drivers/panfrost/pan_util.h @@ -31,6 +31,7 @@ #define PAN_DBG_MSGS 0x0001 #define PAN_DBG_TRACE 0x0002 #define PAN_DBG_DEQP 0x0004 +#define PAN_DBG_AFBC 0x0008 extern int pan_debug;