vbo: implement primitive merging for glBegin/End sequences
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
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: José Fonseca <jfonseca@vmware.com>
This commit is contained in:
@@ -718,6 +718,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.
|
||||
*/
|
||||
@@ -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;
|
||||
|
||||
@@ -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,19 +315,13 @@ 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 &&
|
||||
this_prim->start == prev_prim->start + prev_prim->count &&
|
||||
this_prim->basevertex == prev_prim->basevertex &&
|
||||
this_prim->num_instances == prev_prim->num_instances &&
|
||||
this_prim->base_instance == prev_prim->base_instance) {
|
||||
vbo_try_prim_conversion(this_prim);
|
||||
|
||||
if (vbo_can_merge_prims(prev_prim, this_prim)) {
|
||||
/* 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 +414,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:
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user