Mesa (main): v3d: better scissor tracking

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jul 14 12:04:50 UTC 2021


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

Author: Iago Toral Quiroga <itoral at igalia.com>
Date:   Mon Jul  5 14:24:12 2021 +0200

v3d: better scissor tracking

If all drawing is scissored but we have multiple discontinuous
scissor rects, we end up flushing all the tiles in the rect that
covers all scissor rects, which can be a waste, particularly for
large render targets. The obvious case for this are updates to a
mega texture or atlas for example.

This change checks if all rendering happenings against scissor
rects, in which case it keeps track of the rects and uses this to
discard tiles that are not included in any of them.

This optimization needs to be disabled if we have any
non-scissored rendering, including non-scissored clears.

Reviewed-by: Alejandro Piñeiro <apinheiro at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11875>

---

 src/gallium/drivers/v3d/v3d_blit.c    |  2 ++
 src/gallium/drivers/v3d/v3d_context.h | 24 ++++++++++++++++++++-
 src/gallium/drivers/v3d/v3dx_draw.c   |  1 +
 src/gallium/drivers/v3d/v3dx_emit.c   | 20 ++++++++++++++++++
 src/gallium/drivers/v3d/v3dx_rcl.c    | 39 ++++++++++++++++++++++++++++++++---
 5 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/src/gallium/drivers/v3d/v3d_blit.c b/src/gallium/drivers/v3d/v3d_blit.c
index 8ebc42b7d3c..192e8d75bb0 100644
--- a/src/gallium/drivers/v3d/v3d_blit.c
+++ b/src/gallium/drivers/v3d/v3d_blit.c
@@ -521,6 +521,8 @@ v3d_tlb_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
         job->draw_min_y = info->dst.box.y;
         job->draw_max_x = info->dst.box.x + info->dst.box.width;
         job->draw_max_y = info->dst.box.y + info->dst.box.height;
+        job->scissor.disabled = false;
+
         /* The simulator complains if we do a TLB load from a source with a
          * stride that is smaller than the destination's, so we program the
          * 'frame region' to match the smallest dimensions of the two surfaces.
diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h
index cd13c50b177..04ff23e859d 100644
--- a/src/gallium/drivers/v3d/v3d_context.h
+++ b/src/gallium/drivers/v3d/v3d_context.h
@@ -99,6 +99,8 @@ void v3d_job_add_bo(struct v3d_job *job, struct v3d_bo *bo);
 
 #define V3D_MAX_FS_INPUTS 64
 
+#define MAX_JOB_SCISSORS 16
+
 enum v3d_sampler_state_variant {
         V3D_SAMPLER_STATE_BORDER_0,
         V3D_SAMPLER_STATE_F16,
@@ -356,11 +358,31 @@ struct v3d_job {
         uint32_t draw_min_y;
         uint32_t draw_max_x;
         uint32_t draw_max_y;
+
+        /** @} */
+        /** @{
+         * List of scissor rects used for all queued drawing. All scissor
+         * rects will be contained in the draw_{min/max}_{x/y} bounding box.
+         *
+         * This is used as an optimization when all drawing is scissored to
+         * limit tile flushing only to tiles that intersect a scissor rect.
+         * If scissor is used together with non-scissored drawing, then
+         * the optimization is disabled.
+         */
+        struct {
+                bool disabled;
+                uint32_t count;
+                struct {
+                        uint32_t min_x, min_y;
+                        uint32_t max_x, max_y;
+                } rects[MAX_JOB_SCISSORS];
+        } scissor;
+
         /** @} */
         /** @{
          * Width/height of the color framebuffer being rendered to,
          * for V3D_TILE_RENDERING_MODE_CONFIG.
-        */
+         */
         uint32_t draw_width;
         uint32_t draw_height;
         uint32_t num_layers;
diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c
index b9b5254c9f8..0cf4b65d78d 100644
--- a/src/gallium/drivers/v3d/v3dx_draw.c
+++ b/src/gallium/drivers/v3d/v3dx_draw.c
@@ -1613,6 +1613,7 @@ v3d_tlb_clear(struct v3d_job *job, unsigned buffers,
         job->draw_max_y = v3d->framebuffer.height;
         job->clear |= buffers;
         job->store |= buffers;
+        job->scissor.disabled = true;
 
         v3d_start_draw(v3d);
 
diff --git a/src/gallium/drivers/v3d/v3dx_emit.c b/src/gallium/drivers/v3d/v3dx_emit.c
index 04eb27618e7..21c35561b8c 100644
--- a/src/gallium/drivers/v3d/v3dx_emit.c
+++ b/src/gallium/drivers/v3d/v3dx_emit.c
@@ -469,6 +469,26 @@ v3dX(emit_state)(struct pipe_context *pctx)
                 job->draw_min_y = MIN2(job->draw_min_y, miny);
                 job->draw_max_x = MAX2(job->draw_max_x, maxx);
                 job->draw_max_y = MAX2(job->draw_max_y, maxy);
+
+                if (!v3d->rasterizer->base.scissor) {
+                    job->scissor.disabled = true;
+                } else if (!job->scissor.disabled &&
+                           (v3d->dirty & V3D_DIRTY_SCISSOR)) {
+                        if (job->scissor.count < MAX_JOB_SCISSORS) {
+                                job->scissor.rects[job->scissor.count].min_x =
+                                        v3d->scissor.minx;
+                                job->scissor.rects[job->scissor.count].min_y =
+                                        v3d->scissor.miny;
+                                job->scissor.rects[job->scissor.count].max_x =
+                                        v3d->scissor.maxx - 1;
+                                job->scissor.rects[job->scissor.count].max_y =
+                                        v3d->scissor.maxy - 1;
+                                job->scissor.count++;
+                        } else {
+                                job->scissor.disabled = true;
+                                perf_debug("Too many scissor rects.");
+                        }
+                }
         }
 
         if (v3d->dirty & (V3D_DIRTY_RASTERIZER |
diff --git a/src/gallium/drivers/v3d/v3dx_rcl.c b/src/gallium/drivers/v3d/v3dx_rcl.c
index 3acd56e7096..92e7c06cd60 100644
--- a/src/gallium/drivers/v3d/v3dx_rcl.c
+++ b/src/gallium/drivers/v3d/v3dx_rcl.c
@@ -532,6 +532,35 @@ v3d_emit_z_stencil_config(struct v3d_job *job, struct v3d_surface *surf,
 
 #define div_round_up(a, b) (((a) + (b) - 1) / b)
 
+static bool
+supertile_in_job_scissors(struct v3d_job *job,
+                          uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+   if (job->scissor.disabled || job->scissor.count == 0)
+      return true;
+
+   const uint32_t min_x = x * w;
+   const uint32_t min_y = y * h;
+   const uint32_t max_x = min_x + w - 1;
+   const uint32_t max_y = min_y + h - 1;
+
+   for (uint32_t i = 0; i < job->scissor.count; i++) {
+           const uint32_t min_s_x = job->scissor.rects[i].min_x;
+           const uint32_t min_s_y = job->scissor.rects[i].min_y;
+           const uint32_t max_s_x = job->scissor.rects[i].max_x;
+           const uint32_t max_s_y = job->scissor.rects[i].max_y;
+
+           if (max_x < min_s_x || min_x > max_s_x ||
+               max_y < min_s_y || min_y > max_s_y) {
+                   continue;
+           }
+
+           return true;
+   }
+
+   return false;
+}
+
 static void
 emit_render_layer(struct v3d_job *job, uint32_t layer)
 {
@@ -641,9 +670,13 @@ emit_render_layer(struct v3d_job *job, uint32_t layer)
 
         for (int y = min_y_supertile; y <= max_y_supertile; y++) {
                 for (int x = min_x_supertile; x <= max_x_supertile; x++) {
-                        cl_emit(&job->rcl, SUPERTILE_COORDINATES, coords) {
-                                coords.column_number_in_supertiles = x;
-                                coords.row_number_in_supertiles = y;
+                        if (supertile_in_job_scissors(job, x, y,
+                                                      supertile_w_in_pixels,
+                                                      supertile_h_in_pixels)) {
+                                cl_emit(&job->rcl, SUPERTILE_COORDINATES, coords) {
+                                      coords.column_number_in_supertiles = x;
+                                      coords.row_number_in_supertiles = y;
+                                }
                         }
                 }
         }



More information about the mesa-commit mailing list