[Mesa-dev] [PATCH 6/7] i965: Properly reset SVBI counters on ResumeTransformFeedback().

Kenneth Graunke kenneth at whitecape.org
Fri Feb 17 09:56:20 UTC 2017


This fixes Piglit's ARB_transform_feedback2/change-objects-while-paused
GLES 3.0 test.  When resuming the transform feedback object, we need to
reset the SVBI counters so we continue writing at the correct point in
the buffer.

Instead of SO_WRITE_OFFSET counters (with a DWord offset), we have the
Streamed Vertex Buffer Index (SVBI) counters, which contain a count of
vertices emitted.

Unfortunately, there's no straightforward way to store the current SVBI
counter values to a buffer.  They're not available in a register.  You
can use a bit in the 3DSTATE_SVB_INDEX packet to copy them to another
internal counter which 3DPRIMITIVE can use...but there's no good way to
extract that either.

So, once again, we use SO_NUM_PRIMS_WRITTEN to calculate the vertex
numbers.  Thankfully, we can reuse most of the existing Gen7+ code.

Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
---
 src/mesa/drivers/dri/i965/brw_context.c |   2 +
 src/mesa/drivers/dri/i965/brw_context.h |   6 ++
 src/mesa/drivers/dri/i965/gen6_sol.c    | 116 +++++++++++++++++++++++++++-----
 3 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index 7240b1f4455..977c59c1c3e 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -481,6 +481,8 @@ brw_init_driver_functions(struct brw_context *brw,
    } else {
       functions->BeginTransformFeedback = brw_begin_transform_feedback;
       functions->EndTransformFeedback = brw_end_transform_feedback;
+      functions->PauseTransformFeedback = brw_pause_transform_feedback;
+      functions->ResumeTransformFeedback = brw_resume_transform_feedback;
    }
 
    if (brw->gen >= 6)
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index 25c90645cea..df406c0d772 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -1471,6 +1471,12 @@ void
 brw_end_transform_feedback(struct gl_context *ctx,
                            struct gl_transform_feedback_object *obj);
 void
+brw_pause_transform_feedback(struct gl_context *ctx,
+                             struct gl_transform_feedback_object *obj);
+void
+brw_resume_transform_feedback(struct gl_context *ctx,
+                              struct gl_transform_feedback_object *obj);
+void
 brw_save_primitives_written_counters(struct brw_context *brw,
                                      struct brw_transform_feedback_object *obj);
 void
diff --git a/src/mesa/drivers/dri/i965/gen6_sol.c b/src/mesa/drivers/dri/i965/gen6_sol.c
index f1cc2d59fd4..702cb2830f0 100644
--- a/src/mesa/drivers/dri/i965/gen6_sol.c
+++ b/src/mesa/drivers/dri/i965/gen6_sol.c
@@ -314,18 +314,12 @@ brw_save_primitives_written_counters(struct brw_context *brw,
    obj->prim_count_buffer_index += streams;
 }
 
-/**
- * Compute the number of vertices written by this transform feedback operation.
- */
-void
-brw_compute_xfb_vertices_written(struct brw_context *brw,
-                                 struct brw_transform_feedback_object *obj)
+static void
+compute_vertices_written_so_far(struct brw_context *brw,
+                                struct brw_transform_feedback_object *obj,
+                                uint64_t *vertices_written)
 {
    const struct gl_context *ctx = &brw->ctx;
-
-   if (obj->vertices_written_valid || !obj->base.EndedAnytime)
-      return;
-
    unsigned vertices_per_prim = 0;
 
    switch (obj->primitive_mode) {
@@ -346,8 +340,22 @@ brw_compute_xfb_vertices_written(struct brw_context *brw,
    tally_prims_generated(brw, obj);
 
    for (int i = 0; i < ctx->Const.MaxVertexStreams; i++) {
-      obj->vertices_written[i] = vertices_per_prim * obj->prims_generated[i];
+      vertices_written[i] = vertices_per_prim * obj->prims_generated[i];
    }
+}
+
+/**
+ * Compute the number of vertices written by this transform feedback operation.
+ */
+void
+brw_compute_xfb_vertices_written(struct brw_context *brw,
+                                 struct brw_transform_feedback_object *obj)
+{
+   if (obj->vertices_written_valid || !obj->base.EndedAnytime)
+      return;
+
+   compute_vertices_written_so_far(brw, obj, obj->vertices_written);
+
    obj->vertices_written_valid = true;
 }
 
@@ -423,18 +431,92 @@ brw_begin_transform_feedback(struct gl_context *ctx, GLenum mode,
       OUT_BATCH(0xffffffff);
       ADVANCE_BATCH();
    }
+
+   /* We're about to lose the information needed to compute the number of
+    * vertices written during the last Begin/EndTransformFeedback section,
+    * so we can't delay it any further.
+    */
+   brw_compute_xfb_vertices_written(brw, brw_obj);
+
+   /* No primitives have been generated yet. */
+   for (int i = 0; i < BRW_MAX_XFB_STREAMS; i++) {
+      brw_obj->prims_generated[i] = 0;
+   }
+
+   /* Store the starting value of the SO_NUM_PRIMS_WRITTEN counters. */
+   brw_save_primitives_written_counters(brw, brw_obj);
+
+   brw_obj->primitive_mode = mode;
 }
 
 void
 brw_end_transform_feedback(struct gl_context *ctx,
                            struct gl_transform_feedback_object *obj)
 {
-   /* After EndTransformFeedback, it's likely that the client program will try
-    * to draw using the contents of the transform feedback buffer as vertex
-    * input.  In order for this to work, we need to flush the data through at
-    * least the GS stage of the pipeline, and flush out the render cache.  For
-    * simplicity, just do a full flush.
+   struct brw_context *brw = brw_context(ctx);
+   struct brw_transform_feedback_object *brw_obj =
+      (struct brw_transform_feedback_object *) obj;
+
+   /* Store the ending value of the SO_NUM_PRIMS_WRITTEN counters. */
+   if (!obj->Paused)
+      brw_save_primitives_written_counters(brw, brw_obj);
+
+   /* EndTransformFeedback() means that we need to update the number of
+    * vertices written.  Since it's only necessary if DrawTransformFeedback()
+    * is called and it means mapping a buffer object, we delay computing it
+    * until it's absolutely necessary to try and avoid stalls.
+    */
+   brw_obj->vertices_written_valid = false;
+}
+
+void
+brw_pause_transform_feedback(struct gl_context *ctx,
+                             struct gl_transform_feedback_object *obj)
+{
+   struct brw_context *brw = brw_context(ctx);
+   struct brw_transform_feedback_object *brw_obj =
+      (struct brw_transform_feedback_object *) obj;
+
+   /* Store the temporary ending value of the SO_NUM_PRIMS_WRITTEN counters.
+    * While this operation is paused, other transform feedback actions may
+    * occur, which will contribute to the counters.  We need to exclude that
+    * from our counts.
     */
+   brw_save_primitives_written_counters(brw, brw_obj);
+}
+
+void
+brw_resume_transform_feedback(struct gl_context *ctx,
+                              struct gl_transform_feedback_object *obj)
+{
    struct brw_context *brw = brw_context(ctx);
-   brw_emit_mi_flush(brw);
+   struct brw_transform_feedback_object *brw_obj =
+      (struct brw_transform_feedback_object *) obj;
+
+   /* Reload SVBI 0 with the count of vertices written so far. */
+   uint64_t svbi;
+   compute_vertices_written_so_far(brw, brw_obj, &svbi);
+
+   BEGIN_BATCH(4);
+   OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
+   OUT_BATCH(0); /* SVBI 0 */
+   OUT_BATCH((uint32_t) svbi); /* starting index */
+   OUT_BATCH(brw_obj->max_index);
+   ADVANCE_BATCH();
+
+   /* Initialize the rest of the unused streams to sane values.  Otherwise,
+    * they may indicate that there is no room to write data and prevent
+    * anything from happening at all.
+    */
+   for (int i = 1; i < 4; i++) {
+      BEGIN_BATCH(4);
+      OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
+      OUT_BATCH(i << SVB_INDEX_SHIFT);
+      OUT_BATCH(0); /* starting index */
+      OUT_BATCH(0xffffffff);
+      ADVANCE_BATCH();
+   }
+
+   /* Store the new starting value of the SO_NUM_PRIMS_WRITTEN counters. */
+   brw_save_primitives_written_counters(brw, brw_obj);
 }
-- 
2.11.1



More information about the mesa-dev mailing list