panfrost: Implement opportunistic AFBC
authorAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Mon, 15 Jul 2019 21:15:24 +0000 (14:15 -0700)
committerAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Tue, 16 Jul 2019 14:21:08 +0000 (07:21 -0700)
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 <alyssa.rosenzweig@collabora.com>
src/gallium/drivers/panfrost/pan_context.c
src/gallium/drivers/panfrost/pan_resource.c
src/gallium/drivers/panfrost/pan_resource.h
src/gallium/drivers/panfrost/pan_screen.c
src/gallium/drivers/panfrost/pan_util.h

index aed49311c02067b8faa484c44623fbd0b6a6adca..d720f086361e2e9d884e05338ea9c7e97119d267 100644 (file)
@@ -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
index 7b46acaf58b590c1fe2d215f3111fe2f210aadf1..d3cbfe70c77a26cbbb149b2f9d65bba4207928c6 100644 (file)
@@ -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)
index 3814c2b27eb46b27d0c671a2b1ef0df641fa47c5..e51ba8959c3af485abccb40231eb1c72f7652d54 100644 (file)
@@ -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
index 43a26856f9b1ec373013cde2eef82501944a2887..ffd2de4734e1bb59e777be9c16b7669f8d6a7ad6 100644 (file)
@@ -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
 };
 
index 3ae702186065700573e602a3a6ee3e0f10810951..24c71d59ba04e38f47e5f9aeede34c0cbf9248a6 100644 (file)
@@ -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;