broadcom/vc5: Add partial transform feedback query support.
authorEric Anholt <eric@anholt.net>
Tue, 7 Nov 2017 00:59:05 +0000 (16:59 -0800)
committerEric Anholt <eric@anholt.net>
Tue, 7 Nov 2017 20:57:43 +0000 (12:57 -0800)
We have to compute the queries in software, so we're counting the
primitives by hand.  We still need to make sure to not increment the
PRIMITIVES_EMITTED if we overflowed, but leave that for later.

src/gallium/drivers/vc5/vc5_context.h
src/gallium/drivers/vc5/vc5_draw.c
src/gallium/drivers/vc5/vc5_query.c

index 2fec7a7..4917153 100644 (file)
@@ -363,6 +363,9 @@ struct vc5_context {
 
         bool active_queries;
 
+        uint32_t tf_prims_generated;
+        uint32_t prims_generated;
+
         struct pipe_poly_stipple stipple;
         struct pipe_clip_state clip;
         struct pipe_viewport_state viewport;
index 8020e26..55a2e49 100644 (file)
@@ -270,6 +270,25 @@ vc5_emit_gl_shader_state(struct vc5_context *vc5,
         job->shader_rec_count++;
 }
 
+/**
+ * Computes the various transform feedback statistics, since they can't be
+ * recorded by CL packets.
+ */
+static void
+vc5_tf_statistics_record(struct vc5_context *vc5,
+                         const struct pipe_draw_info *info,
+                         bool prim_tf)
+{
+        uint32_t prims = u_prims_for_vertices(info->mode, info->count);
+
+        vc5->prims_generated += prims;
+
+        if (prim_tf) {
+                /* XXX: Only count if we didn't overflow. */
+                vc5->tf_prims_generated += prims;
+        }
+}
+
 static void
 vc5_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 {
@@ -363,6 +382,8 @@ vc5_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
         if (vc5->prog.bind_vs->num_tf_outputs)
                 prim_tf_enable = (V3D_PRIM_POINTS_TF - V3D_PRIM_POINTS);
 
+        vc5_tf_statistics_record(vc5, info, prim_tf_enable);
+
         /* Note that the primitive type fields match with OpenGL/gallium
          * definitions, up to but not including QUADS.
          */
index a412b38..5ec9be2 100644 (file)
 /**
  * Gallium query object support.
  *
- * 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.
+ * The HW has native support for occlusion queries, 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.
  *
- * 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.
+ * For the transform feedback PRIMITIVES_GENERATED/WRITTEN queries, we have to
+ * do the calculations in software at draw time.
  */
 
 #include "vc5_context.h"
@@ -39,6 +40,8 @@ struct vc5_query
 {
         enum pipe_query_type type;
         struct vc5_bo *bo;
+
+        uint32_t start, end;
 };
 
 static struct pipe_query *
@@ -46,10 +49,6 @@ vc5_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
 {
         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. */
@@ -71,13 +70,22 @@ 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;
+        switch (q->type) {
+        case PIPE_QUERY_PRIMITIVES_GENERATED:
+                q->start = vc5->prims_generated;
+                break;
+        case PIPE_QUERY_PRIMITIVES_EMITTED:
+                q->start = vc5->tf_prims_generated;
+                break;
+        default:
+                q->bo = vc5_bo_alloc(vc5->screen, 4096, "query");
 
-        vc5->current_oq = q->bo;
-        vc5->dirty |= VC5_DIRTY_OQ;
+                uint32_t *map = vc5_bo_map(q->bo);
+                *map = 0;
+                vc5->current_oq = q->bo;
+                vc5->dirty |= VC5_DIRTY_OQ;
+                break;
+        }
 
         return true;
 }
@@ -86,9 +94,20 @@ static bool
 vc5_end_query(struct pipe_context *pctx, struct pipe_query *query)
 {
         struct vc5_context *vc5 = vc5_context(pctx);
+        struct vc5_query *q = (struct vc5_query *)query;
 
-        vc5->current_oq = NULL;
-        vc5->dirty |= VC5_DIRTY_OQ;
+        switch (q->type) {
+        case PIPE_QUERY_PRIMITIVES_GENERATED:
+                q->end = vc5->prims_generated;
+                break;
+        case PIPE_QUERY_PRIMITIVES_EMITTED:
+                q->end = vc5->tf_prims_generated;
+                break;
+        default:
+                vc5->current_oq = NULL;
+                vc5->dirty |= VC5_DIRTY_OQ;
+                break;
+        }
 
         return true;
 }
@@ -127,6 +146,10 @@ vc5_get_query_result(struct pipe_context *pctx, struct pipe_query *query,
         case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
                 vresult->b = result != 0;
                 break;
+        case PIPE_QUERY_PRIMITIVES_GENERATED:
+        case PIPE_QUERY_PRIMITIVES_EMITTED:
+                vresult->u64 = q->end - q->start;
+                break;
         default:
                 unreachable("unsupported query type");
         }