diff options
Diffstat (limited to 'src/mesa/main/state.c')
-rw-r--r-- | src/mesa/main/state.c | 88 |
1 files changed, 61 insertions, 27 deletions
diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index 47e1aaa728..a6411f7b62 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)) |