[Mesa-dev] [PATCH 06/11] mesa: Add ARB_vertex_attrib_binding

Fredrik Höglund fredrik at kde.org
Tue Nov 5 14:50:52 PST 2013


update_array() and update_array_format() are changed to update the new
attrib and binding states, and the client arrays become derived state.

Reviewed-by: Eric Anholt <eric at anholt.net>
---
 src/mesa/main/api_arrayelt.c     |    7 +
 src/mesa/main/api_validate.c     |    6 +-
 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/enable.c           |   36 +--
 src/mesa/main/ffvertex_prog.c    |    2 +-
 src/mesa/main/get.c              |    8 +-
 src/mesa/main/get_hash_params.py |   66 ++---
 src/mesa/main/getstring.c        |   18 +-
 src/mesa/main/mtypes.h           |   50 +++-
 src/mesa/main/state.c            |    3 +
 src/mesa/main/varray.c           |  491 ++++++++++++++++++++++++++++++++++----
 src/mesa/main/varray.h           |   48 ++++
 16 files changed, 691 insertions(+), 125 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/api_validate.c b/src/mesa/main/api_validate.c
index d31f593..f285c97 100644
--- a/src/mesa/main/api_validate.c
+++ b/src/mesa/main/api_validate.c
@@ -120,7 +120,7 @@ check_valid_to_render(struct gl_context *ctx, const char *function)
    case API_OPENGLES:
       /* For OpenGL ES, only draw if we have vertex positions
        */
-      if (!ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POS].Enabled)
+      if (!ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled)
 	 return GL_FALSE;
       break;
 
@@ -141,8 +141,8 @@ check_valid_to_render(struct gl_context *ctx, const char *function)
             /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
              * array [0]).
              */
-            return (ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POS].Enabled ||
-                    ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
+            return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
+                    ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
          }
       }
       break;
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 15ec40c..b27f592 100644
--- a/src/mesa/main/bufferobj.c
+++ b/src/mesa/main/bufferobj.c
@@ -864,8 +864,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 6cdeed1..49dbb55 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -678,6 +678,10 @@ _mesa_init_constants(struct gl_context *ctx)
    ctx->Const.MaxAtomicBufferSize = MAX_ATOMIC_COUNTERS * ATOMIC_COUNTER_SIZE;
    ctx->Const.MaxCombinedAtomicBuffers = MAX_COMBINED_ATOMIC_BUFFERS;
    ctx->Const.MaxCombinedAtomicCounters = MAX_ATOMIC_COUNTERS;
+
+   /* GL_ARB_vertex_attrib_binding */
+   ctx->Const.MaxVertexAttribRelativeOffset = 2047;
+   ctx->Const.MaxVertexAttribBindings = MAX_VERTEX_GENERIC_ATTRIBS;
 }
 
 
diff --git a/src/mesa/main/enable.c b/src/mesa/main/enable.c
index 255e25f..c047f5d 100644
--- a/src/mesa/main/enable.c
+++ b/src/mesa/main/enable.c
@@ -69,40 +69,40 @@ client_state(struct gl_context *ctx, GLenum cap, GLboolean state)
 
    switch (cap) {
       case GL_VERTEX_ARRAY:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_POS].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled;
          flag = VERT_BIT_POS;
          break;
       case GL_NORMAL_ARRAY:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled;
          flag = VERT_BIT_NORMAL;
          break;
       case GL_COLOR_ARRAY:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled;
          flag = VERT_BIT_COLOR0;
          break;
       case GL_INDEX_ARRAY:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled;
          flag = VERT_BIT_COLOR_INDEX;
          break;
       case GL_TEXTURE_COORD_ARRAY:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].Enabled;
          flag = VERT_BIT_TEX(ctx->Array.ActiveTexture);
          break;
       case GL_EDGE_FLAG_ARRAY:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled;
          flag = VERT_BIT_EDGEFLAG;
          break;
       case GL_FOG_COORDINATE_ARRAY_EXT:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_FOG].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled;
          flag = VERT_BIT_FOG;
          break;
       case GL_SECONDARY_COLOR_ARRAY_EXT:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR1].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled;
          flag = VERT_BIT_COLOR1;
          break;
 
       case GL_POINT_SIZE_ARRAY_OES:
-         var = &arrayObj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled;
+         var = &arrayObj->VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled;
          flag = VERT_BIT_POINT_SIZE;
          break;
 
@@ -1417,41 +1417,41 @@ _mesa_IsEnabled( GLenum cap )
       case GL_VERTEX_ARRAY:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POS].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled;
       case GL_NORMAL_ARRAY:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled;
       case GL_COLOR_ARRAY:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled;
       case GL_INDEX_ARRAY:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_enum_error;
          return ctx->Array.ArrayObj->
-            _VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled;
+            VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled;
       case GL_TEXTURE_COORD_ARRAY:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_enum_error;
          return ctx->Array.ArrayObj->
-            _VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].Enabled;
+            VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].Enabled;
       case GL_EDGE_FLAG_ARRAY:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled;
       case GL_FOG_COORDINATE_ARRAY_EXT:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_FOG].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled;
       case GL_SECONDARY_COLOR_ARRAY_EXT:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_COLOR1].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled;
       case GL_POINT_SIZE_ARRAY_OES:
          if (ctx->API != API_OPENGLES)
             goto invalid_enum_error;
-         return ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled;
+         return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled;
 
       /* GL_ARB_texture_cube_map */
       case GL_TEXTURE_CUBE_MAP_ARB:
diff --git a/src/mesa/main/ffvertex_prog.c b/src/mesa/main/ffvertex_prog.c
index 08665c6..be6ac0f 100644
--- a/src/mesa/main/ffvertex_prog.c
+++ b/src/mesa/main/ffvertex_prog.c
@@ -228,7 +228,7 @@ static void make_state_key( struct gl_context *ctx, struct state_key *key )
    if (ctx->Point._Attenuated)
       key->point_attenuated = 1;
 
-   if (ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled)
+   if (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled)
       key->point_array = 1;
 
    if (ctx->Texture._TexGenEnabled ||
diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
index d41e73e..a0dd7cf 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -550,7 +550,7 @@ static void
 find_custom_value(struct gl_context *ctx, const struct value_desc *d, union value *v)
 {
    struct gl_buffer_object **buffer_obj;
-   struct gl_client_array *array;
+   struct gl_vertex_attrib_array *array;
    GLuint unit, *p;
 
    switch (d->pname) {
@@ -629,7 +629,7 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
    case GL_TEXTURE_COORD_ARRAY_SIZE:
    case GL_TEXTURE_COORD_ARRAY_TYPE:
    case GL_TEXTURE_COORD_ARRAY_STRIDE:
-      array = &ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)];
+      array = &ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)];
       v->value_int = *(GLuint *) ((char *) array + d->offset);
       break;
 
@@ -775,7 +775,7 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
       break;
    case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB:
       v->value_int =
-	 ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].BufferObj->Name;
+	 ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_TEX(ctx->Array.ActiveTexture)].BufferObj->Name;
       break;
    case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB:
       v->value_int = ctx->Array.ArrayObj->ElementArrayBufferObj->Name;
@@ -819,7 +819,7 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
 	 ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0;
       break;
    case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
-      v->value_int = ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE].BufferObj->Name;
+      v->value_int = ctx->Array.ArrayObj->VertexBinding[VERT_ATTRIB_POINT_SIZE].BufferObj->Name;
       break;
 
    case GL_FOG_COLOR:
diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py
index cc0c5cd..5ecfbbc 100644
--- a/src/mesa/main/get_hash_params.py
+++ b/src/mesa/main/get_hash_params.py
@@ -191,17 +191,17 @@ descriptor=[
   [ "TEXTURE_2D", "LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA" ],
   [ "TEXTURE_MATRIX", "LOC_CUSTOM, TYPE_MATRIX, 0, extra_valid_texture_unit" ],
   [ "TEXTURE_STACK_DEPTH", "LOC_CUSTOM, TYPE_INT, 0, extra_valid_texture_unit" ],
-  [ "VERTEX_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_POS].Enabled), NO_EXTRA" ],
-  [ "VERTEX_ARRAY_SIZE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_POS].Size), NO_EXTRA" ],
-  [ "VERTEX_ARRAY_TYPE", "ARRAY_ENUM(_VertexAttrib[VERT_ATTRIB_POS].Type), NO_EXTRA" ],
-  [ "VERTEX_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_POS].Stride), NO_EXTRA" ],
-  [ "NORMAL_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_NORMAL].Enabled), NO_EXTRA" ],
-  [ "NORMAL_ARRAY_TYPE", "ARRAY_ENUM(_VertexAttrib[VERT_ATTRIB_NORMAL].Type), NO_EXTRA" ],
-  [ "NORMAL_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_NORMAL].Stride), NO_EXTRA" ],
-  [ "COLOR_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_COLOR0].Enabled), NO_EXTRA" ],
-  [ "COLOR_ARRAY_SIZE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_COLOR0].Size), NO_EXTRA" ],
-  [ "COLOR_ARRAY_TYPE", "ARRAY_ENUM(_VertexAttrib[VERT_ATTRIB_COLOR0].Type), NO_EXTRA" ],
-  [ "COLOR_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_COLOR0].Stride), NO_EXTRA" ],
+  [ "VERTEX_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_POS].Enabled), NO_EXTRA" ],
+  [ "VERTEX_ARRAY_SIZE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_POS].Size), NO_EXTRA" ],
+  [ "VERTEX_ARRAY_TYPE", "ARRAY_ENUM(VertexAttrib[VERT_ATTRIB_POS].Type), NO_EXTRA" ],
+  [ "VERTEX_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_POS].Stride), NO_EXTRA" ],
+  [ "NORMAL_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_NORMAL].Enabled), NO_EXTRA" ],
+  [ "NORMAL_ARRAY_TYPE", "ARRAY_ENUM(VertexAttrib[VERT_ATTRIB_NORMAL].Type), NO_EXTRA" ],
+  [ "NORMAL_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_NORMAL].Stride), NO_EXTRA" ],
+  [ "COLOR_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_COLOR0].Enabled), NO_EXTRA" ],
+  [ "COLOR_ARRAY_SIZE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_COLOR0].Size), NO_EXTRA" ],
+  [ "COLOR_ARRAY_TYPE", "ARRAY_ENUM(VertexAttrib[VERT_ATTRIB_COLOR0].Type), NO_EXTRA" ],
+  [ "COLOR_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_COLOR0].Stride), NO_EXTRA" ],
   [ "TEXTURE_COORD_ARRAY", "LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Enabled), NO_EXTRA" ],
   [ "TEXTURE_COORD_ARRAY_SIZE", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_client_array, Size), NO_EXTRA" ],
   [ "TEXTURE_COORD_ARRAY_TYPE", "LOC_CUSTOM, TYPE_ENUM, offsetof(struct gl_client_array, Type), NO_EXTRA" ],
@@ -221,9 +221,9 @@ descriptor=[
   [ "SAMPLE_ALPHA_TO_ONE_ARB", "CONTEXT_BOOL(Multisample.SampleAlphaToOne), NO_EXTRA" ],
 
 # GL_ARB_vertex_buffer_object
-  [ "VERTEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_POS].BufferObj), NO_EXTRA" ],
-  [ "NORMAL_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_NORMAL].BufferObj), NO_EXTRA" ],
-  [ "COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_COLOR0].BufferObj), NO_EXTRA" ],
+  [ "VERTEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_POS].BufferObj), NO_EXTRA" ],
+  [ "NORMAL_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_NORMAL].BufferObj), NO_EXTRA" ],
+  [ "COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_COLOR0].BufferObj), NO_EXTRA" ],
   [ "TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA" ],
 
 # GL_OES_point_sprite
@@ -233,9 +233,9 @@ descriptor=[
 
 { "apis": ["GLES"], "params": [
 # OES_point_size_array
-  [ "POINT_SIZE_ARRAY_OES", "ARRAY_FIELD(_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled, TYPE_BOOLEAN)" ],
-  [ "POINT_SIZE_ARRAY_TYPE_OES", "ARRAY_FIELD(_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Type, TYPE_ENUM)" ],
-  [ "POINT_SIZE_ARRAY_STRIDE_OES", "ARRAY_FIELD(_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Stride, TYPE_INT)" ],
+  [ "POINT_SIZE_ARRAY_OES", "ARRAY_FIELD(VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled, TYPE_BOOLEAN)" ],
+  [ "POINT_SIZE_ARRAY_TYPE_OES", "ARRAY_FIELD(VertexAttrib[VERT_ATTRIB_POINT_SIZE].Type, TYPE_ENUM)" ],
+  [ "POINT_SIZE_ARRAY_STRIDE_OES", "ARRAY_FIELD(VertexAttrib[VERT_ATTRIB_POINT_SIZE].Stride, TYPE_INT)" ],
   [ "POINT_SIZE_ARRAY_BUFFER_BINDING_OES", "LOC_CUSTOM, TYPE_INT, 0" ],
 ]},
 
@@ -521,13 +521,13 @@ descriptor=[
   [ "VERTEX_ARRAY_COUNT_EXT", "CONST(0), NO_EXTRA" ],
   [ "NORMAL_ARRAY_COUNT_EXT", "CONST(0), NO_EXTRA" ],
   [ "COLOR_ARRAY_COUNT_EXT", "CONST(0), NO_EXTRA" ],
-  [ "INDEX_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled), NO_EXTRA" ],
-  [ "INDEX_ARRAY_TYPE", "ARRAY_ENUM(_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Type), NO_EXTRA" ],
-  [ "INDEX_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Stride), NO_EXTRA" ],
+  [ "INDEX_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled), NO_EXTRA" ],
+  [ "INDEX_ARRAY_TYPE", "ARRAY_ENUM(VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Type), NO_EXTRA" ],
+  [ "INDEX_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Stride), NO_EXTRA" ],
   [ "INDEX_ARRAY_COUNT_EXT", "CONST(0), NO_EXTRA" ],
   [ "TEXTURE_COORD_ARRAY_COUNT_EXT", "CONST(0), NO_EXTRA" ],
-  [ "EDGE_FLAG_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled), NO_EXTRA" ],
-  [ "EDGE_FLAG_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_EDGEFLAG].Stride), NO_EXTRA" ],
+  [ "EDGE_FLAG_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled), NO_EXTRA" ],
+  [ "EDGE_FLAG_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_EDGEFLAG].Stride), NO_EXTRA" ],
   [ "EDGE_FLAG_ARRAY_COUNT_EXT", "CONST(0), NO_EXTRA" ],
 
 # GL_ARB_texture_compression
@@ -545,16 +545,16 @@ descriptor=[
 # GL_EXT_secondary_color
   [ "COLOR_SUM", "CONTEXT_BOOL(Fog.ColorSumEnabled), extra_ARB_vertex_program" ],
   [ "CURRENT_SECONDARY_COLOR", "CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR1][0], TYPE_FLOATN_4), extra_flush_current" ],
-  [ "SECONDARY_COLOR_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_COLOR1].Enabled), NO_EXTRA" ],
-  [ "SECONDARY_COLOR_ARRAY_TYPE", "ARRAY_ENUM(_VertexAttrib[VERT_ATTRIB_COLOR1].Type), NO_EXTRA" ],
-  [ "SECONDARY_COLOR_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_COLOR1].Stride), NO_EXTRA" ],
-  [ "SECONDARY_COLOR_ARRAY_SIZE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_COLOR1].Size), NO_EXTRA" ],
+  [ "SECONDARY_COLOR_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_COLOR1].Enabled), NO_EXTRA" ],
+  [ "SECONDARY_COLOR_ARRAY_TYPE", "ARRAY_ENUM(VertexAttrib[VERT_ATTRIB_COLOR1].Type), NO_EXTRA" ],
+  [ "SECONDARY_COLOR_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_COLOR1].Stride), NO_EXTRA" ],
+  [ "SECONDARY_COLOR_ARRAY_SIZE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_COLOR1].Size), NO_EXTRA" ],
 
 # GL_EXT_fog_coord
   [ "CURRENT_FOG_COORDINATE", "CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_FOG][0]), extra_flush_current" ],
-  [ "FOG_COORDINATE_ARRAY", "ARRAY_BOOL(_VertexAttrib[VERT_ATTRIB_FOG].Enabled), NO_EXTRA" ],
-  [ "FOG_COORDINATE_ARRAY_TYPE", "ARRAY_ENUM(_VertexAttrib[VERT_ATTRIB_FOG].Type), NO_EXTRA" ],
-  [ "FOG_COORDINATE_ARRAY_STRIDE", "ARRAY_INT(_VertexAttrib[VERT_ATTRIB_FOG].Stride), NO_EXTRA" ],
+  [ "FOG_COORDINATE_ARRAY", "ARRAY_BOOL(VertexAttrib[VERT_ATTRIB_FOG].Enabled), NO_EXTRA" ],
+  [ "FOG_COORDINATE_ARRAY_TYPE", "ARRAY_ENUM(VertexAttrib[VERT_ATTRIB_FOG].Type), NO_EXTRA" ],
+  [ "FOG_COORDINATE_ARRAY_STRIDE", "ARRAY_INT(VertexAttrib[VERT_ATTRIB_FOG].Stride), NO_EXTRA" ],
   [ "FOG_COORDINATE_SOURCE", "CONTEXT_ENUM(Fog.FogCoordinateSource), NO_EXTRA" ],
 
 # GL_NV_fog_distance
@@ -585,10 +585,10 @@ descriptor=[
   [ "PRIMITIVE_RESTART_INDEX_NV", "CONTEXT_INT(Array.RestartIndex), extra_NV_primitive_restart" ],
 
 # GL_ARB_vertex_buffer_object
-  [ "INDEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_COLOR_INDEX].BufferObj), NO_EXTRA" ],
-  [ "EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_EDGEFLAG].BufferObj), NO_EXTRA" ],
-  [ "SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_COLOR1].BufferObj), NO_EXTRA" ],
-  [ "FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, _VertexAttrib[VERT_ATTRIB_FOG].BufferObj), NO_EXTRA" ],
+  [ "INDEX_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_COLOR_INDEX].BufferObj), NO_EXTRA" ],
+  [ "EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_EDGEFLAG].BufferObj), NO_EXTRA" ],
+  [ "SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_COLOR1].BufferObj), NO_EXTRA" ],
+  [ "FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB", "LOC_CUSTOM, TYPE_INT, offsetof(struct gl_array_object, VertexBinding[VERT_ATTRIB_FOG].BufferObj), NO_EXTRA" ],
 
 # GL_ARB_vertex_program
 # == GL_VERTEX_PROGRAM_NV
diff --git a/src/mesa/main/getstring.c b/src/mesa/main/getstring.c
index 60ffaa1..0e07542 100644
--- a/src/mesa/main/getstring.c
+++ b/src/mesa/main/getstring.c
@@ -202,42 +202,42 @@ _mesa_GetPointerv( GLenum pname, GLvoid **params )
       case GL_VERTEX_ARRAY_POINTER:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POS].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Ptr;
          break;
       case GL_NORMAL_ARRAY_POINTER:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_NORMAL].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Ptr;
          break;
       case GL_COLOR_ARRAY_POINTER:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_COLOR0].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Ptr;
          break;
       case GL_SECONDARY_COLOR_ARRAY_POINTER_EXT:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_COLOR1].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Ptr;
          break;
       case GL_FOG_COORDINATE_ARRAY_POINTER_EXT:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_FOG].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG].Ptr;
          break;
       case GL_INDEX_ARRAY_POINTER:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Ptr;
          break;
       case GL_TEXTURE_COORD_ARRAY_POINTER:
          if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_TEX(clientUnit)].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_TEX(clientUnit)].Ptr;
          break;
       case GL_EDGE_FLAG_ARRAY_POINTER:
          if (ctx->API != API_OPENGL_COMPAT)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Ptr;
          break;
       case GL_FEEDBACK_BUFFER_POINTER:
          if (ctx->API != API_OPENGL_COMPAT)
@@ -252,7 +252,7 @@ _mesa_GetPointerv( GLenum pname, GLvoid **params )
       case GL_POINT_SIZE_ARRAY_POINTER_OES:
          if (ctx->API != API_OPENGLES)
             goto invalid_pname;
-         *params = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE].Ptr;
+         *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POINT_SIZE].Ptr;
          break;
       case GL_DEBUG_CALLBACK_FUNCTION_ARB:
          if (!_mesa_is_desktop_gl(ctx))
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 0fd9c14..3f0e3ea 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1474,6 +1474,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.
  */
@@ -1507,9 +1545,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;
 
@@ -3216,6 +3260,10 @@ struct gl_constants
    GLuint MaxAtomicBufferSize;
    GLuint MaxCombinedAtomicBuffers;
    GLuint MaxCombinedAtomicCounters;
+
+   /** 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 a705b6b..b0e0286 100644
--- a/src/mesa/main/varray.c
+++ b/src/mesa/main/varray.c
@@ -103,19 +103,93 @@ type_to_bit(const struct gl_context *ctx, GLenum type)
 
 
 /**
+ * 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_array_object *arrayObj = ctx->Array.ArrayObj;
+   struct gl_vertex_attrib_array *array = &arrayObj->VertexAttrib[attribIndex];
+
+   if (array->VertexBinding != bindingIndex) {
+      const GLbitfield64 array_bit = VERT_BIT(attribIndex);
+
+      FLUSH_VERTICES(ctx, _NEW_ARRAY);
+
+      arrayObj->VertexBinding[array->VertexBinding]._BoundArrays &= ~array_bit;
+      arrayObj->VertexBinding[bindingIndex]._BoundArrays |= array_bit;
+
+      array->VertexBinding = bindingIndex;
+
+      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_array_object *arrayObj = ctx->Array.ArrayObj;
+   struct gl_vertex_buffer_binding *binding = &arrayObj->VertexBinding[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;
+
+      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_array_object *arrayObj = ctx->Array.ArrayObj;
+   struct gl_vertex_buffer_binding *binding =
+      &arrayObj->VertexBinding[bindingIndex];
+
+   if (binding->InstanceDivisor != divisor) {
+      FLUSH_VERTICES(ctx, _NEW_ARRAY);
+      binding->InstanceDivisor = divisor;
+      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 bool
 update_array_format(struct gl_context *ctx,
@@ -123,9 +197,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 +299,36 @@ update_array_format(struct gl_context *ctx,
       return 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 = &ctx->Array.ArrayObj->VertexAttrib[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 true;
 }
 
@@ -266,7 +358,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 +379,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 +406,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 = &ctx->Array.ArrayObj->VertexAttrib[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 +664,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 +690,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);
    }
@@ -614,16 +709,17 @@ static GLuint
 get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname,
                   const char *caller)
 {
-   const struct gl_client_array *array;
+   const struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+   const struct gl_vertex_attrib_array *array;
 
    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", caller, index);
       return 0;
    }
 
-   ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->_VertexAttrib));
+   ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->VertexAttrib));
 
-   array = &ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)];
+   array = &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)];
 
    switch (pname) {
    case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
@@ -637,7 +733,7 @@ get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname,
    case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
       return array->Normalized;
    case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
-      return array->BufferObj->Name;
+      return arrayObj->VertexBinding[array->VertexBinding].BufferObj->Name;
    case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
       if ((_mesa_is_desktop_gl(ctx)
            && (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4))
@@ -648,7 +744,7 @@ get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname,
    case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB:
       if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_instanced_arrays)
           || _mesa_is_gles3(ctx)) {
-         return array->InstanceDivisor;
+         return arrayObj->VertexBinding[array->VertexBinding].InstanceDivisor;
       }
       goto error;
    default:
@@ -806,7 +902,7 @@ _mesa_GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer)
 
    ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->_VertexAttrib));
 
-   *pointer = (GLvoid *) ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr;
+   *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr;
 }
 
 
@@ -1180,9 +1276,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 +1291,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 +1341,80 @@ 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=%lld < 0)", (long long)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);
+
+      /* From the GL_ARB_vertex_attrib_array spec:
+       *
+       *   "[Core profile only:]
+       *    An INVALID_OPERATION error is generated if buffer is not zero or a
+       *    name returned from a previous call to GenBuffers, or if such a name
+       *    has since been deleted with DeleteBuffers.
+       *
+       * Otherwise, we fall back to the same compat profile behavior as other
+       * object references (automatically gen it).
+       */
+      if (!_mesa_handle_bind_buffer_gen(ctx, GL_ARRAY_BUFFER, buffer,
+                                        &vbo, "glBindVertexBuffer"))
+         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 +1422,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 +1473,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 +1520,136 @@ 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);
+
+   if (!ctx->Extensions.ARB_instanced_arrays) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexBindingDivisor()");
+      return;
+   }
+
+   /* 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 +1676,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