[Mesa-dev] [PATCH 05/11] mesa: Add ARB_vertex_attrib_binding
Fredrik Höglund
fredrik at kde.org
Mon Oct 28 23:33:48 CET 2013
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
More information about the mesa-dev
mailing list