[Mesa-dev] [PATCH 2/2] vbo: implement primitive merging for glBegin/End sequences

Brian Paul brianp at vmware.com
Thu May 2 15:26:08 PDT 2013


A surprising number of apps and benchmarks have poor code like this:

glBegin(GL_LINE_STRIP);
glVertex(v1);
glVertex(v2);
glEnd();
// Possibly some no-op state changes here
glBegin(GL_LINE_STRIP);
glVertex(v3);
glVertex(v4);
glEnd();
// repeat many, many times.

The above sequence can be converted into:

glBegin(GL_LINES);
glVertex(v1);
glVertex(v2);
glVertex(v3);
glVertex(v4);
glEnd();

Similarly for GL_POINTS, GL_TRIANGLES, etc.

Merging was already implemented for GL_QUADS in the display list code.
Now other prim types are handled and it's also done for immediate mode.

In one case:
                                 before   after
-----------------------------------------------
number of st_draw_vbo() calls:     141      45
number of _mesa_prims issued:     7520     632
---
 src/mesa/vbo/vbo_exec_api.c |   30 ++++++++++++++++++++++++++++++
 src/mesa/vbo/vbo_save_api.c |   18 ++++++++----------
 2 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
index 88cce98..600398c 100644
--- a/src/mesa/vbo/vbo_exec_api.c
+++ b/src/mesa/vbo/vbo_exec_api.c
@@ -719,6 +719,34 @@ static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
 
 
 /**
+ * Try to merge / concatenate the two most recent VBO primitives.
+ */
+static void
+try_vbo_merge(struct vbo_exec_context *exec)
+{
+   struct _mesa_prim *cur =  &exec->vtx.prim[exec->vtx.prim_count - 1];
+
+   assert(exec->vtx.prim_count >= 1);
+
+   vbo_try_prim_conversion(cur);
+
+   if (exec->vtx.prim_count >= 2) {
+      struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
+      assert(prev == cur - 1);
+
+      if (vbo_can_merge_prims(prev, cur)) {
+         assert(cur->begin);
+         assert(cur->end);
+         assert(prev->begin);
+         assert(prev->end);
+         vbo_merge_prims(prev, cur);
+         exec->vtx.prim_count--;  /* drop the last primitive */
+      }
+   }
+}
+
+
+/**
  * Called via glEnd.
  */
 static void GLAPIENTRY vbo_exec_End( void )
@@ -744,6 +772,8 @@ static void GLAPIENTRY vbo_exec_End( void )
 
       exec->vtx.prim[i].end = 1;
       exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
+
+      try_vbo_merge(exec);
    }
 
    ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index b8dd90c..9ce3c6e 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -305,9 +305,9 @@ _save_reset_counters(struct gl_context *ctx)
  * previous prim.
  */
 static void
-vbo_merge_prims(struct gl_context *ctx,
-                struct _mesa_prim *prim_list,
-                GLuint *prim_count)
+merge_prims(struct gl_context *ctx,
+            struct _mesa_prim *prim_list,
+            GLuint *prim_count)
 {
    GLuint i;
    struct _mesa_prim *prev_prim = prim_list;
@@ -315,10 +315,9 @@ vbo_merge_prims(struct gl_context *ctx,
    for (i = 1; i < *prim_count; i++) {
       struct _mesa_prim *this_prim = prim_list + i;
 
-      if (this_prim->mode == prev_prim->mode &&
-          this_prim->mode == GL_QUADS &&
-          this_prim->count % 4 == 0 &&
-          prev_prim->count % 4 == 0 &&
+      vbo_try_prim_conversion(this_prim);
+
+      if (vbo_can_merge_prims(prev_prim, this_prim) &&
           this_prim->start == prev_prim->start + prev_prim->count &&
           this_prim->basevertex == prev_prim->basevertex &&
           this_prim->num_instances == prev_prim->num_instances &&
@@ -326,8 +325,7 @@ vbo_merge_prims(struct gl_context *ctx,
          /* We've found a prim that just extend the previous one.  Tack it
           * onto the previous one, and let this primitive struct get dropped.
           */
-         prev_prim->count += this_prim->count;
-         prev_prim->end = this_prim->end;
+         vbo_merge_prims(prev_prim, this_prim);
          continue;
       }
 
@@ -420,7 +418,7 @@ _save_compile_vertex_list(struct gl_context *ctx)
     */
    save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
 
-   vbo_merge_prims(ctx, node->prim, &node->prim_count);
+   merge_prims(ctx, node->prim, &node->prim_count);
 
    /* Deal with GL_COMPILE_AND_EXECUTE:
     */
-- 
1.7.3.4



More information about the mesa-dev mailing list