[Mesa-dev] [PATCH v2 5/8] mesa: Add a new GetTransformFeedbackVertexCount() driver hook.

Kenneth Graunke kenneth at whitecape.org
Sat Oct 26 07:35:46 CEST 2013

DrawTransformFeedback() needs to obtain the number of vertices written
to a particular stream during the last Begin/EndTransformFeedback block.
The new driver hook returns exactly that information.

Gallium drivers already implement this by passing the transform feedback
object to the drawing function, counting the number of vertices written
on the GPU, and using draw indirect.  This is efficient, but doesn't
always work:

If vertex data comes from user arrays, then the VBO module needs to
know how many vertices to upload, so we need to synchronously count.
Gallium drivers are currently broken in this case.

It also doesn't work if primitive restart is done in software.  For
normal drawing, vbo_draw_arrays() performs software primitive restart,
splitting the draw call in two.  vbo_draw_transform_feedback() currently
doesn't because it has no idea how many vertices need to be drawn.

The new driver hook gives it that information, allowing us to reuse
the existing vbo_draw_arrays() code to do everything right.

On Intel hardware (at least Ivybridge), using the draw indirect approach
is difficult since the hardware counts primitives, rather than vertices,
which requires doing some simple math.  So we always use this hook.

Gallium drivers will likely want to use this hook in some cases, but
want to use the existing draw indirect approach where possible.  Hence,
I've added a flag to allow drivers to opt-in to this call.

v2: Make it possible to implement this hook but only use this path
    when necessary (suggested by Marek).

Cc: Marek Olšák <maraeo at gmail.com>
Cc: Eric Anholt <eric at anholt.net>
Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
 src/mesa/drivers/dri/i965/brw_context.c |  2 ++
 src/mesa/main/dd.h                      |  8 ++++++++
 src/mesa/main/mtypes.h                  |  6 ++++++
 src/mesa/vbo/vbo_exec_array.c           | 10 ++++++++++
 4 files changed, 26 insertions(+)


Does this look like what you wanted?  I feel a bit silly adding all of this
seeing as the later conditions are totally untested - i965 sets the "always
use this hook" flag, so it short-circuits them, and Gallium drivers don't
yet implement the hook, so they don't hit it either. :)

But I think this is probably roughly what you're going to want...

Eric, does this look reasonable?

Thanks for everything!

diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index 90d9be4..623273c 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -329,6 +329,8 @@ brw_initialize_context_constants(struct brw_context *brw)
    ctx->Const.MaxTransformFeedbackSeparateComponents =
+   ctx->Const.AlwaysUseGetTransformFeedbackVertexCount = true;
    if (brw->gen == 6) {
       ctx->Const.MaxSamples = 4;
       ctx->Const.MaxColorTextureSamples = 4;
diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
index 29469ce..11d5a9e 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -843,6 +843,14 @@ struct dd_function_table {
                                    struct gl_transform_feedback_object *obj);
+    * Return the number of vertices written to a stream during the last
+    * Begin/EndTransformFeedback block.
+    */
+   GLsizei (*GetTransformFeedbackVertexCount)(struct gl_context *ctx,
+                                              struct gl_transform_feedback_object *obj,
+                                              GLuint stream);
+   /**
     * \name GL_NV_texture_barrier interface
    void (*TextureBarrier)(struct gl_context *ctx);
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 97ed1bd..f5e1f01 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -3131,6 +3131,12 @@ struct gl_constants
    GLboolean PrimitiveRestartInSoftware;
+   /**
+    * Always use the GetTransformFeedbackVertexCount() driver hook, rather
+    * than passing the transform feedback object to the drawing function.
+    */
+   GLboolean AlwaysUseGetTransformFeedbackVertexCount;
    /** GL_ARB_map_buffer_alignment */
    GLuint MinMapBufferAlignment;
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 1670409..f25a9de 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -1464,6 +1464,16 @@ vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
+   if (ctx->Driver.GetTransformFeedbackVertexCount &&
+       (ctx->Const.AlwaysUseGetTransformFeedbackVertexCount ||
+        (ctx->Const.PrimitiveRestartInSoftware &&
+         ctx->Array._PrimitiveRestart) ||
+        !vbo_all_varyings_in_vbos(exec->array.inputs))) {
+      GLsizei n = ctx->Driver.GetTransformFeedbackVertexCount(ctx, obj, stream);
+      vbo_draw_arrays(ctx, mode, 0, n, numInstances, 0);
+      return;
+   }
    /* init most fields to zero */

More information about the mesa-dev mailing list