[Mesa-dev] [PATCH] panfrost: Track buffer initialization

Alyssa Rosenzweig alyssa.rosenzweig at collabora.com
Fri Jun 21 12:28:21 UTC 2019


We want to know if a given slice of a buffer is initialized at a
particular point in the execution of the program. This is accomplished
easily enough -- start out uninitialized and upon an operation writing
to the buffer, mark it initialized.

The motivation is to optimize away expensive operations (like wallpaper
blits) when reading from an uninitialized buffer; since it's
uninitialized, the results of these operations are undefined, and it's
legal to take the fast path ^_^

Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig at collabora.com>
---
 src/gallium/drivers/panfrost/pan_context.c  |  9 +++++++++
 src/gallium/drivers/panfrost/pan_fragment.c | 21 +++++++++++++++++++++
 src/gallium/drivers/panfrost/pan_resource.c | 12 ++++++++++--
 src/gallium/drivers/panfrost/pan_resource.h |  3 +++
 4 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c
index d8c5510a31e..6257ffe2ac4 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -1397,6 +1397,15 @@ panfrost_draw_wallpaper(struct pipe_context *pipe)
 	if (ctx->pipe_framebuffer.cbufs[0] == NULL)
 		return;
 
+        /* Check if the buffer has any content on it worth preserving */
+
+        struct pipe_surface *surf = ctx->pipe_framebuffer.cbufs[0];
+        struct panfrost_resource *rsrc = pan_resource(surf->texture);
+        unsigned level = surf->u.tex.level;
+
+        if (!rsrc->bo->slices[level].initialized)
+                return;
+
         /* Save the batch */
         struct panfrost_job *batch = panfrost_get_job_for_fbo(ctx);
 
diff --git a/src/gallium/drivers/panfrost/pan_fragment.c b/src/gallium/drivers/panfrost/pan_fragment.c
index 70358fec3f3..d6b8afdc6b9 100644
--- a/src/gallium/drivers/panfrost/pan_fragment.c
+++ b/src/gallium/drivers/panfrost/pan_fragment.c
@@ -28,6 +28,17 @@
 
 #include "util/u_format.h"
 
+/* Mark a surface as written */
+
+static void
+panfrost_initialize_surface(struct pipe_surface *surf)
+{
+        unsigned level = surf->u.tex.level;
+        struct panfrost_resource *rsrc = pan_resource(surf->texture);
+
+        rsrc->bo->slices[level].initialized = true;
+}
+
 /* Generate a fragment job. This should be called once per frame. (According to
  * presentations, this is supposed to correspond to eglSwapBuffers) */
 
@@ -38,6 +49,16 @@ panfrost_fragment_job(struct panfrost_context *ctx, bool has_draws)
                 panfrost_sfbd_fragment(ctx, has_draws) :
                 panfrost_mfbd_fragment(ctx, has_draws);
 
+        /* Mark the affected buffers as initialized, since we're writing to it */
+        struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
+
+        for (unsigned i = 0; i < fb->nr_cbufs; ++i) {
+                panfrost_initialize_surface(fb->cbufs[i]);
+        }
+
+        if (fb->zsbuf)
+                panfrost_initialize_surface(fb->zsbuf);
+
         struct mali_job_descriptor_header header = {
                 .job_type = JOB_TYPE_FRAGMENT,
                 .job_index = 1,
diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c
index a99840e4a52..1a4ce8ef297 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -71,6 +71,7 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
 
 	rsc->bo = screen->driver->import_bo(screen, whandle);
 	rsc->bo->slices[0].stride = whandle->stride;
+        rsc->bo->slices[0].initialized = true;
 
 	if (screen->ro) {
 		rsc->scanout =
@@ -509,7 +510,7 @@ panfrost_transfer_map(struct pipe_context *pctx,
                 transfer->map = rzalloc_size(transfer, transfer->base.layer_stride * box->depth);
                 assert(box->depth == 1);
 
-                if (usage & PIPE_TRANSFER_READ) {
+                if ((usage & PIPE_TRANSFER_READ) && bo->slices[level].initialized) {
                         if (bo->layout == PAN_AFBC) {
                                 DBG("Unimplemented: reads from AFBC");
                         } else if (bo->layout == PAN_TILED) {
@@ -528,6 +529,12 @@ panfrost_transfer_map(struct pipe_context *pctx,
                 transfer->base.stride = bo->slices[level].stride;
                 transfer->base.layer_stride = bo->cubemap_stride;
 
+                /* By mapping direct-write, we're implicitly already
+                 * initialized (maybe), so be conservative */
+
+                if ((usage & PIPE_TRANSFER_WRITE) && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
+                        bo->slices[level].initialized = true;
+
                 return bo->cpu
                         + bo->slices[level].offset
                         + transfer->base.box.z * bo->cubemap_stride
@@ -549,11 +556,12 @@ panfrost_transfer_unmap(struct pipe_context *pctx,
                 struct panfrost_bo *bo = prsrc->bo;
 
                 if (transfer->usage & PIPE_TRANSFER_WRITE) {
+                        unsigned level = transfer->level;
+                        bo->slices[level].initialized = true;
 
                         if (bo->layout == PAN_AFBC) {
                                 DBG("Unimplemented: writes to AFBC\n");
                         } else if (bo->layout == PAN_TILED) {
-                                unsigned level = transfer->level;
                                 assert(transfer->box.depth == 1);
 
                                 panfrost_store_tiled_image(
diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h
index 114e283889b..632250fa2aa 100644
--- a/src/gallium/drivers/panfrost/pan_resource.h
+++ b/src/gallium/drivers/panfrost/pan_resource.h
@@ -43,6 +43,9 @@ enum panfrost_memory_layout {
 struct panfrost_slice {
         unsigned offset;
         unsigned stride;
+
+        /* Has anything been written to this slice? */
+        bool initialized;
 };
 
 struct panfrost_bo {
-- 
2.20.1



More information about the mesa-dev mailing list