summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2009-05-06 15:17:25 -0600
committerBrian Paul <[email protected]>2009-05-07 10:12:33 -0600
commitb9d0f947f2bcc47047b162e3d7c8f91b6153e02c (patch)
tree44ece271963c4792f87d690da436a6555ea32463 /src
parent800b14cd378ed708a29230d92031ac7b6ad6a286 (diff)
mesa: Compute gl_client_array->_MaxElement during array validation
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.
Diffstat (limited to 'src')
-rw-r--r--src/mesa/main/bufferobj.c2
-rw-r--r--src/mesa/main/mtypes.h1
-rw-r--r--src/mesa/main/state.c88
-rw-r--r--src/mesa/main/varray.c13
4 files changed, 64 insertions, 40 deletions
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
index c8d160baa9a..49f690ddd2e 100644
--- a/src/mesa/main/bufferobj.c
+++ b/src/mesa/main/bufferobj.c
@@ -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! */
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 716e5c655d8..368acde7a19 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -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
/*@}*/
diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c
index 47e1aaa7281..a6411f7b621 100644
--- a/src/mesa/main/state.c
+++ b/src/mesa/main/state.c
@@ -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))
diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c
index 527555be0e4..4d153b1c0b2 100644
--- a/src/mesa/main/varray.c
+++ b/src/mesa/main/varray.c
@@ -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;
}