v3d: Rework the ordering of how we clear things.
authorEric Anholt <eric@anholt.net>
Mon, 23 Jul 2018 20:56:40 +0000 (13:56 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 26 Jul 2018 18:02:25 +0000 (11:02 -0700)
First, figure out if we can just sneak the clear into the TLB clear, even
if drawing has already happened (since we have job->load and job->clear to
tell us), taking into account GFXH-1461.  For any pieces we can't TLB
clear, fall back to drawing a quad without flushing the scene.

Fixes extra scene flushes in glmark2 due to GFXH-1461.

src/gallium/drivers/v3d/v3dx_draw.c

index e64f2c314e047ebd9c4b7460162d4ea2f20ec2c9..6aa58ceaafe2f8d281b3b834db4dd22b7a991f9e 100644 (file)
@@ -622,50 +622,58 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
                 v3d_flush(pctx);
 }
 
-/* GFXH-1461: If we were to emit a load of just depth or just stencil, then
- * the clear for the other may get lost.  Just fall back to drawing a quad in
- * that case.
+/**
+ * Implements gallium's clear() hook (glClear()) by drawing a pair of triangles.
  */
-static bool
-v3d_gfxh1461_clear_workaround(struct v3d_context *v3d,
-                              unsigned buffers, double depth, unsigned stencil)
+static void
+v3d_draw_clear(struct v3d_context *v3d,
+               unsigned buffers,
+               const union pipe_color_union *color,
+               double depth, unsigned stencil)
 {
-        unsigned zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL;
-        if (!zsclear || zsclear == PIPE_CLEAR_DEPTHSTENCIL)
-                return false;
-
         static const union pipe_color_union dummy_color = {};
 
+        /* The blitter util dereferences the color regardless, even though the
+         * gallium clear API may not pass one in when only Z/S are cleared.
+         */
+        if (!color)
+                color = &dummy_color;
+
         v3d_blitter_save(v3d);
         util_blitter_clear(v3d->blitter,
                            v3d->framebuffer.width,
                            v3d->framebuffer.height,
-                           1,
-                           zsclear,
-                           &dummy_color, depth, stencil);
-        return true;
+                           util_framebuffer_get_num_layers(&v3d->framebuffer),
+                           buffers, color, depth, stencil);
 }
 
-static void
-v3d_clear(struct pipe_context *pctx, unsigned buffers,
-          const union pipe_color_union *color, double depth, unsigned stencil)
+/**
+ * Attempts to perform the GL clear by using the TLB's fast clear at the start
+ * of the frame.
+ */
+static unsigned
+v3d_tlb_clear(struct v3d_job *job, unsigned buffers,
+              const union pipe_color_union *color,
+              double depth, unsigned stencil)
 {
-        struct v3d_context *v3d = v3d_context(pctx);
-        struct v3d_job *job = v3d_get_job_for_fbo(v3d);
-
-        if (v3d_gfxh1461_clear_workaround(v3d, buffers, depth, stencil))
-                buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
+        struct v3d_context *v3d = job->v3d;
 
-        if (!buffers)
-                return;
+        if (job->draw_calls_queued) {
+                /* If anything in the CL has drawn using the buffer, then the
+                 * TLB clear we're trying to add now would happen before that
+                 * drawing.
+                 */
+                buffers &= ~(job->load | job->store);
+        }
 
-        /* We can't flag new buffers for clearing once we've queued draws.  We
-         * could avoid this by using the 3d engine to clear.
+        /* GFXH-1461: If we were to emit a load of just depth or just stencil,
+         * then the clear for the other may get lost.  We need to decide now
+         * if it would be possible to need to emit a load of just one after
+         * we've set up our TLB clears.
          */
-        if (job->draw_calls_queued) {
-                perf_debug("Flushing rendering to process new clear.\n");
-                v3d_job_submit(v3d, job);
-                job = v3d_get_job_for_fbo(v3d);
+        unsigned zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL;
+        if (zsclear && zsclear != PIPE_CLEAR_DEPTHSTENCIL) {
+                buffers &= ~zsclear;
         }
 
         for (int i = 0; i < VC5_MAX_DRAW_BUFFERS; i++) {
@@ -724,7 +732,7 @@ v3d_clear(struct pipe_context *pctx, unsigned buffers,
                 rsc->initialized_buffers |= bit;
         }
 
-        unsigned zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL;
+        zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL;
         if (zsclear) {
                 struct v3d_resource *rsc =
                         v3d_resource(v3d->framebuffer.zsbuf->texture);
@@ -745,6 +753,21 @@ v3d_clear(struct pipe_context *pctx, unsigned buffers,
         job->store |= buffers;
 
         v3d_start_draw(v3d);
+
+        return buffers;
+}
+
+static void
+v3d_clear(struct pipe_context *pctx, unsigned buffers,
+          const union pipe_color_union *color, double depth, unsigned stencil)
+{
+        struct v3d_context *v3d = v3d_context(pctx);
+        struct v3d_job *job = v3d_get_job_for_fbo(v3d);
+
+        buffers &= ~v3d_tlb_clear(job, buffers, color, depth, stencil);
+
+        if (buffers)
+                v3d_draw_clear(v3d, buffers, color, depth, stencil);
 }
 
 static void