mesa: Compute gl_client_array->_MaxElement during array validation
authorBrian Paul <brianp@vmware.com>
Wed, 6 May 2009 21:17:25 +0000 (15:17 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 7 May 2009 16:12:33 +0000 (10:12 -0600)
Used to be done in the glVertex/Normal/Color/etc/Pointer() calls but
if the VBO was reallocated the size could change.
New _NEW_BUFFER_OBJECT state flag.

src/mesa/main/bufferobj.c
src/mesa/main/mtypes.h
src/mesa/main/state.c
src/mesa/main/varray.c

index c8d160baa9a88c302bc1e094df5ac678df9bd272..49f690ddd2e48fdfe2f5aa2baf199d8718e47315 100644 (file)
@@ -958,6 +958,8 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
       bufObj->Pointer = NULL;
    }  
 
+   FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
+
    ASSERT(ctx->Driver.BufferData);
 
    /* Give the buffer object to the driver!  <data> may be null! */
index 716e5c655d87ff43380201e24f2003c278f102f6..368acde7a19749ef35a244adff6a1069c7be0c9e 100644 (file)
@@ -2619,6 +2619,7 @@ struct gl_matrix_stack
 #define _NEW_PROGRAM            0x8000000  /**< __GLcontextRec::VertexProgram */
 #define _NEW_CURRENT_ATTRIB     0x10000000  /**< __GLcontextRec::Current */
 #define _NEW_PROGRAM_CONSTANTS  0x20000000
+#define _NEW_BUFFER_OBJECT      0x40000000
 #define _NEW_ALL ~0
 /*@}*/
 
index 47e1aaa72814369f621022abe3be5cba7d39fceb..a6411f7b6214f60558b48505a87dd1c6e067ad4e 100644 (file)
@@ -64,97 +64,131 @@ update_separate_specular(GLcontext *ctx)
 
 
 /**
- * Update state dependent on vertex arrays.
+ * Compute the index of the last array element that can be safely accessed
+ * in a vertex array.  We can really only do this when the array lives in
+ * a VBO.
+ * The array->_MaxElement field will be updated.
+ * Later in glDrawArrays/Elements/etc we can do some bounds checking.
+ */
+static void
+compute_max_element(struct gl_client_array *array)
+{
+   assert(array->Enabled);
+   if (array->BufferObj->Name) {
+      /* Compute the max element we can access in the VBO without going
+       * out of bounds.
+       */
+      array->_MaxElement = ((GLsizeiptrARB) array->BufferObj->Size
+                            - (GLsizeiptrARB) array->Ptr + array->StrideB
+                            - array->_ElementSize) / array->StrideB;
+   }
+   else {
+      /* user-space array, no idea how big it is */
+      array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
+   }
+}
+
+
+/**
+ * Helper for update_arrays().
+ * \return  min(current min, array->_MaxElement).
+ */
+static GLuint
+update_min(GLuint min, struct gl_client_array *array)
+{
+   compute_max_element(array);
+   return MIN2(min, array->_MaxElement);
+}
+
+
+/**
+ * Update ctx->Array._MaxElement (the max legal index into all enabled arrays).
+ * Need to do this upon new array state or new buffer object state.
  */
 static void
 update_arrays( GLcontext *ctx )
 {
-   const struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
-   GLuint i, min;
+   struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+   GLuint i, min = ~0;
 
    /* find min of _MaxElement values for all enabled arrays */
 
    /* 0 */
    if (ctx->VertexProgram._Current
        && arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
-      min = arrayObj->VertexAttrib[VERT_ATTRIB_POS]._MaxElement;
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]);
    }
    else if (arrayObj->Vertex.Enabled) {
-      min = arrayObj->Vertex._MaxElement;
-   }
-   else {
-      /* can't draw anything without vertex positions! */
-      min = 0;
+      min = update_min(min, &arrayObj->Vertex);
    }
 
    /* 1 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]);
    }
    /* no conventional vertex weight array */
 
    /* 2 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]);
    }
    else if (arrayObj->Normal.Enabled) {
-      min = MIN2(min, arrayObj->Normal._MaxElement);
+      min = update_min(min, &arrayObj->Normal);
    }
 
    /* 3 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]);
    }
    else if (arrayObj->Color.Enabled) {
-      min = MIN2(min, arrayObj->Color._MaxElement);
+      min = update_min(min, &arrayObj->Color);
    }
 
    /* 4 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]);
    }
    else if (arrayObj->SecondaryColor.Enabled) {
-      min = MIN2(min, arrayObj->SecondaryColor._MaxElement);
+      min = update_min(min, &arrayObj->SecondaryColor);
    }
 
    /* 5 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_FOG]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]);
    }
    else if (arrayObj->FogCoord.Enabled) {
-      min = MIN2(min, arrayObj->FogCoord._MaxElement);
+      min = update_min(min, &arrayObj->FogCoord);
    }
 
    /* 6 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]);
    }
    else if (arrayObj->Index.Enabled) {
-      min = MIN2(min, arrayObj->Index._MaxElement);
+      min = update_min(min, &arrayObj->Index);
    }
 
-
    /* 7 */
    if (ctx->VertexProgram._Enabled
        && arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
-      min = MIN2(min, arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]._MaxElement);
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]);
    }
 
    /* 8..15 */
    for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX7; i++) {
       if (ctx->VertexProgram._Enabled
           && arrayObj->VertexAttrib[i].Enabled) {
-         min = MIN2(min, arrayObj->VertexAttrib[i]._MaxElement);
+         min = update_min(min, &arrayObj->VertexAttrib[i]);
       }
       else if (i - VERT_ATTRIB_TEX0 < ctx->Const.MaxTextureCoordUnits
                && arrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
-         min = MIN2(min, arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]._MaxElement);
+         min = update_min(min, &arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]);
       }
    }
 
@@ -162,13 +196,13 @@ update_arrays( GLcontext *ctx )
    if (ctx->VertexProgram._Current) {
       for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) {
          if (arrayObj->VertexAttrib[i].Enabled) {
-            min = MIN2(min, arrayObj->VertexAttrib[i]._MaxElement);
+            min = update_min(min, &arrayObj->VertexAttrib[i]);
          }
       }
    }
 
    if (arrayObj->EdgeFlag.Enabled) {
-      min = MIN2(min, arrayObj->EdgeFlag._MaxElement);
+      min = update_min(min, &arrayObj->EdgeFlag);
    }
 
    /* _MaxElement is one past the last legal array element */
@@ -548,7 +582,7 @@ _mesa_update_state_locked( GLcontext *ctx )
    if (new_state & _DD_NEW_SEPARATE_SPECULAR)
       update_separate_specular( ctx );
 
-   if (new_state & (_NEW_ARRAY | _NEW_PROGRAM))
+   if (new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT))
       update_arrays( ctx );
 
    if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
index 527555be0e4f44d787e19892a9e3c113e516ed1d..4d153b1c0b22ca69759e2ec62052244afc6807be 100644 (file)
@@ -65,22 +65,9 @@ update_array(GLcontext *ctx, struct gl_client_array *array,
    array->Ptr = (const GLubyte *) ptr;
    array->_ElementSize = elementSize;
 
-#if FEATURE_ARB_vertex_buffer_object
    _mesa_reference_buffer_object(ctx, &array->BufferObj,
                                  ctx->Array.ArrayBufferObj);
 
-   /* Compute the index of the last array element that's inside the buffer.
-    * Later in glDrawArrays we'll check if start + count > _MaxElement to
-    * be sure we won't go out of bounds.
-    */
-   if (array->BufferObj->Name)
-      array->_MaxElement = ((GLsizeiptrARB) array->BufferObj->Size
-                            - (GLsizeiptrARB) array->Ptr + array->StrideB
-                            - elementSize) / array->StrideB;
-   else
-#endif
-      array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
-
    ctx->NewState |= _NEW_ARRAY;
    ctx->Array.NewState |= dirtyBit;
 }