mesa/dlist: shortcircuit some redundant statechanges at compile time
authorKeith Whitwell <keithw@vmware.com>
Tue, 30 Jun 2009 08:55:33 +0000 (09:55 +0100)
committerKeith Whitwell <keithw@vmware.com>
Tue, 30 Jun 2009 08:55:33 +0000 (09:55 +0100)
Currently, state-changes in mesa display lists are more or less
a verbatim recording of the GL calls made during compilation.

This change introduces a minor optimization to recognize and eliminate
cases where the application emits redundant state changes, eg:

  glShadeModel( GL_FLAT );
  glBegin( prim )
  ...
  glEnd()
  glShadeModel( GL_FLAT );
  glBegin( prim )
  ...
  glEnd()

The big win is when we can eliminate all the statechanges between two
primitive blocks and combine them into a single VBO node.

This commit implements state-change elimination for Material and ShadeModel
only.  This is enough to make a start on debugging, etc.

src/mesa/main/dlist.c
src/mesa/main/mtypes.h

index 782f847904e580b742ecb88a01a01fdf9d375dc7..3647401a1bd32d5d6665de39dd877490d145f311 100644 (file)
@@ -3177,14 +3177,21 @@ save_ShadeModel(GLenum mode)
 {
    GET_CURRENT_CONTEXT(ctx);
    Node *n;
-   ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+   ASSERT_OUTSIDE_SAVE_BEGIN_END(ctx);
+
+   if (ctx->ExecuteFlag) {
+      CALL_ShadeModel(ctx->Exec, (mode));
+   }
+
+   if (ctx->ListState.Current.ShadeModel == mode)
+      return;
+
+   ctx->ListState.Current.ShadeModel = mode;
+
    n = ALLOC_INSTRUCTION(ctx, OPCODE_SHADE_MODEL, 1);
    if (n) {
       n[1].e = mode;
    }
-   if (ctx->ExecuteFlag) {
-      CALL_ShadeModel(ctx->Exec, (mode));
-   }
 }
 
 
@@ -5146,14 +5153,21 @@ save_EdgeFlag(GLboolean x)
    save_Attr1fNV(VERT_ATTRIB_EDGEFLAG, x ? (GLfloat)1.0 : (GLfloat)0.0);
 }
 
+static INLINE GLboolean compare4fv( const GLfloat *a,
+                                    const GLfloat *b,
+                                    GLuint count )
+{
+   return memcmp( a, b, count * sizeof(GLfloat) ) == 0;
+}
+                              
+
 static void GLAPIENTRY
 save_Materialfv(GLenum face, GLenum pname, const GLfloat * param)
 {
    GET_CURRENT_CONTEXT(ctx);
    Node *n;
    int args, i;
-
-   SAVE_FLUSH_VERTICES(ctx);
+   GLuint bitmask;
 
    switch (face) {
    case GL_BACK:
@@ -5183,6 +5197,28 @@ save_Materialfv(GLenum face, GLenum pname, const GLfloat * param)
       _mesa_compile_error(ctx, GL_INVALID_ENUM, "material(pname)");
       return;
    }
+   
+   if (ctx->ExecuteFlag) {
+      CALL_Materialfv(ctx->Exec, (face, pname, param));
+   }
+
+   bitmask = _mesa_material_bitmask(ctx, face, pname, ~0, NULL);
+
+   /* Try to eliminate redundant statechanges
+    */
+   for (i = 0; i < MAT_ATTRIB_MAX; i++) {
+      if (bitmask & (1 << i)) {
+         if (ctx->Driver.CurrentSavePrimitive == PRIM_OUTSIDE_BEGIN_END && 
+             ctx->ListState.ActiveMaterialSize[i] == args &&
+             compare4fv(ctx->ListState.CurrentMaterial[i], param, args))
+            return;
+             
+         ctx->ListState.ActiveMaterialSize[i] = args;
+         COPY_SZ_4V(ctx->ListState.CurrentMaterial[i], args, param);
+      }
+   }
+
+   SAVE_FLUSH_VERTICES(ctx);
 
    n = ALLOC_INSTRUCTION(ctx, OPCODE_MATERIAL, 6);
    if (n) {
@@ -5191,19 +5227,6 @@ save_Materialfv(GLenum face, GLenum pname, const GLfloat * param)
       for (i = 0; i < args; i++)
          n[3 + i].f = param[i];
    }
-
-   {
-      GLuint bitmask = _mesa_material_bitmask(ctx, face, pname, ~0, NULL);
-      for (i = 0; i < MAT_ATTRIB_MAX; i++)
-         if (bitmask & (1 << i)) {
-            ctx->ListState.ActiveMaterialSize[i] = args;
-            COPY_SZ_4V(ctx->ListState.CurrentMaterial[i], args, param);
-         }
-   }
-
-   if (ctx->ExecuteFlag) {
-      CALL_Materialfv(ctx->Exec, (face, pname, param));
-   }
 }
 
 static void GLAPIENTRY
@@ -6812,6 +6835,8 @@ _mesa_NewList(GLuint name, GLenum mode)
    for (i = 0; i < MAT_ATTRIB_MAX; i++)
       ctx->ListState.ActiveMaterialSize[i] = 0;
 
+   memset(&ctx->ListState.Current, 0, sizeof ctx->ListState.Current);
+
    ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
    ctx->Driver.NewList(ctx, name, mode);
 
index 84a082b253e3abc8705cbe085a01e6b5109bd9db..bdaa4977b72ad64fbd9300dcb5a6af02b3525507 100644 (file)
@@ -2806,6 +2806,13 @@ struct gl_dlist_state
    
    GLubyte ActiveEdgeFlag;
    GLboolean CurrentEdgeFlag;
+
+   struct {
+      /* State known to have been set by the currently-compiling display
+       * list.  Used to eliminate some redundant state changes.
+       */
+      GLenum ShadeModel;
+   } Current;
 };