[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