Mesa (main): v3d: implement double-buffer mode

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jan 14 11:23:27 UTC 2022


Module: Mesa
Branch: main
Commit: b0f7f1afacdbcd55406e86fee4d75bf8f05d81c2
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=b0f7f1afacdbcd55406e86fee4d75bf8f05d81c2

Author: Iago Toral Quiroga <itoral at igalia.com>
Date:   Fri Jan  7 08:08:00 2022 +0100

v3d: implement double-buffer mode

As with Vulkan, we are not enabling this by default since it may
improve of hurt performance depending on the case. Instead, we
can selectively enable it by using the V3D_DEBUG environment
variable.

Reviewed-by: Juan A. Suarez <jasuarez at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14551>

---

 src/gallium/drivers/v3d/v3d_blit.c    |  8 +++++++-
 src/gallium/drivers/v3d/v3d_context.c |  7 +++++--
 src/gallium/drivers/v3d/v3d_context.h |  4 ++++
 src/gallium/drivers/v3d/v3d_job.c     | 14 +++++++++-----
 src/gallium/drivers/v3d/v3dx_draw.c   |  3 +++
 src/gallium/drivers/v3d/v3dx_rcl.c    | 19 ++++++++++++++++++-
 6 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/src/gallium/drivers/v3d/v3d_blit.c b/src/gallium/drivers/v3d/v3d_blit.c
index b337218cb00..b44b6cd78ec 100644
--- a/src/gallium/drivers/v3d/v3d_blit.c
+++ b/src/gallium/drivers/v3d/v3d_blit.c
@@ -467,8 +467,13 @@ v3d_tlb_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
         if (is_color_blit)
                 surfaces[0] = dst_surf;
 
+        bool double_buffer =
+                 unlikely(V3D_DEBUG & V3D_DEBUG_DOUBLE_BUFFER) && !msaa;
+
         uint32_t tile_width, tile_height, max_bpp;
-        v3d_get_tile_buffer_size(msaa, is_color_blit ? 1 : 0, surfaces, src_surf, &tile_width, &tile_height, &max_bpp);
+        v3d_get_tile_buffer_size(msaa, double_buffer,
+                                 is_color_blit ? 1 : 0, surfaces, src_surf,
+                                 &tile_width, &tile_height, &max_bpp);
 
         int dst_surface_width = u_minify(info->dst.resource->width0,
                                          info->dst.level);
@@ -491,6 +496,7 @@ v3d_tlb_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
                                           is_color_blit ? NULL : dst_surf,
                                           src_surf);
         job->msaa = msaa;
+        job->double_buffer = double_buffer;
         job->tile_width = tile_width;
         job->tile_height = tile_height;
         job->internal_bpp = max_bpp;
diff --git a/src/gallium/drivers/v3d/v3d_context.c b/src/gallium/drivers/v3d/v3d_context.c
index 6ae58d7518d..a35bd3666cd 100644
--- a/src/gallium/drivers/v3d/v3d_context.c
+++ b/src/gallium/drivers/v3d/v3d_context.c
@@ -242,6 +242,7 @@ v3d_create_texture_shader_state_bo(struct v3d_context *v3d,
 
 void
 v3d_get_tile_buffer_size(bool is_msaa,
+                         bool double_buffer,
                          uint32_t nr_cbufs,
                          struct pipe_surface **cbufs,
                          struct pipe_surface *bbuf,
@@ -249,6 +250,8 @@ v3d_get_tile_buffer_size(bool is_msaa,
                          uint32_t *tile_height,
                          uint32_t *max_bpp)
 {
+        assert(!is_msaa || !double_buffer);
+
         uint32_t max_cbuf_idx = 0;
         *max_bpp = 0;
         for (int i = 0; i < nr_cbufs; i++) {
@@ -265,8 +268,8 @@ v3d_get_tile_buffer_size(bool is_msaa,
                 *max_bpp = MAX2(*max_bpp, bsurf->internal_bpp);
         }
 
-        v3d_choose_tile_size(max_cbuf_idx + 1, *max_bpp, is_msaa,
-                             false /* double-buffer */,
+        v3d_choose_tile_size(max_cbuf_idx + 1, *max_bpp,
+                             is_msaa, double_buffer,
                              tile_width, tile_height);
 }
 
diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h
index b283929e38b..2fe0cfb3ddd 100644
--- a/src/gallium/drivers/v3d/v3d_context.h
+++ b/src/gallium/drivers/v3d/v3d_context.h
@@ -430,6 +430,9 @@ struct v3d_job {
         float clear_z;
         uint8_t clear_s;
 
+        /* If TLB double-buffering is enabled for this job */
+        bool double_buffer;
+
         /**
          * Set if some drawing (triangles, blits, or just a glClear()) has
          * been done to the FBO, meaning that we need to
@@ -777,6 +780,7 @@ void v3d_create_texture_shader_state_bo(struct v3d_context *v3d,
                                         struct v3d_sampler_view *so);
 
 void v3d_get_tile_buffer_size(bool is_msaa,
+                              bool double_buffer,
                               uint32_t nr_cbufs,
                               struct pipe_surface **cbufs,
                               struct pipe_surface *bbuf,
diff --git a/src/gallium/drivers/v3d/v3d_job.c b/src/gallium/drivers/v3d/v3d_job.c
index 8e62130f96c..f2260292e75 100644
--- a/src/gallium/drivers/v3d/v3d_job.c
+++ b/src/gallium/drivers/v3d/v3d_job.c
@@ -358,6 +358,9 @@ v3d_get_job(struct v3d_context *v3d,
                 }
         }
 
+       job->double_buffer =
+               unlikely(V3D_DEBUG & V3D_DEBUG_DOUBLE_BUFFER) && !job->msaa;
+
         memcpy(&job->key, &local_key, sizeof(local_key));
         _mesa_hash_table_insert(v3d->jobs, &job->key, job);
 
@@ -375,13 +378,14 @@ v3d_get_job_for_fbo(struct v3d_context *v3d)
         struct pipe_surface *zsbuf = v3d->framebuffer.zsbuf;
         struct v3d_job *job = v3d_get_job(v3d, nr_cbufs, cbufs, zsbuf, NULL);
 
-        if (v3d->framebuffer.samples >= 1)
+        if (v3d->framebuffer.samples >= 1) {
                 job->msaa = true;
+                job->double_buffer = false;
+        }
 
-        v3d_get_tile_buffer_size(job->msaa, job->nr_cbufs,
-                                 job->cbufs, job->bbuf,
-                                 &job->tile_width,
-                                 &job->tile_height,
+        v3d_get_tile_buffer_size(job->msaa, job->double_buffer,
+                                 job->nr_cbufs, job->cbufs, job->bbuf,
+                                 &job->tile_width, &job->tile_height,
                                  &job->internal_bpp);
 
         /* The dirty flags are tracking what's been updated while v3d->job has
diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c
index e9e8f1889af..86330ddf9f8 100644
--- a/src/gallium/drivers/v3d/v3dx_draw.c
+++ b/src/gallium/drivers/v3d/v3dx_draw.c
@@ -94,6 +94,7 @@ v3dX(start_binning)(struct v3d_context *v3d, struct v3d_job *job)
         }
 #endif
 
+        assert(!job->msaa || !job->double_buffer);
 #if V3D_VERSION >= 40
         cl_emit(&job->bcl, TILE_BINNING_MODE_CFG, config) {
                 config.width_in_pixels = job->draw_width;
@@ -102,6 +103,7 @@ v3dX(start_binning)(struct v3d_context *v3d, struct v3d_job *job)
                         MAX2(job->nr_cbufs, 1);
 
                 config.multisample_mode_4x = job->msaa;
+                config.double_buffer_in_non_ms_mode = job->double_buffer;
 
                 config.maximum_bpp_of_all_render_targets = job->internal_bpp;
         }
@@ -128,6 +130,7 @@ v3dX(start_binning)(struct v3d_context *v3d, struct v3d_job *job)
                         MAX2(job->nr_cbufs, 1);
 
                 config.multisample_mode_4x = job->msaa;
+                config.double_buffer_in_non_ms_mode = job->double_buffer;
 
                 config.maximum_bpp_of_all_render_targets = job->internal_bpp;
         }
diff --git a/src/gallium/drivers/v3d/v3dx_rcl.c b/src/gallium/drivers/v3d/v3dx_rcl.c
index 92e7c06cd60..f62e490cee9 100644
--- a/src/gallium/drivers/v3d/v3dx_rcl.c
+++ b/src/gallium/drivers/v3d/v3dx_rcl.c
@@ -561,6 +561,21 @@ supertile_in_job_scissors(struct v3d_job *job,
    return false;
 }
 
+static inline bool
+do_double_initial_tile_clear(const struct v3d_job *job)
+{
+        /* Our rendering code emits an initial clear per layer, unlike the
+         * Vulkan driver, which only executes a single initial clear for all
+         * layers. This is because in GL we don't use the
+         * 'clear_buffer_being_stored' bit when storing tiles, so each layer
+         * needs the iniital clear. This is also why this helper, unlike the
+         * Vulkan version, doesn't check the layer count to decide if double
+         * clear for double buffer mode is required.
+         */
+        return job->double_buffer &&
+               (job->draw_tiles_x > 1 || job->draw_tiles_y > 1);
+}
+
 static void
 emit_render_layer(struct v3d_job *job, uint32_t layer)
 {
@@ -638,7 +653,7 @@ emit_render_layer(struct v3d_job *job, uint32_t layer)
                 cl_emit(&job->rcl, STORE_TILE_BUFFER_GENERAL, store) {
                         store.buffer_to_store = NONE;
                 }
-                if (i == 0) {
+                if (i == 0 || do_double_initial_tile_clear(job)) {
                         cl_emit(&job->rcl, CLEAR_TILE_BUFFERS, clear) {
                                 clear.clear_z_stencil_buffer = true;
                                 clear.clear_all_render_targets = true;
@@ -732,7 +747,9 @@ v3dX(emit_rcl)(struct v3d_job *job)
 
                 config.number_of_render_targets = MAX2(job->nr_cbufs, 1);
 
+                assert(!job->msaa || !job->double_buffer);
                 config.multisample_mode_4x = job->msaa;
+                config.double_buffer_in_non_ms_mode = job->double_buffer;
 
                 config.maximum_bpp_of_all_render_targets = job->internal_bpp;
         }



More information about the mesa-commit mailing list