update_array() and update_array_format() are changed to update the new attrib and binding states, and the client arrays become derived state. --- src/mesa/main/api_arrayelt.c | 7 + src/mesa/main/arrayobj.c | 63 ++++-- src/mesa/main/arrayobj.h | 5 + src/mesa/main/attrib.c | 5 +- src/mesa/main/bufferobj.c | 4 +- src/mesa/main/context.c | 4 + src/mesa/main/extensions.c | 1 + src/mesa/main/mtypes.h | 50 ++++- src/mesa/main/state.c | 3 + src/mesa/main/varray.c | 490 +++++++++++++++++++++++++++++++++++++++--- src/mesa/main/varray.h | 48 +++++ 11 files changed, 629 insertions(+), 51 deletions(-)
diff --git a/src/mesa/main/api_arrayelt.c b/src/mesa/main/api_arrayelt.c index 5a316f0..6822465 100644 --- a/src/mesa/main/api_arrayelt.c +++ b/src/mesa/main/api_arrayelt.c @@ -35,6 +35,7 @@ */ #include "glheader.h" +#include "arrayobj.h" #include "api_arrayelt.h" #include "bufferobj.h" #include "context.h" @@ -1485,6 +1486,12 @@ _ae_update_state(struct gl_context *ctx) actx->nr_vbos = 0; + if (arrayObj->NewArrays) { + /* update the derived client arrays */ + _mesa_update_array_object_client_arrays(ctx, arrayObj); + arrayObj->NewArrays = 0; + } + /* conventional vertex arrays */ if (arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) { aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX]; diff --git a/src/mesa/main/arrayobj.c b/src/mesa/main/arrayobj.c index 79a54fa..dbf8fdc 100644 --- a/src/mesa/main/arrayobj.c +++ b/src/mesa/main/arrayobj.c @@ -72,7 +72,7 @@ _mesa_lookup_arrayobj(struct gl_context *ctx, GLuint id) /** - * For all the vertex arrays in the array object, unbind any pointers + * For all the vertex binding points in the array object, unbind any pointers * to any buffer objects (VBOs). * This is done just prior to array object destruction. */ @@ -81,6 +81,9 @@ unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj) { GLuint i; + for (i = 0; i < Elements(obj->VertexBinding); i++) + _mesa_reference_buffer_object(ctx, &obj->VertexBinding[i].BufferObj, NULL); + for (i = 0; i < Elements(obj->_VertexAttrib); i++) _mesa_reference_buffer_object(ctx, &obj->_VertexAttrib[i].BufferObj, NULL); } @@ -181,20 +184,30 @@ _mesa_reference_array_object_(struct gl_context *ctx, static void init_array(struct gl_context *ctx, - struct gl_client_array *array, GLint size, GLint type) + struct gl_array_object *obj, GLuint index, GLint size, GLint type) { + struct gl_vertex_attrib_array *array = &obj->VertexAttrib[index]; + struct gl_vertex_buffer_binding *binding = &obj->VertexBinding[index]; + array->Size = size; array->Type = type; array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ array->Stride = 0; - array->StrideB = 0; array->Ptr = NULL; + array->RelativeOffset = 0; array->Enabled = GL_FALSE; array->Normalized = GL_FALSE; array->Integer = GL_FALSE; array->_ElementSize = size * _mesa_sizeof_type(type); + array->VertexBinding = index; + + binding->Offset = 0; + binding->Stride = array->_ElementSize; + binding->BufferObj = NULL; + binding->_BoundArrays = BITFIELD64_BIT(index); + /* Vertex array buffers */ - _mesa_reference_buffer_object(ctx, &array->BufferObj, + _mesa_reference_buffer_object(ctx, &binding->BufferObj, ctx->Shared->NullBufferObj); } @@ -218,28 +231,28 @@ _mesa_initialize_array_object( struct gl_context *ctx, for (i = 0; i < Elements(obj->_VertexAttrib); i++) { switch (i) { case VERT_ATTRIB_WEIGHT: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_WEIGHT], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_WEIGHT, 1, GL_FLOAT); break; case VERT_ATTRIB_NORMAL: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_NORMAL], 3, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_NORMAL, 3, GL_FLOAT); break; case VERT_ATTRIB_COLOR1: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_COLOR1], 3, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_COLOR1, 3, GL_FLOAT); break; case VERT_ATTRIB_FOG: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_FOG], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_FOG, 1, GL_FLOAT); break; case VERT_ATTRIB_COLOR_INDEX: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT); break; case VERT_ATTRIB_EDGEFLAG: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG], 1, GL_BOOL); + init_array(ctx, obj, VERT_ATTRIB_EDGEFLAG, 1, GL_BOOL); break; case VERT_ATTRIB_POINT_SIZE: - init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE], 1, GL_FLOAT); + init_array(ctx, obj, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT); break; default: - init_array(ctx, &obj->_VertexAttrib[i], 4, GL_FLOAT); + init_array(ctx, obj, i, 4, GL_FLOAT); break; } } @@ -322,6 +335,32 @@ _mesa_update_array_object_max_element(struct gl_context *ctx, } +/** + * Updates the derived gl_client_arrays when a gl_vertex_attrib_array + * or a gl_vertex_buffer_binding has changed. + */ +void +_mesa_update_array_object_client_arrays(struct gl_context *ctx, struct gl_array_object *arrayObj) +{ + GLbitfield64 arrays = arrayObj->NewArrays; + + while (arrays) { + struct gl_client_array *client_array; + struct gl_vertex_attrib_array *attrib_array; + struct gl_vertex_buffer_binding *buffer_binding; + + GLint attrib = ffsll(arrays) - 1; + arrays ^= BITFIELD64_BIT(attrib); + + attrib_array = &arrayObj->VertexAttrib[attrib]; + buffer_binding = &arrayObj->VertexBinding[attrib_array->VertexBinding]; + client_array = &arrayObj->_VertexAttrib[attrib]; + + _mesa_update_client_array(ctx, client_array, attrib_array, buffer_binding); + } +} + + /**********************************************************************/ /* API Functions */ /**********************************************************************/ diff --git a/src/mesa/main/arrayobj.h b/src/mesa/main/arrayobj.h index 492ef35..7c37202 100644 --- a/src/mesa/main/arrayobj.h +++ b/src/mesa/main/arrayobj.h @@ -78,6 +78,11 @@ extern void _mesa_update_array_object_max_element(struct gl_context *ctx, struct gl_array_object *arrayObj); +extern void +_mesa_update_array_object_client_arrays(struct gl_context *ctx, + struct gl_array_object *arrayObj); + + /** Returns the bitmask of all enabled arrays in fixed function mode. * * In fixed function mode only the traditional fixed function arrays diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c index 87c7f66..c9332bd 100644 --- a/src/mesa/main/attrib.c +++ b/src/mesa/main/attrib.c @@ -1369,8 +1369,11 @@ copy_array_object(struct gl_context *ctx, /* In theory must be the same anyway, but on recreate make sure it matches */ dest->ARBsemantics = src->ARBsemantics; - for (i = 0; i < Elements(src->_VertexAttrib); i++) + for (i = 0; i < Elements(src->_VertexAttrib); i++) { _mesa_copy_client_array(ctx, &dest->_VertexAttrib[i], &src->_VertexAttrib[i]); + _mesa_copy_vertex_attrib_array(ctx, &dest->VertexAttrib[i], &src->VertexAttrib[i]); + _mesa_copy_vertex_buffer_binding(ctx, &dest->VertexBinding[i], &src->VertexBinding[i]); + } /* _Enabled must be the same than on push */ dest->_Enabled = src->_Enabled; diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index d4c4cdd..cab7937 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -857,8 +857,8 @@ _mesa_DeleteBuffers(GLsizei n, const GLuint *ids) } /* unbind any vertex pointers bound to this buffer */ - for (j = 0; j < Elements(arrayObj->_VertexAttrib); j++) { - unbind(ctx, &arrayObj->_VertexAttrib[j].BufferObj, bufObj); + for (j = 0; j < Elements(arrayObj->VertexBinding); j++) { + unbind(ctx, &arrayObj->VertexBinding[j].BufferObj, bufObj); } if (ctx->Array.ArrayBufferObj == bufObj) { diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 0d1f71c..70b2453 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -669,6 +669,10 @@ _mesa_init_constants(struct gl_context *ctx) ctx->Const.MaxColorTextureSamples = 1; ctx->Const.MaxDepthTextureSamples = 1; ctx->Const.MaxIntegerSamples = 1; + + /* GL_ARB_vertex_attrib_binding */ + ctx->Const.MaxVertexAttribRelativeOffset = 2047; + ctx->Const.MaxVertexAttribBindings = MAX_VERTEX_GENERIC_ATTRIBS; } diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index 00d65cc..2c3fc07 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -163,6 +163,7 @@ static const struct extension extension_table[] = { { "GL_ARB_uniform_buffer_object", o(ARB_uniform_buffer_object), GL, 2009 }, { "GL_ARB_vertex_array_bgra", o(EXT_vertex_array_bgra), GL, 2008 }, { "GL_ARB_vertex_array_object", o(dummy_true), GL, 2006 }, + { "GL_ARB_vertex_attrib_binding", o(dummy_true), GL, 2012 }, { "GL_ARB_vertex_buffer_object", o(dummy_true), GLL, 2003 }, { "GL_ARB_vertex_program", o(ARB_vertex_program), GLL, 2002 }, { "GL_ARB_vertex_shader", o(ARB_vertex_shader), GL, 2002 }, diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index b0d638f..aac81c3 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1466,6 +1466,44 @@ struct gl_client_array /** + * Vertex attribute array as seen by the client. + * + * Contains the size, type, format and normalization flag, + * along with the index of a vertex buffer binding point. + * + * Note that the Stride field corresponds to VERTEX_ATTRIB_ARRAY_STRIDE + * and is only present for backwards compatibility reasons. + * Rendering always uses VERTEX_BINDING_STRIDE. + * The gl*Pointer() functions will set VERTEX_ATTRIB_ARRAY_STRIDE + * and VERTEX_BINDING_STRIDE to the same value, while + * glBindVertexBuffer() will only set VERTEX_BINDING_STRIDE. + */ +struct gl_vertex_attrib_array +{ + GLint Size; /**< Components per element (1,2,3,4) */ + GLenum Type; /**< Datatype: GL_FLOAT, GL_INT, etc */ + GLenum Format; /**< Default: GL_RGBA, but may be GL_BGRA */ + GLsizei Stride; /**< Stride as specified with gl*Pointer() */ + const GLubyte *Ptr; /**< Points to client array data. Not used when a VBO is bound */ + GLintptr RelativeOffset; /**< Offset of the first element relative to the binding offset */ + GLboolean Enabled; /**< Whether the array is enabled */ + GLboolean Normalized; /**< Fixed-point values are normalized when converted to floats */ + GLboolean Integer; /**< Fixed-point values are not converted to floats */ + GLuint _ElementSize; /**< Size of each element in bytes */ + GLuint VertexBinding; /**< Vertex buffer binding */ +}; + +struct gl_vertex_buffer_binding +{ + GLintptr Offset; /**< User-specified offset */ + GLsizei Stride; /**< User-specified stride */ + GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ + struct gl_buffer_object *BufferObj; /**< GL_ARB_vertex_buffer_object */ + GLbitfield64 _BoundArrays; /**< Arrays bound to this binding point */ +}; + + +/** * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object * extension, but a nice encapsulation in any case. */ @@ -1499,9 +1537,15 @@ struct gl_array_object */ GLboolean EverBound; - /** Vertex attribute arrays */ + /** Derived vertex attribute arrays */ struct gl_client_array _VertexAttrib[VERT_ATTRIB_MAX]; + /** Vertex attribute arrays */ + struct gl_vertex_attrib_array VertexAttrib[VERT_ATTRIB_MAX]; + + /** Vertex buffer bindings */ + struct gl_vertex_buffer_binding VertexBinding[VERT_ATTRIB_MAX]; + /** Mask of VERT_BIT_* values indicating which arrays are enabled */ GLbitfield64 _Enabled; @@ -3169,6 +3213,10 @@ struct gl_constants GLint MaxColorTextureSamples; GLint MaxDepthTextureSamples; GLint MaxIntegerSamples; + + /** GL_ARB_vertex_attrib_binding */ + GLint MaxVertexAttribRelativeOffset; + GLint MaxVertexAttribBindings; }; diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index bf21631..33070b7 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -410,6 +410,9 @@ _mesa_update_state_locked( struct gl_context *ctx ) new_prog_state |= update_program( ctx ); } + if (new_state & _NEW_ARRAY) + _mesa_update_array_object_client_arrays(ctx, ctx->Array.ArrayObj); + if (ctx->Const.CheckArrayBounds && new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) { _mesa_update_array_object_max_element(ctx, ctx->Array.ArrayObj); diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c index f046fd6..e15081a 100644 --- a/src/mesa/main/varray.c +++ b/src/mesa/main/varray.c @@ -102,20 +102,113 @@ type_to_bit(const struct gl_context *ctx, GLenum type) } +static inline struct gl_vertex_attrib_array * +gl_vertex_attrib_array(struct gl_context *ctx, GLuint index) +{ + ASSERT(index < Elements(arrayObj->VertexAttrib)); + return &ctx->Array.ArrayObj->VertexAttrib[index]; +} + + +static inline struct gl_vertex_buffer_binding * +gl_vertex_buffer_binding(struct gl_context *ctx, GLuint index) +{ + ASSERT(index < Elements(arrayObj->VertexBinding)); + return &ctx->Array.ArrayObj->VertexBinding[index]; +} + + +/** + * Sets the VertexBinding field in the vertex attribute given by attribIndex. + */ +static void +vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex, + GLuint bindingIndex) +{ + struct gl_vertex_attrib_array *array = + gl_vertex_attrib_array(ctx, attribIndex); + + if (array->VertexBinding != bindingIndex) { + const GLbitfield64 array_bit = VERT_BIT(attribIndex); + struct gl_vertex_buffer_binding *new_binding = + gl_vertex_buffer_binding(ctx, bindingIndex); + struct gl_vertex_buffer_binding *old_binding = + gl_vertex_buffer_binding(ctx, array->VertexBinding); + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + + array->VertexBinding = bindingIndex; + + old_binding->_BoundArrays &= ~array_bit; + new_binding->_BoundArrays |= array_bit; + + ctx->Array.ArrayObj->NewArrays |= array_bit; + } +} + + +/** + * Binds a buffer object to the vertex buffer binding point given by index, + * and sets the Offset and Stride fields. + */ +static void +bind_vertex_buffer(struct gl_context *ctx, GLuint index, + struct gl_buffer_object *vbo, + GLintptr offset, GLsizei stride) +{ + struct gl_vertex_buffer_binding *binding = + gl_vertex_buffer_binding(ctx, index); + + if (binding->BufferObj != vbo || + binding->Offset != offset || + binding->Stride != stride) { + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + + _mesa_reference_buffer_object(ctx, &binding->BufferObj, vbo); + + binding->Offset = offset; + binding->Stride = stride; + + ctx->Array.ArrayObj->NewArrays |= binding->_BoundArrays; + } +} + + +/** + * Sets the InstanceDivisor field in the vertex buffer binding point + * given by bindingIndex. + */ +static void +vertex_binding_divisor(struct gl_context *ctx, GLuint bindingIndex, + GLuint divisor) +{ + struct gl_vertex_buffer_binding *binding = + gl_vertex_buffer_binding(ctx, bindingIndex); + + if (binding->InstanceDivisor != divisor) { + FLUSH_VERTICES(ctx, _NEW_ARRAY); + binding->InstanceDivisor = divisor; + ctx->Array.ArrayObj->NewArrays |= binding->_BoundArrays; + } +} + + /** * Does error checking and updates the format in an attrib array. * - * Called by update_array(). + * Called by update_array() and VertexAttrib*Format(). * - * \param func Name of calling function used for error reporting - * \param attrib The index of the attribute array - * \param legalTypes Bitmask of *_BIT above indicating legal datatypes - * \param sizeMin Min allowable size value - * \param sizeMax Max allowable size value (may also be BGRA_OR_4) - * \param size Components per element (1, 2, 3 or 4) - * \param type Datatype of each component (GL_FLOAT, GL_INT, etc) - * \param normalized Whether integer types are converted to floats in [-1, 1] - * \param integer Integer-valued values (will not be normalized to [-1, 1]) + * \param func Name of calling function used for error reporting + * \param attrib The index of the attribute array + * \param legalTypes Bitmask of *_BIT above indicating legal datatypes + * \param sizeMin Min allowable size value + * \param sizeMax Max allowable size value (may also be BGRA_OR_4) + * \param size Components per element (1, 2, 3 or 4) + * \param type Datatype of each component (GL_FLOAT, GL_INT, etc) + * \param normalized Whether integer types are converted to floats in [-1, 1] + * \param integer Integer-valued values (will not be normalized to [-1, 1]) + * \param relativeOffset Offset of the first element relative to the binding offset. */ static GLboolean update_array_format(struct gl_context *ctx, @@ -123,9 +216,10 @@ update_array_format(struct gl_context *ctx, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, - GLboolean normalized, GLboolean integer) + GLboolean normalized, GLboolean integer, + GLuint relativeOffset) { - struct gl_client_array *array; + struct gl_vertex_attrib_array *array; GLbitfield typeBit; GLuint elementSize; GLenum format = GL_RGBA; @@ -224,19 +318,36 @@ update_array_format(struct gl_context *ctx, return GL_FALSE; } + /* The ARB_vertex_attrib_binding_spec says: + * + * An INVALID_VALUE error is generated if <relativeoffset> is larger than + * the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSET. + */ + if (relativeOffset > ctx->Const.MaxVertexAttribRelativeOffset) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(relativeOffset=%d > " + "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET)", + func, relativeOffset); + return GL_FALSE; + } + ASSERT(size <= 4); elementSize = _mesa_bytes_per_vertex_attrib(size, type); assert(elementSize != -1); - array = &ctx->Array.ArrayObj->_VertexAttrib[attrib]; + array = gl_vertex_attrib_array(ctx, attrib); array->Size = size; array->Type = type; array->Format = format; array->Normalized = normalized; array->Integer = integer; + array->RelativeOffset = relativeOffset; array->_ElementSize = elementSize; + ctx->Array.ArrayObj->NewArrays |= VERT_BIT(attrib); + ctx->NewState |= _NEW_ARRAY; + return GL_TRUE; } @@ -266,7 +377,8 @@ update_array(struct gl_context *ctx, GLboolean normalized, GLboolean integer, const GLvoid *ptr) { - struct gl_client_array *array; + struct gl_vertex_attrib_array *array; + GLsizei effectiveStride; /* Page 407 (page 423 of the PDF) of the OpenGL 3.0 spec says: * @@ -286,7 +398,7 @@ update_array(struct gl_context *ctx, } if (!update_array_format(ctx, func, attrib, legalTypesMask, sizeMin, sizeMax, - size, type, normalized, integer)) { + size, type, normalized, integer, 0)) { return; } @@ -313,16 +425,18 @@ update_array(struct gl_context *ctx, return; } - array = &ctx->Array.ArrayObj->_VertexAttrib[attrib]; - array->Stride = stride; - array->StrideB = stride ? stride : array->_ElementSize; - array->Ptr = (const GLubyte *) ptr; + /* Reset the vertex attrib binding */ + vertex_attrib_binding(ctx, attrib, attrib); - _mesa_reference_buffer_object(ctx, &array->BufferObj, - ctx->Array.ArrayBufferObj); + /* The Stride and Ptr fields are not set by update_array_format() */ + array = gl_vertex_attrib_array(ctx, attrib); + array->Stride = stride; + array->Ptr = (const GLvoid *) ptr; - ctx->NewState |= _NEW_ARRAY; - ctx->Array.ArrayObj->NewArrays |= VERT_BIT(attrib); + /* Update the vertex buffer binding */ + effectiveStride = stride != 0 ? stride : array->_ElementSize; + bind_vertex_buffer(ctx, attrib, ctx->Array.ArrayBufferObj, + (GLintptr) ptr, effectiveStride); } @@ -569,10 +683,10 @@ _mesa_EnableVertexAttribArray(GLuint index) ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->_VertexAttrib)); - if (!arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) { + if (!arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) { /* was disabled, now being enabled */ FLUSH_VERTICES(ctx, _NEW_ARRAY); - arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_TRUE; + arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_TRUE; arrayObj->_Enabled |= VERT_BIT_GENERIC(index); arrayObj->NewArrays |= VERT_BIT_GENERIC(index); } @@ -595,10 +709,10 @@ _mesa_DisableVertexAttribArray(GLuint index) ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->_VertexAttrib)); - if (arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) { + if (arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) { /* was enabled, now being disabled */ FLUSH_VERTICES(ctx, _NEW_ARRAY); - arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_FALSE; + arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_FALSE; arrayObj->_Enabled &= ~VERT_BIT_GENERIC(index); arrayObj->NewArrays |= VERT_BIT_GENERIC(index); } @@ -1180,9 +1294,10 @@ _mesa_PrimitiveRestartIndex(GLuint index) void GLAPIENTRY _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) { - struct gl_client_array *array; GET_CURRENT_CONTEXT(ctx); + const GLuint genericIndex = VERT_ATTRIB_GENERIC(index); + if (!ctx->Extensions.ARB_instanced_arrays) { _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexAttribDivisor()"); return; @@ -1194,14 +1309,21 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) return; } - ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->_VertexAttrib)); + ASSERT(genericIndex < Elements(ctx->Array.ArrayObj->VertexAttrib)); - array = &ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)]; - if (array->InstanceDivisor != divisor) { - FLUSH_VERTICES(ctx, _NEW_ARRAY); - array->InstanceDivisor = divisor; - ctx->Array.ArrayObj->NewArrays |= VERT_BIT(VERT_ATTRIB_GENERIC(index)); - } + /* The ARB_vertex_attrib_binding spec says: + * + * "The command + * + * void VertexAttribDivisor(uint index, uint divisor); + * + * is equivalent to (assuming no errors are generated): + * + * VertexAttribBinding(index, index); + * VertexBindingDivisor(index, divisor);" + */ + vertex_attrib_binding(ctx, genericIndex, genericIndex); + vertex_binding_divisor(ctx, genericIndex, divisor); } @@ -1237,6 +1359,78 @@ void GLAPIENTRY _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, GLsizei stride) { + struct gl_buffer_object *vbo; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no vertex array object + * is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindVertexBuffer(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_VALUE error is generated if <bindingindex> is greater than + * the value of MAX_VERTEX_ATTRIB_BINDINGS." + */ + if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(bindingindex=%u > " + "GL_MAX_VERTEX_ATTRIB_BINDINGS)", + bindingIndex); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if <stride> or <offset> + * are negative." + */ + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(offset=%d < 0)", offset); + return; + } + + if (stride < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glBindVertexBuffer(stride=%d < 0)", stride); + return; + } + + if (buffer != 0) { + vbo = _mesa_lookup_bufferobj(ctx, buffer); + + /* The ARB_vertex_attrib_binding spec doesn't specify that an error + * should be generated when <buffer> doesn't refer to a valid buffer + * object, but we assume that this is an oversight. + */ + if (!vbo) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindVertexBuffer(buffer=%u is not a valid " + "buffer object)", + buffer); + return; + } + } else { + /* The ARB_vertex_attrib_binding spec says: + * + * "If <buffer> is zero, any buffer object attached to this + * bindpoint is detached." + */ + vbo = ctx->Shared->NullBufferObj; + } + + bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(bindingIndex), + vbo, offset, stride); } @@ -1244,6 +1438,50 @@ void GLAPIENTRY _mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, GLboolean normalized, GLuint relativeOffset) { + const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT | + SHORT_BIT | UNSIGNED_SHORT_BIT | + INT_BIT | UNSIGNED_INT_BIT | + HALF_BIT | FLOAT_BIT | DOUBLE_BIT | + FIXED_GL_BIT | + UNSIGNED_INT_2_10_10_10_REV_BIT | + INT_2_10_10_10_REV_BIT); + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated under any of the following + * conditions: + * - if no vertex array object is currently bound (see section 2.10); + * - ..." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribFormat(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if index is greater than or equal + * to the value of MAX_VERTEX_ATTRIBS." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribFormat(attribindex=%u > " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + FLUSH_VERTICES(ctx, 0); + + update_array_format(ctx, "glVertexAttribFormat", + VERT_ATTRIB_GENERIC(attribIndex), + legalTypes, 1, BGRA_OR_4, size, type, normalized, + GL_FALSE, relativeOffset); } @@ -1251,6 +1489,46 @@ void GLAPIENTRY _mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset) { + const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT | + SHORT_BIT | UNSIGNED_SHORT_BIT | + INT_BIT | UNSIGNED_INT_BIT); + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated under any of the following + * conditions: + * - if no vertex array object is currently bound (see section 2.10); + * - ..." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribIFormat(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if index is greater than + * or equal to the value of MAX_VERTEX_ATTRIBS." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribIFormat(attribindex=%u > " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + FLUSH_VERTICES(ctx, 0); + + update_array_format(ctx, "glVertexAttribIFormat", + VERT_ATTRIB_GENERIC(attribIndex), + legalTypes, 1, 4, size, type, GL_FALSE, GL_TRUE, + relativeOffset); } @@ -1258,18 +1536,131 @@ void GLAPIENTRY _mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset) { + const GLbitfield legalTypes = DOUBLE_BIT; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* Page 298 of the PDF of the OpenGL 4.3 (Core Profile) spec says: + * + * "An INVALID_OPERATION error is generated under any of the following + * conditions: + * • if no vertex array object is currently bound (see section 10.4); + * • ..." + * + * This language is missing from the extension spec, but we assume + * that this is an oversight. + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribLFormat(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "The error INVALID_VALUE is generated if <attribindex> is greater than + * or equal to the value of MAX_VERTEX_ATTRIBS." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribLFormat(attribindex=%u > " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + FLUSH_VERTICES(ctx, 0); + + update_array_format(ctx, "glVertexAttribLFormat", + VERT_ATTRIB_GENERIC(attribIndex), + legalTypes, 1, 4, size, type, GL_FALSE, GL_FALSE, + relativeOffset); } void GLAPIENTRY _mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) { + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no vertex array object + * is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexAttribBinding(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "<attribindex> must be less than the value of MAX_VERTEX_ATTRIBS and + * <bindingindex> must be less than the value of + * MAX_VERTEX_ATTRIB_BINDINGS, otherwise the error INVALID_VALUE + * is generated." + */ + if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribBinding(attribindex=%u >= " + "GL_MAX_VERTEX_ATTRIBS)", + attribIndex); + return; + } + + if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexAttribBinding(bindingindex=%u >= " + "GL_MAX_VERTEX_ATTRIB_BINDINGS)", + bindingIndex); + return; + } + + ASSERT(VERT_ATTRIB_GENERIC(attribIndex) < + Elements(ctx->Array.ArrayObj->VertexAttrib)); + + vertex_attrib_binding(ctx, VERT_ATTRIB_GENERIC(attribIndex), + VERT_ATTRIB_GENERIC(bindingIndex)); } void GLAPIENTRY _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor) { + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_OPERATION error is generated if no vertex array object + * is bound." + */ + if (ctx->API == API_OPENGL_CORE && + ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexBindingDivisor(No array object bound)"); + return; + } + + /* The ARB_vertex_attrib_binding spec says: + * + * "An INVALID_VALUE error is generated if <bindingindex> is greater + * than or equal to the value of MAX_VERTEX_ATTRIB_BINDINGS." + */ + if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glVertexBindingDivisor(bindingindex=%u > " + "GL_MAX_VERTEX_ATTRIB_BINDINGS)", + bindingIndex); + return; + } + + vertex_binding_divisor(ctx, VERT_ATTRIB_GENERIC(bindingIndex), divisor); } @@ -1296,7 +1687,36 @@ _mesa_copy_client_array(struct gl_context *ctx, dst->_MaxElement = src->_MaxElement; } +void +_mesa_copy_vertex_attrib_array(struct gl_context *ctx, + struct gl_vertex_attrib_array *dst, + const struct gl_vertex_attrib_array *src) +{ + dst->Size = src->Size; + dst->Type = src->Type; + dst->Format = src->Format; + dst->VertexBinding = src->VertexBinding; + dst->RelativeOffset = src->RelativeOffset; + dst->Format = src->Format; + dst->Integer = src->Integer; + dst->Normalized = src->Normalized; + dst->Ptr = src->Ptr; + dst->Enabled = src->Enabled; + dst->_ElementSize = src->_ElementSize; +} + +void +_mesa_copy_vertex_buffer_binding(struct gl_context *ctx, + struct gl_vertex_buffer_binding *dst, + const struct gl_vertex_buffer_binding *src) +{ + dst->Offset = src->Offset; + dst->Stride = src->Stride; + dst->InstanceDivisor = src->InstanceDivisor; + dst->_BoundArrays = src->_BoundArrays; + _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); +} /** * Print vertex array's fields. diff --git a/src/mesa/main/varray.h b/src/mesa/main/varray.h index 2b54fde..a75cb7d 100644 --- a/src/mesa/main/varray.h +++ b/src/mesa/main/varray.h @@ -29,6 +29,7 @@ #include "glheader.h" +#include "bufferobj.h" struct gl_client_array; struct gl_context; @@ -64,6 +65,44 @@ _mesa_update_array_max_element(struct gl_client_array *array) } +/** + * Returns a pointer to the vertex attribute data in a client array, + * or the offset into the vertex buffer for an array that resides in + * a vertex buffer. + */ +static inline const GLubyte * +_mesa_vertex_attrib_address(struct gl_vertex_attrib_array *array, + struct gl_vertex_buffer_binding *binding) +{ + return (binding->BufferObj->Name == 0 ? + array->Ptr : + (const GLubyte *)(binding->Offset + array->RelativeOffset)); +} + +/** + * Sets the fields in a gl_client_array to values derived from a + * gl_vertex_attrib_array and a gl_vertex_buffer_binding. + */ +static inline void +_mesa_update_client_array(struct gl_context *ctx, + struct gl_client_array *dst, + struct gl_vertex_attrib_array *src, + struct gl_vertex_buffer_binding *binding) +{ + dst->Size = src->Size; + dst->Type = src->Type; + dst->Format = src->Format; + dst->Stride = src->Stride; + dst->StrideB = binding->Stride; + dst->Ptr = _mesa_vertex_attrib_address(src, binding); + dst->Enabled = src->Enabled; + dst->Normalized = src->Normalized; + dst->Integer = src->Integer; + dst->InstanceDivisor = binding->InstanceDivisor; + dst->_ElementSize = src->_ElementSize; + _mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj); +} + extern void GLAPIENTRY _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); @@ -278,6 +317,15 @@ _mesa_copy_client_array(struct gl_context *ctx, struct gl_client_array *dst, struct gl_client_array *src); +extern void +_mesa_copy_vertex_attrib_array(struct gl_context *ctx, + struct gl_vertex_attrib_array *dst, + const struct gl_vertex_attrib_array *src); + +extern void +_mesa_copy_vertex_buffer_binding(struct gl_context *ctx, + struct gl_vertex_buffer_binding *dst, + const struct gl_vertex_buffer_binding *src); extern void _mesa_print_arrays(struct gl_context *ctx); -- 1.7.10.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev