Mesa (master): broadcom/vc5: Add occlusion query support.

Eric Anholt anholt at kemper.freedesktop.org
Tue Nov 7 20:59:05 UTC 2017


Module: Mesa
Branch: master
Commit: 4f33344e7a6b988fbbc4a0802dacf5cab487e408
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4f33344e7a6b988fbbc4a0802dacf5cab487e408

Author: Eric Anholt <eric at anholt.net>
Date:   Mon Nov  6 15:41:40 2017 -0800

broadcom/vc5: Add occlusion query support.

Fixes all of piglit's OQ tests.

---

 src/broadcom/cle/v3d_packet_v33.xml   |  4 ++
 src/gallium/drivers/vc5/vc5_context.c |  1 +
 src/gallium/drivers/vc5/vc5_context.h | 11 ++++
 src/gallium/drivers/vc5/vc5_draw.c    |  3 ++
 src/gallium/drivers/vc5/vc5_emit.c    |  9 ++++
 src/gallium/drivers/vc5/vc5_job.c     | 20 ++++++--
 src/gallium/drivers/vc5/vc5_query.c   | 97 +++++++++++++++++++++++++++++------
 7 files changed, 125 insertions(+), 20 deletions(-)

diff --git a/src/broadcom/cle/v3d_packet_v33.xml b/src/broadcom/cle/v3d_packet_v33.xml
index 2b0665537e..165e489d4c 100644
--- a/src/broadcom/cle/v3d_packet_v33.xml
+++ b/src/broadcom/cle/v3d_packet_v33.xml
@@ -329,6 +329,10 @@
     <field name="Render Target 0 per colour component write masks" size="4" start="0" type="uint"/>
   </packet>
 
+  <packet code="92" name="Occlusion Query Counter">
+    <field name="address" size="32" start="0" type="address"/>
+  </packet>
+
   <packet code="96" name="Configuration Bits">
     <field name="Direct3D Provoking Vertex" size="1" start="21" type="bool"/>
     <field name="Direct3D 'Point-fill' mode" size="1" start="20" type="bool"/>
diff --git a/src/gallium/drivers/vc5/vc5_context.c b/src/gallium/drivers/vc5/vc5_context.c
index f80020ab31..d27f41bb5f 100644
--- a/src/gallium/drivers/vc5/vc5_context.c
+++ b/src/gallium/drivers/vc5/vc5_context.c
@@ -162,6 +162,7 @@ vc5_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
         V3D_DEBUG |= saved_shaderdb_flag;
 
         vc5->sample_mask = (1 << VC5_MAX_SAMPLES) - 1;
+        vc5->active_queries = true;
 
         return &vc5->base;
 
diff --git a/src/gallium/drivers/vc5/vc5_context.h b/src/gallium/drivers/vc5/vc5_context.h
index 298dfacf87..2fec7a77da 100644
--- a/src/gallium/drivers/vc5/vc5_context.h
+++ b/src/gallium/drivers/vc5/vc5_context.h
@@ -77,6 +77,7 @@ void vc5_job_add_bo(struct vc5_job *job, struct vc5_bo *bo);
 #define VC5_DIRTY_COMPILED_FS   (1 << 25)
 #define VC5_DIRTY_FS_INPUTS     (1 << 26)
 #define VC5_DIRTY_STREAMOUT     (1 << 27)
+#define VC5_DIRTY_OQ            (1 << 28)
 
 #define VC5_MAX_FS_INPUTS 64
 
@@ -262,6 +263,13 @@ struct vc5_job {
          */
         bool needs_flush;
 
+        /**
+         * Set if there is a nonzero address for OCCLUSION_QUERY_COUNTER.  If
+         * so, we need to disable it and flush before ending the CL, to keep
+         * the next tile from starting with it enabled.
+         */
+        bool oq_enabled;
+
         bool uses_early_z;
 
         /**
@@ -353,12 +361,15 @@ struct vc5_context {
          */
         uint8_t blend_dst_alpha_one;
 
+        bool active_queries;
+
         struct pipe_poly_stipple stipple;
         struct pipe_clip_state clip;
         struct pipe_viewport_state viewport;
         struct vc5_constbuf_stateobj constbuf[PIPE_SHADER_TYPES];
         struct vc5_vertexbuf_stateobj vertexbuf;
         struct vc5_streamout_stateobj streamout;
+        struct vc5_bo *current_oq;
         /** @} */
 };
 
diff --git a/src/gallium/drivers/vc5/vc5_draw.c b/src/gallium/drivers/vc5/vc5_draw.c
index edc5285915..8020e26802 100644
--- a/src/gallium/drivers/vc5/vc5_draw.c
+++ b/src/gallium/drivers/vc5/vc5_draw.c
@@ -93,6 +93,9 @@ vc5_start_draw(struct vc5_context *vc5)
         /* There's definitely nothing in the VCD cache we want. */
         cl_emit(&job->bcl, FLUSH_VCD_CACHE, bin);
 
+        /* Disable any leftover OQ state from another job. */
+        cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter);
+
         /* "Binning mode lists must have a Start Tile Binning item (6) after
          *  any prefix state data before the binning list proper starts."
          */
diff --git a/src/gallium/drivers/vc5/vc5_emit.c b/src/gallium/drivers/vc5/vc5_emit.c
index de4737eeec..a4a1af7ddf 100644
--- a/src/gallium/drivers/vc5/vc5_emit.c
+++ b/src/gallium/drivers/vc5/vc5_emit.c
@@ -492,4 +492,13 @@ vc5_emit_state(struct pipe_context *pctx)
                         /* XXX? */
                 }
         }
+
+        if (vc5->dirty & VC5_DIRTY_OQ) {
+                cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter) {
+                        job->oq_enabled = vc5->active_queries && vc5->current_oq;
+                        if (job->oq_enabled) {
+                                counter.address = cl_address(vc5->current_oq, 0);
+                        }
+                }
+        }
 }
diff --git a/src/gallium/drivers/vc5/vc5_job.c b/src/gallium/drivers/vc5/vc5_job.c
index ed1a64be89..46c85e7edf 100644
--- a/src/gallium/drivers/vc5/vc5_job.c
+++ b/src/gallium/drivers/vc5/vc5_job.c
@@ -381,7 +381,17 @@ vc5_job_submit(struct vc5_context *vc5, struct vc5_job *job)
         vc5_emit_rcl(job);
 
         if (cl_offset(&job->bcl) > 0) {
-                vc5_cl_ensure_space_with_branch(&job->bcl, 2);
+                vc5_cl_ensure_space_with_branch(&job->bcl,
+                                                7 +
+                                                cl_packet_length(OCCLUSION_QUERY_COUNTER));
+
+                if (job->oq_enabled) {
+                        /* Disable the OQ at the end of the CL, so that the
+                         * draw calls at the start of the CL don't inherit the
+                         * OQ counter.
+                         */
+                        cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter);
+                }
 
                 /* Increment the semaphore indicating that binning is done and
                  * unblocking the render thread.  Note that this doesn't act
@@ -389,10 +399,12 @@ vc5_job_submit(struct vc5_context *vc5, struct vc5_job *job)
                  */
                 cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr);
 
-                /* The FLUSH caps all of our bin lists with a
-                 * VC5_PACKET_RETURN.
+                /* The FLUSH_ALL emits any unwritten state changes in each
+                 * tile.  We can use this to reset any state that needs to be
+                 * present at the start of the next tile, as we do with
+                 * OCCLUSION_QUERY_COUNTER above.
                  */
-                cl_emit(&job->bcl, FLUSH, flush);
+                cl_emit(&job->bcl, FLUSH_ALL_STATE, flush);
         }
 
         job->submit.bcl_end = job->bcl.bo->offset + cl_offset(&job->bcl);
diff --git a/src/gallium/drivers/vc5/vc5_query.c b/src/gallium/drivers/vc5/vc5_query.c
index c114e76eef..a412b38408 100644
--- a/src/gallium/drivers/vc5/vc5_query.c
+++ b/src/gallium/drivers/vc5/vc5_query.c
@@ -22,60 +22,125 @@
  */
 
 /**
- * Stub support for occlusion queries.
+ * Gallium query object support.
  *
- * Since we expose support for GL 2.0, we have to expose occlusion queries,
- * but the spec allows you to expose 0 query counter bits, so we just return 0
- * as the result of all our queries.
+ * So far we just support occlusion queries.  The HW has native support for
+ * them, with the query result being loaded and stored by the TLB unit.
+ *
+ * From a SW perspective, we have to be careful to make sure that the jobs
+ * that need to be tracking queries are bracketed by the start and end of
+ * counting, even across FBO transitions.
  */
+
 #include "vc5_context.h"
+#include "broadcom/cle/v3d_packet_v33_pack.h"
 
 struct vc5_query
 {
-        uint8_t pad;
+        enum pipe_query_type type;
+        struct vc5_bo *bo;
 };
 
 static struct pipe_query *
-vc5_create_query(struct pipe_context *ctx, unsigned query_type, unsigned index)
+vc5_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
 {
-        struct vc5_query *query = calloc(1, sizeof(*query));
+        struct vc5_query *q = calloc(1, sizeof(*q));
+
+        assert(query_type == PIPE_QUERY_OCCLUSION_COUNTER ||
+               query_type == PIPE_QUERY_OCCLUSION_PREDICATE ||
+               query_type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE);
+
+        q->type = query_type;
 
         /* Note that struct pipe_query isn't actually defined anywhere. */
-        return (struct pipe_query *)query;
+        return (struct pipe_query *)q;
 }
 
 static void
-vc5_destroy_query(struct pipe_context *ctx, struct pipe_query *query)
+vc5_destroy_query(struct pipe_context *pctx, struct pipe_query *query)
 {
-        free(query);
+        struct vc5_query *q = (struct vc5_query *)query;
+
+        vc5_bo_unreference(&q->bo);
+        free(q);
 }
 
 static boolean
-vc5_begin_query(struct pipe_context *ctx, struct pipe_query *query)
+vc5_begin_query(struct pipe_context *pctx, struct pipe_query *query)
 {
+        struct vc5_context *vc5 = vc5_context(pctx);
+        struct vc5_query *q = (struct vc5_query *)query;
+
+        q->bo = vc5_bo_alloc(vc5->screen, 4096, "query");
+
+        uint32_t *map = vc5_bo_map(q->bo);
+        *map = 0;
+
+        vc5->current_oq = q->bo;
+        vc5->dirty |= VC5_DIRTY_OQ;
+
         return true;
 }
 
 static bool
-vc5_end_query(struct pipe_context *ctx, struct pipe_query *query)
+vc5_end_query(struct pipe_context *pctx, struct pipe_query *query)
 {
+        struct vc5_context *vc5 = vc5_context(pctx);
+
+        vc5->current_oq = NULL;
+        vc5->dirty |= VC5_DIRTY_OQ;
+
         return true;
 }
 
 static boolean
-vc5_get_query_result(struct pipe_context *ctx, struct pipe_query *query,
+vc5_get_query_result(struct pipe_context *pctx, struct pipe_query *query,
                      boolean wait, union pipe_query_result *vresult)
 {
-        uint64_t *result = &vresult->u64;
+        struct vc5_query *q = (struct vc5_query *)query;
+        uint32_t result = 0;
+
+        if (q->bo) {
+                /* XXX: Only flush the jobs using this BO. */
+                vc5_flush(pctx);
 
-        *result = 0;
+                if (wait) {
+                        if (!vc5_bo_wait(q->bo, 0, "query"))
+                                return false;
+                } else {
+                        if (!vc5_bo_wait(q->bo, ~0ull, "query"))
+                                return false;
+                }
+
+                /* XXX: Sum up per-core values. */
+                uint32_t *map = vc5_bo_map(q->bo);
+                result = *map;
+
+                vc5_bo_unreference(&q->bo);
+        }
+
+        switch (q->type) {
+        case PIPE_QUERY_OCCLUSION_COUNTER:
+                vresult->u64 = result;
+                break;
+        case PIPE_QUERY_OCCLUSION_PREDICATE:
+        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
+                vresult->b = result != 0;
+                break;
+        default:
+                unreachable("unsupported query type");
+        }
 
         return true;
 }
 
 static void
-vc5_set_active_query_state(struct pipe_context *pipe, boolean enable)
+vc5_set_active_query_state(struct pipe_context *pctx, boolean enable)
 {
+        struct vc5_context *vc5 = vc5_context(pctx);
+
+        vc5->active_queries = enable;
+        vc5->dirty |= VC5_DIRTY_OQ;
 }
 
 void




More information about the mesa-commit mailing list