mesa: add KHR_no_error support to glPrimitiveRestartIndex()
[mesa.git] / src / mesa / main / varray.c
index 4b506ea39c4a48010396daa5020b0105268b701f..993472448918da6d19fcda98eaea65bef067eec7 100644 (file)
@@ -102,6 +102,7 @@ type_to_bit(const struct gl_context *ctx, GLenum type)
    case GL_UNSIGNED_INT:
       return UNSIGNED_INT_BIT;
    case GL_HALF_FLOAT:
+   case GL_HALF_FLOAT_OES:
       if (ctx->Extensions.ARB_half_float_vertex)
          return HALF_BIT;
       else
@@ -125,24 +126,29 @@ type_to_bit(const struct gl_context *ctx, GLenum type)
 
 
 /**
- * Sets the VertexBinding field in the vertex attribute given by attribIndex.
+ * Sets the BufferBindingIndex field for the vertex attribute given by
+ * attribIndex.
  */
 static void
-vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex,
+vertex_attrib_binding(struct gl_context *ctx,
+                      struct gl_vertex_array_object *vao,
+                      GLuint attribIndex,
                       GLuint bindingIndex)
 {
-   struct gl_vertex_array_object *vao = ctx->Array.VAO;
-   struct gl_vertex_attrib_array *array = &vao->VertexAttrib[attribIndex];
+   struct gl_array_attributes *array = &vao->VertexAttrib[attribIndex];
 
-   if (array->VertexBinding != bindingIndex) {
+   if (array->BufferBindingIndex != bindingIndex) {
       const GLbitfield64 array_bit = VERT_BIT(attribIndex);
 
+      if (_mesa_is_bufferobj(vao->BufferBinding[bindingIndex].BufferObj))
+         vao->VertexAttribBufferMask |= array_bit;
+
       FLUSH_VERTICES(ctx, _NEW_ARRAY);
 
-      vao->VertexBinding[array->VertexBinding]._BoundArrays &= ~array_bit;
-      vao->VertexBinding[bindingIndex]._BoundArrays |= array_bit;
+      vao->BufferBinding[array->BufferBindingIndex]._BoundArrays &= ~array_bit;
+      vao->BufferBinding[bindingIndex]._BoundArrays |= array_bit;
 
-      array->VertexBinding = bindingIndex;
+      array->BufferBindingIndex = bindingIndex;
 
       vao->NewArrays |= array_bit;
    }
@@ -153,14 +159,14 @@ vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex,
  * 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,
-                   struct gl_vertex_array_object *vao,
-                   GLuint index,
-                   struct gl_buffer_object *vbo,
-                   GLintptr offset, GLsizei stride)
+void
+_mesa_bind_vertex_buffer(struct gl_context *ctx,
+                         struct gl_vertex_array_object *vao,
+                         GLuint index,
+                         struct gl_buffer_object *vbo,
+                         GLintptr offset, GLsizei stride)
 {
-   struct gl_vertex_buffer_binding *binding = &vao->VertexBinding[index];
+   struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[index];
 
    if (binding->BufferObj != vbo ||
        binding->Offset != offset ||
@@ -173,6 +179,11 @@ bind_vertex_buffer(struct gl_context *ctx,
       binding->Offset = offset;
       binding->Stride = stride;
 
+      if (!_mesa_is_bufferobj(vbo))
+         vao->VertexAttribBufferMask &= ~binding->_BoundArrays;
+      else
+         vao->VertexAttribBufferMask |= binding->_BoundArrays;
+
       vao->NewArrays |= binding->_BoundArrays;
    }
 }
@@ -183,12 +194,13 @@ bind_vertex_buffer(struct gl_context *ctx,
  * given by bindingIndex.
  */
 static void
-vertex_binding_divisor(struct gl_context *ctx, GLuint bindingIndex,
+vertex_binding_divisor(struct gl_context *ctx,
+                       struct gl_vertex_array_object *vao,
+                       GLuint bindingIndex,
                        GLuint divisor)
 {
-   struct gl_vertex_array_object *vao = ctx->Array.VAO;
    struct gl_vertex_buffer_binding *binding =
-      &vao->VertexBinding[bindingIndex];
+      &vao->BufferBinding[bindingIndex];
 
    if (binding->InstanceDivisor != divisor) {
       FLUSH_VERTICES(ctx, _NEW_ARRAY);
@@ -223,8 +235,10 @@ get_legal_types_mask(const struct gl_context *ctx)
          legalTypesMask &= ~(UNSIGNED_INT_BIT |
                              INT_BIT |
                              UNSIGNED_INT_2_10_10_10_REV_BIT |
-                             INT_2_10_10_10_REV_BIT |
-                             HALF_BIT);
+                             INT_2_10_10_10_REV_BIT);
+
+         if (!_mesa_has_OES_vertex_half_float(ctx))
+            legalTypesMask &= ~HALF_BIT;
       }
    }
    else {
@@ -244,11 +258,71 @@ get_legal_types_mask(const struct gl_context *ctx)
    return legalTypesMask;
 }
 
+static GLenum
+get_array_format(const struct gl_context *ctx, GLint sizeMax, GLint *size)
+{
+   GLenum format = GL_RGBA;
+
+   /* Do size parameter checking.
+    * If sizeMax = BGRA_OR_4 it means that size = GL_BGRA is legal and
+    * must be handled specially.
+    */
+   if (ctx->Extensions.EXT_vertex_array_bgra && sizeMax == BGRA_OR_4 &&
+       *size == GL_BGRA) {
+      format = GL_BGRA;
+      *size = 4;
+   }
+
+   return format;
+}
+
+
+/**
+ * \param attrib         The index of the attribute array
+ * \param size           Components per element (1, 2, 3 or 4)
+ * \param type           Datatype of each component (GL_FLOAT, GL_INT, etc)
+ * \param format         Either GL_RGBA or GL_BGRA.
+ * \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 doubles        Double values not reduced to floats
+ * \param relativeOffset Offset of the first element relative to the binding
+ *                       offset.
+ * \param flush_verties  Should \c FLUSH_VERTICES be invoked before updating
+ *                       state?
+ */
+void
+_mesa_update_array_format(struct gl_context *ctx,
+                          struct gl_vertex_array_object *vao,
+                          GLuint attrib, GLint size, GLenum type,
+                          GLenum format, GLboolean normalized,
+                          GLboolean integer, GLboolean doubles,
+                          GLuint relativeOffset)
+{
+   struct gl_array_attributes *const array = &vao->VertexAttrib[attrib];
+   GLint elementSize;
+
+   assert(size <= 4);
+
+   elementSize = _mesa_bytes_per_vertex_attrib(size, type);
+   assert(elementSize != -1);
+
+   array->Size = size;
+   array->Type = type;
+   array->Format = format;
+   array->Normalized = normalized;
+   array->Integer = integer;
+   array->Doubles = doubles;
+   array->RelativeOffset = relativeOffset;
+   array->_ElementSize = elementSize;
+
+   vao->NewArrays |= VERT_BIT(attrib);
+   ctx->NewState |= _NEW_ARRAY;
+}
 
 /**
- * Does error checking and updates the format in an attrib array.
+ * Does error checking of the format in an attrib array.
  *
- * Called by update_array() and VertexAttrib*Format().
+ * Called by *Pointer() and VertexAttrib*Format().
  *
  * \param func         Name of calling function used for error reporting
  * \param attrib       The index of the attribute array
@@ -261,21 +335,21 @@ get_legal_types_mask(const struct gl_context *ctx)
  * \param integer      Integer-valued values (will not be normalized to [-1, 1])
  * \param doubles      Double values not reduced to floats
  * \param relativeOffset Offset of the first element relative to the binding offset.
+ * \return bool True if validation is successful, False otherwise.
  */
 static bool
-update_array_format(struct gl_context *ctx,
-                    const char *func,
-                    struct gl_vertex_array_object *vao,
-                    GLuint attrib, GLbitfield legalTypesMask,
-                    GLint sizeMin, GLint sizeMax,
-                    GLint size, GLenum type,
-                    GLboolean normalized, GLboolean integer, GLboolean doubles,
-                    GLuint relativeOffset)
-{
-   struct gl_vertex_attrib_array *array;
+validate_array_format(struct gl_context *ctx, const char *func,
+                      struct gl_vertex_array_object *vao,
+                      GLuint attrib, GLbitfield legalTypesMask,
+                      GLint sizeMin, GLint sizeMax,
+                      GLint size, GLenum type, GLboolean normalized,
+                      GLboolean integer, GLboolean doubles,
+                      GLuint relativeOffset, GLenum format)
+{
    GLbitfield typeBit;
-   GLint elementSize;
-   GLenum format = GL_RGBA;
+
+   /* at most, one of these bools can be true */
+   assert((int) normalized + (int) integer + (int) doubles <= 1);
 
    if (ctx->Array.LegalTypesMask == 0 || ctx->Array.LegalTypesMaskAPI != ctx->API) {
       /* Compute the LegalTypesMask only once, unless the context API has
@@ -298,17 +372,11 @@ update_array_format(struct gl_context *ctx,
    typeBit = type_to_bit(ctx, type);
    if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) {
       _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)",
-                  func, _mesa_lookup_enum_by_nr(type));
+                  func, _mesa_enum_to_string(type));
       return false;
    }
 
-   /* Do size parameter checking.
-    * If sizeMax = BGRA_OR_4 it means that size = GL_BGRA is legal and
-    * must be handled specially.
-    */
-   if (ctx->Extensions.EXT_vertex_array_bgra &&
-       sizeMax == BGRA_OR_4 &&
-       size == GL_BGRA) {
+   if (format == GL_BGRA) {
       /* 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
@@ -331,7 +399,7 @@ update_array_format(struct gl_context *ctx,
 
       if (bgra_error) {
          _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=GL_BGRA and type=%s)",
-                     func, _mesa_lookup_enum_by_nr(type));
+                     func, _mesa_enum_to_string(type));
          return false;
       }
 
@@ -340,9 +408,6 @@ update_array_format(struct gl_context *ctx,
                      "%s(size=GL_BGRA and normalized=GL_FALSE)", func);
          return false;
       }
-
-      format = GL_BGRA;
-      size = 4;
    }
    else if (size < sizeMin || size > sizeMax || size > 4) {
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size);
@@ -375,31 +440,11 @@ update_array_format(struct gl_context *ctx,
       return false;
    }
 
-   assert(size <= 4);
-
-   elementSize = _mesa_bytes_per_vertex_attrib(size, type);
-   assert(elementSize != -1);
-
-   array = &vao->VertexAttrib[attrib];
-   array->Size = size;
-   array->Type = type;
-   array->Format = format;
-   array->Normalized = normalized;
-   array->Integer = integer;
-   array->Doubles = doubles;
-   array->RelativeOffset = relativeOffset;
-   array->_ElementSize = elementSize;
-
-   vao->NewArrays |= VERT_BIT(attrib);
-   ctx->NewState |= _NEW_ARRAY;
-
    return true;
 }
 
-
 /**
- * Do error checking and update state for glVertex/Color/TexCoord/...Pointer
- * functions.
+ * Do error checking for glVertex/Color/TexCoord/...Pointer functions.
  *
  * \param func  name of calling function used for error reporting
  * \param attrib  the attribute array index to update
@@ -415,16 +460,14 @@ update_array_format(struct gl_context *ctx,
  * \param ptr  the address (or offset inside VBO) of the array data
  */
 static void
-update_array(struct gl_context *ctx,
-             const char *func,
-             GLuint attrib, GLbitfield legalTypesMask,
-             GLint sizeMin, GLint sizeMax,
-             GLint size, GLenum type, GLsizei stride,
-             GLboolean normalized, GLboolean integer, GLboolean doubles,
-             const GLvoid *ptr)
+validate_array(struct gl_context *ctx, const char *func,
+               GLuint attrib, GLbitfield legalTypesMask,
+               GLint sizeMin, GLint sizeMax,
+               GLint size, GLenum type, GLsizei stride,
+               GLboolean normalized, GLboolean integer, GLboolean doubles,
+               const GLvoid *ptr)
 {
-   struct gl_vertex_attrib_array *array;
-   GLsizei effectiveStride;
+   struct gl_vertex_array_object *vao = ctx->Array.VAO;
 
    /* Page 407 (page 423 of the PDF) of the OpenGL 3.0 spec says:
     *
@@ -436,8 +479,7 @@ update_array(struct gl_context *ctx,
     *
     * The check for VBOs is handled below.
     */
-   if (ctx->API == API_OPENGL_CORE
-       && (ctx->Array.VAO == ctx->Array.DefaultVAO)) {
+   if (ctx->API == API_OPENGL_CORE && (vao == ctx->Array.DefaultVAO)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no array object bound)",
                   func);
       return;
@@ -467,30 +509,83 @@ update_array(struct gl_context *ctx,
     *       to the ARRAY_BUFFER buffer object binding point (see section
     *       2.9.6), and the pointer argument is not NULL."
     */
-   if (ptr != NULL && ctx->Array.VAO->ARBsemantics &&
+   if (ptr != NULL && vao != ctx->Array.DefaultVAO &&
        !_mesa_is_bufferobj(ctx->Array.ArrayBufferObj)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-VBO array)", func);
       return;
    }
+}
 
-   if (!update_array_format(ctx, func, ctx->Array.VAO, attrib,
-                            legalTypesMask, sizeMin, sizeMax,
-                            size, type, normalized, integer, doubles, 0)) {
-      return;
-   }
+
+static bool
+validate_array_and_format(struct gl_context *ctx, const char *func,
+                          GLuint attrib, GLbitfield legalTypes,
+                          GLint sizeMin, GLint sizeMax,
+                          GLint size, GLenum type, GLsizei stride,
+                          GLboolean normalized, GLboolean integer,
+                          GLboolean doubles, GLenum format, const GLvoid *ptr,
+                          struct gl_vertex_array_object *vao)
+{
+   validate_array(ctx, func, attrib, legalTypes, sizeMin, sizeMax, size,
+                  type, stride, normalized, integer, doubles, ptr);
+
+   return validate_array_format(ctx, func, vao, attrib, legalTypes, sizeMin,
+                                sizeMax, size, type, normalized, integer,
+                                doubles, 0, format);
+}
+
+
+/**
+ * Update state for glVertex/Color/TexCoord/...Pointer functions.
+ *
+ * \param attrib  the attribute array index to update
+ * \param format  Either GL_RGBA or GL_BGRA.
+ * \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 stride  stride between elements, in elements
+ * \param normalized  are integer types converted to floats in [-1, 1]?
+ * \param integer  integer-valued values (will not be normalized to [-1,1])
+ * \param doubles  Double values not reduced to floats
+ * \param ptr  the address (or offset inside VBO) of the array data
+ */
+static void
+update_array(struct gl_context *ctx,
+             GLuint attrib, GLenum format,
+             GLint sizeMax,
+             GLint size, GLenum type, GLsizei stride,
+             GLboolean normalized, GLboolean integer, GLboolean doubles,
+             const GLvoid *ptr)
+{
+   struct gl_vertex_array_object *vao = ctx->Array.VAO;
+
+   _mesa_update_array_format(ctx, vao, attrib, size, type, format,
+                             normalized, integer, doubles, 0);
 
    /* Reset the vertex attrib binding */
-   vertex_attrib_binding(ctx, attrib, attrib);
+   vertex_attrib_binding(ctx, vao, attrib, attrib);
 
    /* The Stride and Ptr fields are not set by update_array_format() */
-   array = &ctx->Array.VAO->VertexAttrib[attrib];
+   struct gl_array_attributes *array = &vao->VertexAttrib[attrib];
    array->Stride = stride;
-   array->Ptr = (const GLvoid *) ptr;
+   array->Ptr = ptr;
 
    /* Update the vertex buffer binding */
-   effectiveStride = stride != 0 ? stride : array->_ElementSize;
-   bind_vertex_buffer(ctx, ctx->Array.VAO, attrib, ctx->Array.ArrayBufferObj,
-                      (GLintptr) ptr, effectiveStride);
+   GLsizei effectiveStride = stride != 0 ? stride : array->_ElementSize;
+   _mesa_bind_vertex_buffer(ctx, vao, attrib,
+                            ctx->Array.ArrayBufferObj, (GLintptr) ptr,
+                            effectiveStride);
+}
+
+void GLAPIENTRY
+_mesa_VertexPointer_no_error(GLint size, GLenum type, GLsizei stride,
+                             const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   FLUSH_VERTICES(ctx, 0);
+
+   update_array(ctx, VERT_ATTRIB_POS, GL_RGBA, 4, size, type, stride,
+                GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
@@ -498,6 +593,10 @@ void GLAPIENTRY
 _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
+
+   FLUSH_VERTICES(ctx, 0);
+
+   GLenum format = GL_RGBA;
    GLbitfield legalTypes = (ctx->API == API_OPENGLES)
       ? (BYTE_BIT | SHORT_BIT | FLOAT_BIT | FIXED_ES_BIT)
       : (SHORT_BIT | INT_BIT | FLOAT_BIT |
@@ -505,11 +604,25 @@ _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
          UNSIGNED_INT_2_10_10_10_REV_BIT |
          INT_2_10_10_10_REV_BIT);
 
+   if (!validate_array_and_format(ctx, "glVertexPointer", VERT_ATTRIB_POS,
+                                  legalTypes, 2, 4, size, type, stride,
+                                  GL_FALSE, GL_FALSE, GL_FALSE, format,
+                                  ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_POS, format, 4, size, type, stride,
+                GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_NormalPointer_no_error(GLenum type, GLsizei stride, const GLvoid *ptr )
+{
+   GET_CURRENT_CONTEXT(ctx);
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glVertexPointer", VERT_ATTRIB_POS,
-                legalTypes, 2, 4,
-                size, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+   update_array(ctx, VERT_ATTRIB_NORMAL, GL_RGBA, 3, 3, type, stride, GL_TRUE,
+                GL_FALSE, GL_FALSE, ptr);
 }
 
 
@@ -517,6 +630,10 @@ void GLAPIENTRY
 _mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr )
 {
    GET_CURRENT_CONTEXT(ctx);
+
+   FLUSH_VERTICES(ctx, 0);
+
+   GLenum format = GL_RGBA;
    const GLbitfield legalTypes = (ctx->API == API_OPENGLES)
       ? (BYTE_BIT | SHORT_BIT | FLOAT_BIT | FIXED_ES_BIT)
       : (BYTE_BIT | SHORT_BIT | INT_BIT |
@@ -524,11 +641,27 @@ _mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr )
          UNSIGNED_INT_2_10_10_10_REV_BIT |
          INT_2_10_10_10_REV_BIT);
 
+   if (!validate_array_and_format(ctx, "glNormalPointer",
+                                  VERT_ATTRIB_NORMAL, legalTypes, 3, 3, 3,
+                                  type, stride, GL_TRUE, GL_FALSE,
+                                  GL_FALSE, format, ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_NORMAL, format, 3, 3, type, stride, GL_TRUE,
+                GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_ColorPointer_no_error(GLint size, GLenum type, GLsizei stride,
+                            const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glNormalPointer", VERT_ATTRIB_NORMAL,
-                legalTypes, 3, 3,
-                3, type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
+   GLenum format = get_array_format(ctx, BGRA_OR_4, &size);
+   update_array(ctx, VERT_ATTRIB_COLOR0, format, BGRA_OR_4, size,
+                type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
@@ -536,6 +669,11 @@ void GLAPIENTRY
 _mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
+   const GLint sizeMin = (ctx->API == API_OPENGLES) ? 4 : 3;
+
+   FLUSH_VERTICES(ctx, 0);
+
+   GLenum format = get_array_format(ctx, BGRA_OR_4, &size);
    const GLbitfield legalTypes = (ctx->API == API_OPENGLES)
       ? (UNSIGNED_BYTE_BIT | HALF_BIT | FLOAT_BIT | FIXED_ES_BIT)
       : (BYTE_BIT | UNSIGNED_BYTE_BIT |
@@ -544,42 +682,95 @@ _mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
          HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
          UNSIGNED_INT_2_10_10_10_REV_BIT |
          INT_2_10_10_10_REV_BIT);
-   const GLint sizeMin = (ctx->API == API_OPENGLES) ? 4 : 3;
 
+   if (!validate_array_and_format(ctx, "glColorPointer",
+                                  VERT_ATTRIB_COLOR0, legalTypes, sizeMin,
+                                  BGRA_OR_4, size, type, stride, GL_TRUE,
+                                  GL_FALSE, GL_FALSE, format, ptr,
+                                  ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_COLOR0, format, BGRA_OR_4, size,
+                type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_FogCoordPointer_no_error(GLenum type, GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glColorPointer", VERT_ATTRIB_COLOR0,
-                legalTypes, sizeMin, BGRA_OR_4,
-                size, type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
+   update_array(ctx, VERT_ATTRIB_FOG, GL_RGBA, 1, 1, type, stride, GL_FALSE,
+                GL_FALSE, GL_FALSE, ptr);
 }
 
 
 void GLAPIENTRY
 _mesa_FogCoordPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
-   const GLbitfield legalTypes = (HALF_BIT | FLOAT_BIT | DOUBLE_BIT);
    GET_CURRENT_CONTEXT(ctx);
 
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glFogCoordPointer", VERT_ATTRIB_FOG,
-                legalTypes, 1, 1,
-                1, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+   GLenum format = GL_RGBA;
+   const GLbitfield legalTypes = (HALF_BIT | FLOAT_BIT | DOUBLE_BIT);
+
+   if (!validate_array_and_format(ctx, "glFogCoordPointer",
+                                  VERT_ATTRIB_FOG, legalTypes, 1, 1, 1,
+                                  type, stride, GL_FALSE, GL_FALSE,
+                                  GL_FALSE, format, ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_FOG, format, 1, 1, type, stride, GL_FALSE,
+                GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_IndexPointer_no_error(GLenum type, GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   FLUSH_VERTICES(ctx, 0);
+
+   update_array(ctx, VERT_ATTRIB_COLOR_INDEX, GL_RGBA, 1, 1, type, stride,
+                GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
 void GLAPIENTRY
 _mesa_IndexPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
-   const GLbitfield legalTypes = (UNSIGNED_BYTE_BIT | SHORT_BIT | INT_BIT |
-                                  FLOAT_BIT | DOUBLE_BIT);
    GET_CURRENT_CONTEXT(ctx);
 
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glIndexPointer", VERT_ATTRIB_COLOR_INDEX,
-                legalTypes, 1, 1,
-                1, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+   GLenum format = GL_RGBA;
+   const GLbitfield legalTypes = (UNSIGNED_BYTE_BIT | SHORT_BIT | INT_BIT |
+                                     FLOAT_BIT | DOUBLE_BIT);
+
+   if (!validate_array_and_format(ctx, "glIndexPointer",
+                                  VERT_ATTRIB_COLOR_INDEX,
+                                  legalTypes, 1, 1, 1, type, stride,
+                                  GL_FALSE, GL_FALSE, GL_FALSE, format,
+                                  ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_COLOR_INDEX, format, 1, 1, type, stride,
+                GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_SecondaryColorPointer_no_error(GLint size, GLenum type,
+                                     GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   FLUSH_VERTICES(ctx, 0);
+
+   GLenum format = get_array_format(ctx, BGRA_OR_4, &size);
+   update_array(ctx, VERT_ATTRIB_COLOR1, format, BGRA_OR_4, size, type,
+                stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
@@ -587,19 +778,40 @@ void GLAPIENTRY
 _mesa_SecondaryColorPointer(GLint size, GLenum type,
                               GLsizei stride, const GLvoid *ptr)
 {
+   GET_CURRENT_CONTEXT(ctx);
+
+   FLUSH_VERTICES(ctx, 0);
+
+   GLenum format = get_array_format(ctx, BGRA_OR_4, &size);
    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
                                   INT_BIT | UNSIGNED_INT_BIT |
                                   HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
                                   UNSIGNED_INT_2_10_10_10_REV_BIT |
                                   INT_2_10_10_10_REV_BIT);
-   GET_CURRENT_CONTEXT(ctx);
 
+   if (!validate_array_and_format(ctx, "glSecondaryColorPointer",
+                                  VERT_ATTRIB_COLOR1, legalTypes, 3,
+                                  BGRA_OR_4, size, type, stride,
+                                  GL_TRUE, GL_FALSE, GL_FALSE, format, ptr,
+                                  ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_COLOR1, format, BGRA_OR_4, size, type,
+                stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_TexCoordPointer_no_error(GLint size, GLenum type, GLsizei stride,
+                               const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   const GLuint unit = ctx->Array.ActiveTexture;
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glSecondaryColorPointer", VERT_ATTRIB_COLOR1,
-                legalTypes, 3, BGRA_OR_4,
-                size, type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
+   update_array(ctx, VERT_ATTRIB_TEX(unit), GL_RGBA, 4, size, type,
+                stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
@@ -608,57 +820,117 @@ _mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride,
                       const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLbitfield legalTypes = (ctx->API == API_OPENGLES)
+   const GLint sizeMin = (ctx->API == API_OPENGLES) ? 2 : 1;
+   const GLuint unit = ctx->Array.ActiveTexture;
+
+   FLUSH_VERTICES(ctx, 0);
+
+   GLenum format = GL_RGBA;
+   const GLbitfield legalTypes = (ctx->API == API_OPENGLES)
       ? (BYTE_BIT | SHORT_BIT | FLOAT_BIT | FIXED_ES_BIT)
       : (SHORT_BIT | INT_BIT |
          HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
          UNSIGNED_INT_2_10_10_10_REV_BIT |
          INT_2_10_10_10_REV_BIT);
-   const GLint sizeMin = (ctx->API == API_OPENGLES) ? 2 : 1;
-   const GLuint unit = ctx->Array.ActiveTexture;
 
+   if (!validate_array_and_format(ctx, "glTexCoordPointer",
+                                  VERT_ATTRIB_TEX(unit), legalTypes,
+                                  sizeMin, 4, size, type, stride,
+                                  GL_FALSE, GL_FALSE, GL_FALSE, format, ptr,
+                                  ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_TEX(unit), format, 4, size, type,
+                stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_EdgeFlagPointer_no_error(GLsizei stride, const GLvoid *ptr)
+{
+   /* this is the same type that glEdgeFlag uses */
+   const GLboolean integer = GL_FALSE;
+   GET_CURRENT_CONTEXT(ctx);
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glTexCoordPointer", VERT_ATTRIB_TEX(unit),
-                legalTypes, sizeMin, 4,
-                size, type, stride, GL_FALSE, GL_FALSE, GL_FALSE,
-                ptr);
+   update_array(ctx, VERT_ATTRIB_EDGEFLAG, GL_RGBA, 1, 1, GL_UNSIGNED_BYTE,
+                stride, GL_FALSE, integer, GL_FALSE, ptr);
 }
 
 
 void GLAPIENTRY
 _mesa_EdgeFlagPointer(GLsizei stride, const GLvoid *ptr)
 {
-   const GLbitfield legalTypes = UNSIGNED_BYTE_BIT;
    /* this is the same type that glEdgeFlag uses */
    const GLboolean integer = GL_FALSE;
    GET_CURRENT_CONTEXT(ctx);
 
    FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, "glEdgeFlagPointer", VERT_ATTRIB_EDGEFLAG,
-                legalTypes, 1, 1,
-                1, GL_UNSIGNED_BYTE, stride, GL_FALSE, integer, GL_FALSE, ptr);
+   GLenum format = GL_RGBA;
+   const GLbitfield legalTypes = UNSIGNED_BYTE_BIT;
+
+   if (!validate_array_and_format(ctx, "glEdgeFlagPointer",
+                                  VERT_ATTRIB_EDGEFLAG, legalTypes,
+                                  1, 1, 1, GL_UNSIGNED_BYTE, stride,
+                                  GL_FALSE, integer, GL_FALSE, format, ptr,
+                                  ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_EDGEFLAG, format, 1, 1, GL_UNSIGNED_BYTE,
+                stride, GL_FALSE, integer, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_PointSizePointerOES_no_error(GLenum type, GLsizei stride,
+                                   const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   FLUSH_VERTICES(ctx, 0);
+
+   update_array(ctx, VERT_ATTRIB_POINT_SIZE, GL_RGBA, 1, 1, type, stride,
+                GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
 void GLAPIENTRY
 _mesa_PointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
-   const GLbitfield legalTypes = (FLOAT_BIT | FIXED_ES_BIT);
    GET_CURRENT_CONTEXT(ctx);
 
    FLUSH_VERTICES(ctx, 0);
 
+   GLenum format = GL_RGBA;
    if (ctx->API != API_OPENGLES) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glPointSizePointer(ES 1.x only)");
       return;
    }
-      
-   update_array(ctx, "glPointSizePointer", VERT_ATTRIB_POINT_SIZE,
-                legalTypes, 1, 1,
-                1, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+
+   const GLbitfield legalTypes = (FLOAT_BIT | FIXED_ES_BIT);
+
+   if (!validate_array_and_format(ctx, "glPointSizePointer",
+                                  VERT_ATTRIB_POINT_SIZE, legalTypes,
+                                  1, 1, 1, type, stride, GL_FALSE, GL_FALSE,
+                                  GL_FALSE, format, ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_POINT_SIZE, format, 1, 1, type, stride,
+                GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribPointer_no_error(GLuint index, GLint size, GLenum type,
+                                   GLboolean normalized,
+                                   GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   GLenum format = get_array_format(ctx, BGRA_OR_4, &size);
+   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, BGRA_OR_4,
+                size, type, stride, normalized, GL_FALSE, GL_FALSE, ptr);
 }
 
 
@@ -672,6 +944,14 @@ _mesa_VertexAttribPointer(GLuint index, GLint size, GLenum type,
                              GLboolean normalized,
                              GLsizei stride, const GLvoid *ptr)
 {
+   GET_CURRENT_CONTEXT(ctx);
+
+   GLenum format = get_array_format(ctx, BGRA_OR_4, &size);
+   if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(idx)");
+      return;
+   }
+
    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
                                   INT_BIT | UNSIGNED_INT_BIT |
@@ -680,22 +960,35 @@ _mesa_VertexAttribPointer(GLuint index, GLint size, GLenum type,
                                   UNSIGNED_INT_2_10_10_10_REV_BIT |
                                   INT_2_10_10_10_REV_BIT |
                                   UNSIGNED_INT_10F_11F_11F_REV_BIT);
-   GET_CURRENT_CONTEXT(ctx);
 
-   if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(index)");
+   if (!validate_array_and_format(ctx, "glVertexAttribPointer",
+                                  VERT_ATTRIB_GENERIC(index), legalTypes,
+                                  1, BGRA_OR_4, size, type, stride,
+                                  normalized, GL_FALSE, GL_FALSE, format,
+                                  ptr, ctx->Array.VAO))
       return;
-   }
 
-   update_array(ctx, "glVertexAttribPointer", VERT_ATTRIB_GENERIC(index),
-                legalTypes, 1, BGRA_OR_4,
+   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, BGRA_OR_4,
                 size, type, stride, normalized, GL_FALSE, GL_FALSE, ptr);
 }
 
 
-/**
- * GL_EXT_gpu_shader4 / GL 3.0.
- * Set an integer-valued vertex attribute array.
+void GLAPIENTRY
+_mesa_VertexAttribIPointer_no_error(GLuint index, GLint size, GLenum type,
+                                    GLsizei stride, const GLvoid *ptr)
+{
+   const GLboolean normalized = GL_FALSE;
+   const GLboolean integer = GL_TRUE;
+   GET_CURRENT_CONTEXT(ctx);
+
+   update_array(ctx, VERT_ATTRIB_GENERIC(index), GL_RGBA, 4,  size, type,
+                stride, normalized, integer, GL_FALSE, ptr);
+}
+
+
+/**
+ * GL_EXT_gpu_shader4 / GL 3.0.
+ * Set an integer-valued vertex attribute array.
  * Note that these arrays DO NOT alias the conventional GL vertex arrays
  * (position, normal, color, fog, texcoord, etc).
  */
@@ -703,40 +996,85 @@ void GLAPIENTRY
 _mesa_VertexAttribIPointer(GLuint index, GLint size, GLenum type,
                            GLsizei stride, const GLvoid *ptr)
 {
-   const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
-                                  SHORT_BIT | UNSIGNED_SHORT_BIT |
-                                  INT_BIT | UNSIGNED_INT_BIT);
    const GLboolean normalized = GL_FALSE;
    const GLboolean integer = GL_TRUE;
    GET_CURRENT_CONTEXT(ctx);
 
+   GLenum format = GL_RGBA;
    if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribIPointer(index)");
       return;
    }
 
-   update_array(ctx, "glVertexAttribIPointer", VERT_ATTRIB_GENERIC(index),
-                legalTypes, 1, 4,
-                size, type, stride, normalized, integer, GL_FALSE, ptr);
+   const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
+                                  SHORT_BIT | UNSIGNED_SHORT_BIT |
+                                  INT_BIT | UNSIGNED_INT_BIT);
+
+   if (!validate_array_and_format(ctx, "glVertexAttribIPointer",
+                                  VERT_ATTRIB_GENERIC(index), legalTypes,
+                                  1, 4, size, type, stride,
+                                  normalized, integer, GL_FALSE, format,
+                                  ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, 4,  size, type,
+                stride, normalized, integer, GL_FALSE, ptr);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribLPointer_no_error(GLuint index, GLint size, GLenum type,
+                                    GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   update_array(ctx, VERT_ATTRIB_GENERIC(index), GL_RGBA, 4, size, type,
+                stride, GL_FALSE, GL_FALSE, GL_TRUE, ptr);
 }
 
+
 void GLAPIENTRY
 _mesa_VertexAttribLPointer(GLuint index, GLint size, GLenum type,
                            GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
-   const GLbitfield legalTypes = (DOUBLE_BIT);
+
+   GLenum format = GL_RGBA;
    if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribLPointer(index)");
       return;
    }
 
-   update_array(ctx, "glVertexAttribLPointer", VERT_ATTRIB_GENERIC(index),
-                legalTypes, 1, 4,
-                size, type, stride, GL_TRUE, GL_FALSE, GL_TRUE, ptr);
+   const GLbitfield legalTypes = DOUBLE_BIT;
+
+   if (!validate_array_and_format(ctx, "glVertexAttribLPointer",
+                                  VERT_ATTRIB_GENERIC(index), legalTypes,
+                                  1, 4, size, type, stride,
+                                  GL_FALSE, GL_FALSE, GL_TRUE, format,
+                                  ptr, ctx->Array.VAO))
+      return;
+
+   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, 4, size, type,
+                stride, GL_FALSE, GL_FALSE, GL_TRUE, ptr);
 }
 
 
+void
+_mesa_enable_vertex_array_attrib(struct gl_context *ctx,
+                                 struct gl_vertex_array_object *vao,
+                                 unsigned attrib)
+{
+   assert(attrib < ARRAY_SIZE(vao->VertexAttrib));
+
+   if (!vao->VertexAttrib[attrib].Enabled) {
+      /* was disabled, now being enabled */
+      FLUSH_VERTICES(ctx, _NEW_ARRAY);
+      vao->VertexAttrib[attrib].Enabled = GL_TRUE;
+      vao->_Enabled |= VERT_BIT(attrib);
+      vao->NewArrays |= VERT_BIT(attrib);
+   }
+}
+
 static void
 enable_vertex_array_attrib(struct gl_context *ctx,
                            struct gl_vertex_array_object *vao,
@@ -748,15 +1086,7 @@ enable_vertex_array_attrib(struct gl_context *ctx,
       return;
    }
 
-   assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(vao->VertexAttrib));
-
-   if (!vao->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
-      /* was disabled, now being enabled */
-      FLUSH_VERTICES(ctx, _NEW_ARRAY);
-      vao->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_TRUE;
-      vao->_Enabled |= VERT_BIT_GENERIC(index);
-      vao->NewArrays |= VERT_BIT_GENERIC(index);
-   }
+   _mesa_enable_vertex_array_attrib(ctx, vao, VERT_ATTRIB_GENERIC(index));
 }
 
 
@@ -769,6 +1099,15 @@ _mesa_EnableVertexAttribArray(GLuint index)
 }
 
 
+void GLAPIENTRY
+_mesa_EnableVertexAttribArray_no_error(GLuint index)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   _mesa_enable_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                    VERT_ATTRIB_GENERIC(index));
+}
+
+
 void GLAPIENTRY
 _mesa_EnableVertexArrayAttrib(GLuint vaobj, GLuint index)
 {
@@ -790,17 +1129,20 @@ _mesa_EnableVertexArrayAttrib(GLuint vaobj, GLuint index)
 }
 
 
+void GLAPIENTRY
+_mesa_EnableVertexArrayAttrib_no_error(GLuint vaobj, GLuint index)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object *vao = _mesa_lookup_vao(ctx, vaobj);
+   _mesa_enable_vertex_array_attrib(ctx, vao, VERT_ATTRIB_GENERIC(index));
+}
+
+
 static void
 disable_vertex_array_attrib(struct gl_context *ctx,
                             struct gl_vertex_array_object *vao,
-                            GLuint index,
-                            const char *func)
+                            GLuint index)
 {
-   if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
-      return;
-   }
-
    assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(vao->VertexAttrib));
 
    if (vao->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
@@ -817,8 +1159,21 @@ void GLAPIENTRY
 _mesa_DisableVertexAttribArray(GLuint index)
 {
    GET_CURRENT_CONTEXT(ctx);
-   disable_vertex_array_attrib(ctx, ctx->Array.VAO, index,
-                               "glDisableVertexAttribArray");
+
+   if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glDisableVertexAttribArray(index)");
+      return;
+   }
+
+   disable_vertex_array_attrib(ctx, ctx->Array.VAO, index);
+}
+
+
+void GLAPIENTRY
+_mesa_DisableVertexAttribArray_no_error(GLuint index)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   disable_vertex_array_attrib(ctx, ctx->Array.VAO, index);
 }
 
 
@@ -839,7 +1194,21 @@ _mesa_DisableVertexArrayAttrib(GLuint vaobj, GLuint index)
    if (!vao)
       return;
 
-   disable_vertex_array_attrib(ctx, vao, index, "glDisableVertexArrayAttrib");
+   if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glDisableVertexArrayAttrib(index)");
+      return;
+   }
+
+   disable_vertex_array_attrib(ctx, vao, index);
+}
+
+
+void GLAPIENTRY
+_mesa_DisableVertexArrayAttrib_no_error(GLuint vaobj, GLuint index)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object *vao = _mesa_lookup_vao(ctx, vaobj);
+   disable_vertex_array_attrib(ctx, vao, index);
 }
 
 
@@ -849,11 +1218,12 @@ _mesa_DisableVertexArrayAttrib(GLuint vaobj, GLuint index)
  * not handle the 4-element GL_CURRENT_VERTEX_ATTRIB_ARB query.
  */
 static GLuint
-get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname,
-                  const char *caller)
+get_vertex_array_attrib(struct gl_context *ctx,
+                        const struct gl_vertex_array_object *vao,
+                        GLuint index, GLenum pname,
+                        const char *caller)
 {
-   const struct gl_vertex_array_object *vao = ctx->Array.VAO;
-   const struct gl_vertex_attrib_array *array;
+   const struct gl_array_attributes *array;
 
    if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", caller, index);
@@ -876,7 +1246,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 vao->VertexBinding[array->VertexBinding].BufferObj->Name;
+      return vao->BufferBinding[array->BufferBindingIndex].BufferObj->Name;
    case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
       if ((_mesa_is_desktop_gl(ctx)
            && (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4))
@@ -884,19 +1254,24 @@ get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname,
          return array->Integer;
       }
       goto error;
+   case GL_VERTEX_ATTRIB_ARRAY_LONG:
+      if (_mesa_is_desktop_gl(ctx)) {
+         return array->Doubles;
+      }
+      goto error;
    case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB:
       if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_instanced_arrays)
           || _mesa_is_gles3(ctx)) {
-         return vao->VertexBinding[array->VertexBinding].InstanceDivisor;
+         return vao->BufferBinding[array->BufferBindingIndex].InstanceDivisor;
       }
       goto error;
    case GL_VERTEX_ATTRIB_BINDING:
-      if (_mesa_is_desktop_gl(ctx)) {
-         return array->VertexBinding - VERT_ATTRIB_GENERIC0;
+      if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles31(ctx)) {
+         return array->BufferBindingIndex - VERT_ATTRIB_GENERIC0;
       }
       goto error;
    case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
-      if (_mesa_is_desktop_gl(ctx)) {
+      if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles31(ctx)) {
          return array->RelativeOffset;
       }
       goto error;
@@ -925,7 +1300,8 @@ get_current_attrib(struct gl_context *ctx, GLuint index, const char *function)
       return NULL;
    }
 
-   assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(ctx->Array.VAO->VertexAttrib));
+   assert(VERT_ATTRIB_GENERIC(index) <
+          ARRAY_SIZE(ctx->Array.VAO->VertexAttrib));
 
    FLUSH_CURRENT(ctx, 0);
    return ctx->Current.Attrib[VERT_ATTRIB_GENERIC(index)];
@@ -943,7 +1319,8 @@ _mesa_GetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params)
       }
    }
    else {
-      params[0] = (GLfloat) get_vertex_array_attrib(ctx, index, pname,
+      params[0] = (GLfloat) get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                                    index, pname,
                                                     "glGetVertexAttribfv");
    }
 }
@@ -964,7 +1341,8 @@ _mesa_GetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params)
       }
    }
    else {
-      params[0] = (GLdouble) get_vertex_array_attrib(ctx, index, pname,
+      params[0] = (GLdouble) get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                                     index, pname,
                                                      "glGetVertexAttribdv");
    }
 }
@@ -975,7 +1353,9 @@ _mesa_GetVertexAttribLdv(GLuint index, GLenum pname, GLdouble *params)
    GET_CURRENT_CONTEXT(ctx);
 
    if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
-      const GLdouble *v = (const GLdouble *)get_current_attrib(ctx, index, "glGetVertexAttribLdv");
+      const GLdouble *v =
+         (const GLdouble *)get_current_attrib(ctx, index,
+                                              "glGetVertexAttribLdv");
       if (v != NULL) {
          params[0] = v[0];
          params[1] = v[1];
@@ -984,7 +1364,8 @@ _mesa_GetVertexAttribLdv(GLuint index, GLenum pname, GLdouble *params)
       }
    }
    else {
-      params[0] = (GLdouble) get_vertex_array_attrib(ctx, index, pname,
+      params[0] = (GLdouble) get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                                     index, pname,
                                                      "glGetVertexAttribLdv");
    }
 }
@@ -1005,11 +1386,35 @@ _mesa_GetVertexAttribiv(GLuint index, GLenum pname, GLint *params)
       }
    }
    else {
-      params[0] = (GLint) get_vertex_array_attrib(ctx, index, pname,
+      params[0] = (GLint) get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                                  index, pname,
                                                   "glGetVertexAttribiv");
    }
 }
 
+void GLAPIENTRY
+_mesa_GetVertexAttribLui64vARB(GLuint index, GLenum pname, GLuint64EXT *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
+      const GLuint64 *v =
+         (const GLuint64 *)get_current_attrib(ctx, index,
+                                              "glGetVertexAttribLui64vARB");
+      if (v != NULL) {
+         params[0] = v[0];
+         params[1] = v[1];
+         params[2] = v[2];
+         params[3] = v[3];
+      }
+   }
+   else {
+      params[0] = (GLuint64) get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                                     index, pname,
+                                                     "glGetVertexAttribLui64vARB");
+   }
+}
+
 
 /** GL 3.0 */
 void GLAPIENTRY
@@ -1025,7 +1430,8 @@ _mesa_GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
       }
    }
    else {
-      params[0] = (GLint) get_vertex_array_attrib(ctx, index, pname,
+      params[0] = (GLint) get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                                  index, pname,
                                                   "glGetVertexAttribIiv");
    }
 }
@@ -1045,7 +1451,8 @@ _mesa_GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
       }
    }
    else {
-      params[0] = get_vertex_array_attrib(ctx, index, pname,
+      params[0] = get_vertex_array_attrib(ctx, ctx->Array.VAO,
+                                          index, pname,
                                           "glGetVertexAttribIuiv");
    }
 }
@@ -1066,9 +1473,128 @@ _mesa_GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer)
       return;
    }
 
-   assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(ctx->Array.VAO->VertexAttrib));
+   assert(VERT_ATTRIB_GENERIC(index) <
+          ARRAY_SIZE(ctx->Array.VAO->VertexAttrib));
+
+   *pointer = (GLvoid *)
+      ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr;
+}
+
+
+/** ARB_direct_state_access */
+void GLAPIENTRY
+_mesa_GetVertexArrayIndexediv(GLuint vaobj, GLuint index,
+                              GLenum pname, GLint *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object *vao;
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *    "An INVALID_OPERATION error is generated if <vaobj> is not
+    *     [compatibility profile: zero or] the name of an existing
+    *     vertex array object."
+    */
+   vao = _mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayIndexediv");
+   if (!vao)
+      return;
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *    "For GetVertexArrayIndexediv, <pname> must be one of
+    *     VERTEX_ATTRIB_ARRAY_ENABLED, VERTEX_ATTRIB_ARRAY_SIZE,
+    *     VERTEX_ATTRIB_ARRAY_STRIDE, VERTEX_ATTRIB_ARRAY_TYPE,
+    *     VERTEX_ATTRIB_ARRAY_NORMALIZED, VERTEX_ATTRIB_ARRAY_INTEGER,
+    *     VERTEX_ATTRIB_ARRAY_LONG, VERTEX_ATTRIB_ARRAY_DIVISOR, or
+    *     VERTEX_ATTRIB_RELATIVE_OFFSET."
+    *
+    * and:
+    *
+    *    "Add GetVertexArrayIndexediv in 'Get Command' for
+    *     VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
+    *     VERTEX_ATTRIB_BINDING,
+    *     VERTEX_ATTRIB_RELATIVE_OFFSET,
+    *     VERTEX_BINDING_OFFSET, and
+    *     VERTEX_BINDING_STRIDE states"
+    *
+    * The only parameter name common to both lists is
+    * VERTEX_ATTRIB_RELATIVE_OFFSET.  Also note that VERTEX_BINDING_BUFFER
+    * and VERTEX_BINDING_DIVISOR are missing from both lists.  It seems
+    * pretty clear however that the intent is that it should be possible
+    * to query all vertex attrib and binding states that can be set with
+    * a DSA function.
+    */
+   switch (pname) {
+   case GL_VERTEX_BINDING_OFFSET:
+      params[0] = vao->BufferBinding[VERT_ATTRIB_GENERIC(index)].Offset;
+      break;
+   case GL_VERTEX_BINDING_STRIDE:
+      params[0] = vao->BufferBinding[VERT_ATTRIB_GENERIC(index)].Stride;
+      break;
+   case GL_VERTEX_BINDING_DIVISOR:
+      params[0] = vao->BufferBinding[VERT_ATTRIB_GENERIC(index)].InstanceDivisor;
+      break;
+   case GL_VERTEX_BINDING_BUFFER:
+      params[0] = vao->BufferBinding[VERT_ATTRIB_GENERIC(index)].BufferObj->Name;
+      break;
+   default:
+      params[0] = get_vertex_array_attrib(ctx, vao, index, pname,
+                                          "glGetVertexArrayIndexediv");
+      break;
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_GetVertexArrayIndexed64iv(GLuint vaobj, GLuint index,
+                                GLenum pname, GLint64 *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object *vao;
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *    "An INVALID_OPERATION error is generated if <vaobj> is not
+    *     [compatibility profile: zero or] the name of an existing
+    *     vertex array object."
+    */
+   vao = _mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayIndexed64iv");
+   if (!vao)
+      return;
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *    "For GetVertexArrayIndexed64iv, <pname> must be
+    *     VERTEX_BINDING_OFFSET."
+    *
+    * and:
+    *
+    *    "An INVALID_ENUM error is generated if <pname> is not one of
+    *     the valid values listed above for the corresponding command."
+    */
+   if (pname != GL_VERTEX_BINDING_OFFSET) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexArrayIndexed64iv("
+                  "pname != GL_VERTEX_BINDING_OFFSET)");
+      return;
+   }
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *    "An INVALID_VALUE error is generated if <index> is greater than
+    *     or equal to the value of MAX_VERTEX_ATTRIBS."
+    *
+    * Since the index refers to a buffer binding in this case, the intended
+    * limit must be MAX_VERTEX_ATTRIB_BINDINGS.  Both limits are currently
+    * required to be the same, so in practice this doesn't matter.
+    */
+   if (index >= ctx->Const.MaxVertexAttribBindings) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexArrayIndexed64iv(index"
+                  "%d >= the value of GL_MAX_VERTEX_ATTRIB_BINDINGS (%d))",
+                  index, ctx->Const.MaxVertexAttribBindings);
+      return;
+   }
 
-   *pointer = (GLvoid *) ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr;
+   params[0] = vao->BufferBinding[VERT_ATTRIB_GENERIC(index)].Offset;
 }
 
 
@@ -1354,24 +1880,6 @@ _mesa_UnlockArraysEXT( void )
 }
 
 
-/* GL_EXT_multi_draw_arrays */
-void GLAPIENTRY
-_mesa_MultiDrawArrays( GLenum mode, const GLint *first,
-                          const GLsizei *count, GLsizei primcount )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   GLint i;
-
-   FLUSH_VERTICES(ctx, 0);
-
-   for (i = 0; i < primcount; i++) {
-      if (count[i] > 0) {
-         CALL_DrawArrays(ctx->CurrentDispatch, (mode, first[i], count[i]));
-      }
-   }
-}
-
-
 /* GL_IBM_multimode_draw_arrays */
 void GLAPIENTRY
 _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
@@ -1386,7 +1894,7 @@ _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
    for ( i = 0 ; i < primcount ; i++ ) {
       if ( count[i] > 0 ) {
          GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
-        CALL_DrawArrays(ctx->CurrentDispatch, ( m, first[i], count[i] ));
+        CALL_DrawArrays(ctx->CurrentServerDispatch, ( m, first[i], count[i] ));
       }
    }
 }
@@ -1408,16 +1916,34 @@ _mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
    for ( i = 0 ; i < primcount ; i++ ) {
       if ( count[i] > 0 ) {
          GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
-        CALL_DrawElements(ctx->CurrentDispatch, ( m, count[i], type,
-                                                   indices[i] ));
+        CALL_DrawElements(ctx->CurrentServerDispatch, ( m, count[i], type,
+                                                        indices[i] ));
       }
    }
 }
 
 
+static void
+primitive_restart_index(struct gl_context *ctx, GLuint index)
+{
+   if (ctx->Array.RestartIndex != index) {
+      FLUSH_VERTICES(ctx, 0);
+      ctx->Array.RestartIndex = index;
+   }
+}
+
+
 /**
  * GL_NV_primitive_restart and GL 3.1
  */
+void GLAPIENTRY
+_mesa_PrimitiveRestartIndex_no_error(GLuint index)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   primitive_restart_index(ctx, index);
+}
+
+
 void GLAPIENTRY
 _mesa_PrimitiveRestartIndex(GLuint index)
 {
@@ -1428,10 +1954,33 @@ _mesa_PrimitiveRestartIndex(GLuint index)
       return;
    }
 
-   if (ctx->Array.RestartIndex != index) {
-      FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
-      ctx->Array.RestartIndex = index;
-   }
+   primitive_restart_index(ctx, index);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribDivisor_no_error(GLuint index, GLuint divisor)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   const GLuint genericIndex = VERT_ATTRIB_GENERIC(index);
+   struct gl_vertex_array_object * const vao = ctx->Array.VAO;
+
+   assert(genericIndex < ARRAY_SIZE(vao->VertexAttrib));
+
+   /* 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, vao, genericIndex, genericIndex);
+   vertex_binding_divisor(ctx, vao, genericIndex, divisor);
 }
 
 
@@ -1446,6 +1995,7 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
    GET_CURRENT_CONTEXT(ctx);
 
    const GLuint genericIndex = VERT_ATTRIB_GENERIC(index);
+   struct gl_vertex_array_object * const vao = ctx->Array.VAO;
 
    if (!ctx->Extensions.ARB_instanced_arrays) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexAttribDivisor()");
@@ -1453,12 +2003,12 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
    }
 
    if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribDivisor(index = %u)",
-                  index);
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glVertexAttribDivisor(index = %u)", index);
       return;
    }
 
-   assert(genericIndex < ARRAY_SIZE(ctx->Array.VAO->VertexAttrib));
+   assert(genericIndex < ARRAY_SIZE(vao->VertexAttrib));
 
    /* The ARB_vertex_attrib_binding spec says:
     *
@@ -1471,33 +2021,51 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
     *       VertexAttribBinding(index, index);
     *       VertexBindingDivisor(index, divisor);"
     */
-   vertex_attrib_binding(ctx, genericIndex, genericIndex);
-   vertex_binding_divisor(ctx, genericIndex, divisor);
+   vertex_attrib_binding(ctx, vao, genericIndex, genericIndex);
+   vertex_binding_divisor(ctx, vao, genericIndex, divisor);
 }
 
 
-unsigned
-_mesa_primitive_restart_index(const struct gl_context *ctx, GLenum ib_type)
+static ALWAYS_INLINE void
+vertex_array_vertex_buffer(struct gl_context *ctx,
+                           struct gl_vertex_array_object *vao,
+                           GLuint bindingIndex, GLuint buffer, GLintptr offset,
+                           GLsizei stride, bool no_error, const char *func)
 {
-   /* From the OpenGL 4.3 core specification, page 302:
-    * "If both PRIMITIVE_RESTART and PRIMITIVE_RESTART_FIXED_INDEX are
-    *  enabled, the index value determined by PRIMITIVE_RESTART_FIXED_INDEX
-    *  is used."
-    */
-   if (ctx->Array.PrimitiveRestartFixedIndex) {
-      switch (ib_type) {
-      case GL_UNSIGNED_BYTE:
-         return 0xff;
-      case GL_UNSIGNED_SHORT:
-         return 0xffff;
-      case GL_UNSIGNED_INT:
-         return 0xffffffff;
-      default:
-         assert(!"_mesa_primitive_restart_index: Invalid index buffer type.");
+   struct gl_buffer_object *vbo;
+   if (buffer ==
+       vao->BufferBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj->Name) {
+      vbo = vao->BufferBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj;
+   } else if (buffer != 0) {
+      vbo = _mesa_lookup_bufferobj(ctx, buffer);
+
+      if (!no_error && !vbo && _mesa_is_gles31(ctx)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", func);
+         return;
       }
+      /* 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, buffer, &vbo, func))
+         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;
    }
 
-   return ctx->Array.RestartIndex;
+   _mesa_bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex),
+                            vbo, offset, stride);
 }
 
 
@@ -1505,12 +2073,12 @@ _mesa_primitive_restart_index(const struct gl_context *ctx, GLenum ib_type)
  * GL_ARB_vertex_attrib_binding
  */
 static void
-vertex_array_vertex_buffer(struct gl_context *ctx, struct gl_vertex_array_object *vao,
-                           GLuint bindingIndex, GLuint buffer, GLintptr offset,
-                           GLsizei stride, const char *func)
+vertex_array_vertex_buffer_err(struct gl_context *ctx,
+                               struct gl_vertex_array_object *vao,
+                               GLuint bindingIndex, GLuint buffer,
+                               GLintptr offset, GLsizei stride,
+                               const char *func)
 {
-   struct gl_buffer_object *vbo;
-
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    /* The ARB_vertex_attrib_binding spec says:
@@ -1544,42 +2112,26 @@ vertex_array_vertex_buffer(struct gl_context *ctx, struct gl_vertex_array_object
       return;
    }
 
-   if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 &&
+   if (((ctx->API == API_OPENGL_CORE && ctx->Version >= 44) || _mesa_is_gles31(ctx)) &&
        stride > ctx->Const.MaxVertexAttribStride) {
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride=%d > "
                   "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, stride);
       return;
    }
 
-   if (buffer == vao->VertexBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj->Name) {
-      vbo = vao->VertexBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj;
-   } else if (buffer != 0) {
-      vbo = _mesa_lookup_bufferobj(ctx, buffer);
+   vertex_array_vertex_buffer(ctx, vao, bindingIndex, buffer, offset,
+                              stride, false, func);
+}
 
-      /* 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, func))
-         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, vao, VERT_ATTRIB_GENERIC(bindingIndex),
-                      vbo, offset, stride);
+void GLAPIENTRY
+_mesa_BindVertexBuffer_no_error(GLuint bindingIndex, GLuint buffer,
+                                GLintptr offset, GLsizei stride)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   vertex_array_vertex_buffer(ctx, ctx->Array.VAO, bindingIndex,
+                              buffer, offset, stride, true,
+                              "glBindVertexBuffer");
 }
 
 
@@ -1594,15 +2146,29 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset,
     *    "An INVALID_OPERATION error is generated if no vertex array object
     *     is bound."
     */
-   if (ctx->API == API_OPENGL_CORE &&
+   if ((ctx->API == API_OPENGL_CORE || _mesa_is_gles31(ctx)) &&
        ctx->Array.VAO == ctx->Array.DefaultVAO) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glBindVertexBuffer(No array object bound)");
       return;
    }
 
-   vertex_array_vertex_buffer(ctx, ctx->Array.VAO, bindingIndex,
-                              buffer, offset, stride, "glBindVertexBuffer");
+   vertex_array_vertex_buffer_err(ctx, ctx->Array.VAO, bindingIndex,
+                                  buffer, offset, stride,
+                                  "glBindVertexBuffer");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayVertexBuffer_no_error(GLuint vaobj, GLuint bindingIndex,
+                                       GLuint buffer, GLintptr offset,
+                                       GLsizei stride)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_vertex_array_object *vao = _mesa_lookup_vao(ctx, vaobj);
+   vertex_array_vertex_buffer(ctx, vao, bindingIndex, buffer, offset,
+                              stride, true, "glVertexArrayVertexBuffer");
 }
 
 
@@ -1623,35 +2189,19 @@ _mesa_VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingIndex, GLuint buffer,
    if (!vao)
       return;
 
-   vertex_array_vertex_buffer(ctx, vao, bindingIndex,
-                              buffer, offset, stride,
-                              "glVertexArrayVertexBuffer");
+   vertex_array_vertex_buffer_err(ctx, vao, bindingIndex, buffer, offset,
+                                  stride, "glVertexArrayVertexBuffer");
 }
 
 
-static void
+static ALWAYS_INLINE void
 vertex_array_vertex_buffers(struct gl_context *ctx,
                             struct gl_vertex_array_object *vao,
                             GLuint first, GLsizei count, const GLuint *buffers,
                             const GLintptr *offsets, const GLsizei *strides,
-                            const char *func)
+                            bool no_error, const char *func)
 {
-   GLuint i;
-
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   /* The ARB_multi_bind spec says:
-    *
-    *    "An INVALID_OPERATION error is generated if <first> + <count>
-    *     is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS."
-    */
-   if (first + count > ctx->Const.MaxVertexAttribBindings) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(first=%u + count=%d > the value of "
-                  "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)",
-                  func, first, count, ctx->Const.MaxVertexAttribBindings);
-      return;
-   }
+   GLint i;
 
    if (!buffers) {
       /**
@@ -1666,8 +2216,8 @@ vertex_array_vertex_buffers(struct gl_context *ctx,
       struct gl_buffer_object *vbo = ctx->Shared->NullBufferObj;
 
       for (i = 0; i < count; i++)
-         bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i),
-                            vbo, 0, 16);
+         _mesa_bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i),
+                                  vbo, 0, 16);
 
       return;
    }
@@ -1691,41 +2241,43 @@ vertex_array_vertex_buffers(struct gl_context *ctx,
     *       their parameters are valid and no other error occurs."
     */
 
-   _mesa_begin_bufferobj_lookups(ctx);
+   _mesa_HashLockMutex(ctx->Shared->BufferObjects);
 
    for (i = 0; i < count; i++) {
       struct gl_buffer_object *vbo;
 
-      /* The ARB_multi_bind spec says:
-       *
-       *    "An INVALID_VALUE error is generated if any value in
-       *     <offsets> or <strides> is negative (per binding)."
-       */
-      if (offsets[i] < 0) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "%s(offsets[%u]=%" PRId64 " < 0)",
-                     func, i, (int64_t) offsets[i]);
-         continue;
-      }
+      if (!no_error) {
+         /* The ARB_multi_bind spec says:
+          *
+          *    "An INVALID_VALUE error is generated if any value in
+          *     <offsets> or <strides> is negative (per binding)."
+          */
+         if (offsets[i] < 0) {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "%s(offsets[%u]=%" PRId64 " < 0)",
+                        func, i, (int64_t) offsets[i]);
+            continue;
+         }
 
-      if (strides[i] < 0) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "%s(strides[%u]=%d < 0)",
-                     func, i, strides[i]);
-         continue;
-      }
+         if (strides[i] < 0) {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "%s(strides[%u]=%d < 0)",
+                        func, i, strides[i]);
+            continue;
+         }
 
-      if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 &&
-          strides[i] > ctx->Const.MaxVertexAttribStride) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "%s(strides[%u]=%d > "
-                     "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, i, strides[i]);
-         continue;
+         if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 &&
+             strides[i] > ctx->Const.MaxVertexAttribStride) {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "%s(strides[%u]=%d > "
+                        "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, i, strides[i]);
+            continue;
+         }
       }
 
       if (buffers[i]) {
          struct gl_vertex_buffer_binding *binding =
-            &vao->VertexBinding[VERT_ATTRIB_GENERIC(first + i)];
+            &vao->BufferBinding[VERT_ATTRIB_GENERIC(first + i)];
 
          if (buffers[i] == binding->BufferObj->Name)
             vbo = binding->BufferObj;
@@ -1738,11 +2290,51 @@ vertex_array_vertex_buffers(struct gl_context *ctx,
          vbo = ctx->Shared->NullBufferObj;
       }
 
-      bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i),
-                         vbo, offsets[i], strides[i]);
+      _mesa_bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i),
+                               vbo, offsets[i], strides[i]);
+   }
+
+   _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
+}
+
+
+static void
+vertex_array_vertex_buffers_err(struct gl_context *ctx,
+                                struct gl_vertex_array_object *vao,
+                                GLuint first, GLsizei count,
+                                const GLuint *buffers, const GLintptr *offsets,
+                                const GLsizei *strides, const char *func)
+{
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   /* The ARB_multi_bind spec says:
+    *
+    *    "An INVALID_OPERATION error is generated if <first> + <count>
+    *     is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS."
+    */
+   if (first + count > ctx->Const.MaxVertexAttribBindings) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(first=%u + count=%d > the value of "
+                  "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)",
+                  func, first, count, ctx->Const.MaxVertexAttribBindings);
+      return;
    }
 
-   _mesa_end_bufferobj_lookups(ctx);
+   vertex_array_vertex_buffers(ctx, vao, first, count, buffers, offsets,
+                               strides, false, func);
+}
+
+
+void GLAPIENTRY
+_mesa_BindVertexBuffers_no_error(GLuint first, GLsizei count,
+                                 const GLuint *buffers, const GLintptr *offsets,
+                                 const GLsizei *strides)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   vertex_array_vertex_buffers(ctx, ctx->Array.VAO, first, count,
+                               buffers, offsets, strides, true,
+                               "glBindVertexBuffers");
 }
 
 
@@ -1764,9 +2356,24 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers,
       return;
    }
 
-   vertex_array_vertex_buffers(ctx, ctx->Array.VAO, first, count,
-                               buffers, offsets, strides,
-                               "glBindVertexBuffers");
+   vertex_array_vertex_buffers_err(ctx, ctx->Array.VAO, first, count,
+                                   buffers, offsets, strides,
+                                   "glBindVertexBuffers");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayVertexBuffers_no_error(GLuint vaobj, GLuint first,
+                                        GLsizei count, const GLuint *buffers,
+                                        const GLintptr *offsets,
+                                        const GLsizei *strides)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_vertex_array_object *vao = _mesa_lookup_vao(ctx, vaobj);
+   vertex_array_vertex_buffers(ctx, vao, first, count,
+                               buffers, offsets, strides, true,
+                               "glVertexArrayVertexBuffers");
 }
 
 
@@ -1788,9 +2395,9 @@ _mesa_VertexArrayVertexBuffers(GLuint vaobj, GLuint first, GLsizei count,
    if (!vao)
       return;
 
-   vertex_array_vertex_buffers(ctx, vao, first, count,
-                               buffers, offsets, strides,
-                               "glVertexArrayVertexBuffers");
+   vertex_array_vertex_buffers_err(ctx, vao, first, count,
+                                   buffers, offsets, strides,
+                                   "glVertexArrayVertexBuffers");
 }
 
 
@@ -1798,50 +2405,63 @@ static void
 vertex_attrib_format(GLuint attribIndex, GLint size, GLenum type,
                      GLboolean normalized, GLboolean integer,
                      GLboolean doubles, GLbitfield legalTypes,
-                     GLsizei maxSize, GLuint relativeOffset,
+                     GLsizei sizeMax, GLuint relativeOffset,
                      const char *func)
 {
    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);
-    *     - ..."
-    *
-    * This error condition only applies to VertexAttribFormat and
-    * VertexAttribIFormat in the extension spec, but we assume that this
-    * is an oversight.  In the OpenGL 4.3 (Core Profile) spec, it applies
-    * to all three functions.
-    */
-   if (ctx->API == API_OPENGL_CORE &&
-       ctx->Array.VAO == ctx->Array.DefaultVAO) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(No array object bound)", func);
-      return;
-   }
+   GLenum format = get_array_format(ctx, sizeMax, &size);
 
-   /* 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.Program[MESA_SHADER_VERTEX].MaxAttribs) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "%s(attribindex=%u > "
-                  "GL_MAX_VERTEX_ATTRIBS)",
-                  func, attribIndex);
-      return;
+   if (!_mesa_is_no_error_enabled(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);
+       *     - ..."
+       *
+       * This error condition only applies to VertexAttribFormat and
+       * VertexAttribIFormat in the extension spec, but we assume that this
+       * is an oversight.  In the OpenGL 4.3 (Core Profile) spec, it applies
+       * to all three functions.
+       */
+      if ((ctx->API == API_OPENGL_CORE || _mesa_is_gles31(ctx)) &&
+          ctx->Array.VAO == ctx->Array.DefaultVAO) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(No array object bound)", func);
+         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.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "%s(attribindex=%u > "
+                     "GL_MAX_VERTEX_ATTRIBS)",
+                     func, attribIndex);
+         return;
+      }
+
+      if (!validate_array_format(ctx, func, ctx->Array.VAO,
+                                 VERT_ATTRIB_GENERIC(attribIndex),
+                                 legalTypes, 1, sizeMax, size, type,
+                                 normalized, integer, doubles, relativeOffset,
+                                 format)) {
+         return;
+      }
    }
 
    FLUSH_VERTICES(ctx, 0);
 
-   update_array_format(ctx, func, ctx->Array.VAO,
-                       VERT_ATTRIB_GENERIC(attribIndex),
-                       legalTypes, 1, maxSize, size, type,
-                       normalized, integer, doubles, relativeOffset);
+   _mesa_update_array_format(ctx, ctx->Array.VAO,
+                             VERT_ATTRIB_GENERIC(attribIndex), size, type,
+                             format, normalized, integer, doubles,
+                             relativeOffset);
 }
 
 
@@ -1876,24 +2496,108 @@ _mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type,
 }
 
 
-void GLAPIENTRY
-_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
+static void
+vertex_array_attrib_format(GLuint vaobj, GLuint attribIndex, GLint size,
+                           GLenum type, GLboolean normalized,
+                           GLboolean integer, GLboolean doubles,
+                           GLbitfield legalTypes, GLsizei sizeMax,
+                           GLuint relativeOffset, const char *func)
 {
    GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object *vao;
+
    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.VAO == ctx->Array.DefaultVAO) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glVertexAttribBinding(No array object bound)");
-      return;
+   GLenum format = get_array_format(ctx, sizeMax, &size);
+
+   if (_mesa_is_no_error_enabled(ctx)) {
+      vao = _mesa_lookup_vao(ctx, vaobj);
+      if (!vao)
+         return;
+   } else {
+      /* The ARB_direct_state_access spec says:
+       *
+       *   "An INVALID_OPERATION error is generated by
+       *   VertexArrayAttrib*Format if <vaobj> is not [compatibility profile:
+       *   zero or] the name of an existing vertex array object."
+       */
+      vao = _mesa_lookup_vao_err(ctx, vaobj, func);
+      if (!vao)
+         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.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "%s(attribindex=%u > GL_MAX_VERTEX_ATTRIBS)",
+                     func, attribIndex);
+         return;
+      }
+
+      if (!validate_array_format(ctx, func, vao,
+                                 VERT_ATTRIB_GENERIC(attribIndex),
+                                 legalTypes, 1, sizeMax, size, type,
+                                 normalized, integer, doubles, relativeOffset,
+                                 format)) {
+         return;
+      }
    }
 
+   FLUSH_VERTICES(ctx, 0);
+
+   _mesa_update_array_format(ctx, vao, VERT_ATTRIB_GENERIC(attribIndex), size,
+                             type, format, normalized, integer, doubles,
+                             relativeOffset);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribFormat(GLuint vaobj, GLuint attribIndex, GLint size,
+                              GLenum type, GLboolean normalized,
+                              GLuint relativeOffset)
+{
+   vertex_array_attrib_format(vaobj, attribIndex, size, type, normalized,
+                              GL_FALSE, GL_FALSE, ATTRIB_FORMAT_TYPES_MASK,
+                              BGRA_OR_4, relativeOffset,
+                              "glVertexArrayAttribFormat");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribIFormat(GLuint vaobj, GLuint attribIndex,
+                               GLint size, GLenum type,
+                               GLuint relativeOffset)
+{
+   vertex_array_attrib_format(vaobj, attribIndex, size, type, GL_FALSE,
+                              GL_TRUE, GL_FALSE, ATTRIB_IFORMAT_TYPES_MASK,
+                              4, relativeOffset,
+                              "glVertexArrayAttribIFormat");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribLFormat(GLuint vaobj, GLuint attribIndex,
+                               GLint size, GLenum type,
+                               GLuint relativeOffset)
+{
+   vertex_array_attrib_format(vaobj, attribIndex, size, type, GL_FALSE,
+                              GL_FALSE, GL_TRUE, ATTRIB_LFORMAT_TYPES_MASK,
+                              4, relativeOffset,
+                              "glVertexArrayAttribLFormat");
+}
+
+
+static void
+vertex_array_attrib_binding(struct gl_context *ctx,
+                            struct gl_vertex_array_object *vao,
+                            GLuint attribIndex, GLuint bindingIndex,
+                            const char *func)
+{
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
    /* The ARB_vertex_attrib_binding spec says:
     *
     *    "<attribindex> must be less than the value of MAX_VERTEX_ATTRIBS and
@@ -1903,48 +2607,105 @@ _mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
     */
    if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
       _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glVertexAttribBinding(attribindex=%u >= "
+                  "%s(attribindex=%u >= "
                   "GL_MAX_VERTEX_ATTRIBS)",
-                  attribIndex);
+                  func, attribIndex);
       return;
    }
 
    if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) {
       _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glVertexAttribBinding(bindingindex=%u >= "
+                  "%s(bindingindex=%u >= "
                   "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
-                  bindingIndex);
+                  func, bindingIndex);
       return;
    }
 
-   assert(VERT_ATTRIB_GENERIC(attribIndex) <
-          ARRAY_SIZE(ctx->Array.VAO->VertexAttrib));
+   assert(VERT_ATTRIB_GENERIC(attribIndex) < ARRAY_SIZE(vao->VertexAttrib));
 
-   vertex_attrib_binding(ctx, VERT_ATTRIB_GENERIC(attribIndex),
+   vertex_attrib_binding(ctx, vao,
+                         VERT_ATTRIB_GENERIC(attribIndex),
                          VERT_ATTRIB_GENERIC(bindingIndex));
 }
 
 
 void GLAPIENTRY
-_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
+_mesa_VertexAttribBinding_no_error(GLuint attribIndex, GLuint bindingIndex)
 {
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
+   vertex_attrib_binding(ctx, ctx->Array.VAO,
+                         VERT_ATTRIB_GENERIC(attribIndex),
+                         VERT_ATTRIB_GENERIC(bindingIndex));
+}
 
-   if (!ctx->Extensions.ARB_instanced_arrays) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexBindingDivisor()");
-      return;
-   }
+
+void GLAPIENTRY
+_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
+{
+   GET_CURRENT_CONTEXT(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 &&
+   if ((ctx->API == API_OPENGL_CORE || _mesa_is_gles31(ctx)) &&
        ctx->Array.VAO == ctx->Array.DefaultVAO) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glVertexBindingDivisor(No array object bound)");
+                  "glVertexAttribBinding(No array object bound)");
+      return;
+   }
+
+   vertex_array_attrib_binding(ctx, ctx->Array.VAO,
+                               attribIndex, bindingIndex,
+                               "glVertexAttribBinding");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribBinding_no_error(GLuint vaobj, GLuint attribIndex,
+                                        GLuint bindingIndex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_vertex_array_object *vao = _mesa_lookup_vao(ctx, vaobj);
+   vertex_attrib_binding(ctx, vao,
+                         VERT_ATTRIB_GENERIC(attribIndex),
+                         VERT_ATTRIB_GENERIC(bindingIndex));
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribBinding(GLuint vaobj, GLuint attribIndex, GLuint bindingIndex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object *vao;
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *   "An INVALID_OPERATION error is generated by VertexArrayAttribBinding
+    *    if <vaobj> is not [compatibility profile: zero or] the name of an
+    *    existing vertex array object."
+    */
+   vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayAttribBinding");
+   if (!vao)
+      return;
+
+   vertex_array_attrib_binding(ctx, vao, attribIndex, bindingIndex,
+                               "glVertexArrayAttribBinding");
+}
+
+
+static void
+vertex_array_binding_divisor(struct gl_context *ctx,
+                             struct gl_vertex_array_object *vao,
+                             GLuint bindingIndex, GLuint divisor,
+                             const char *func)
+{
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ARB_instanced_arrays) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s()", func);
       return;
    }
 
@@ -1955,13 +2716,78 @@ _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
     */
    if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) {
       _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glVertexBindingDivisor(bindingindex=%u > "
+                  "%s(bindingindex=%u > "
                   "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
-                  bindingIndex);
+                  func, bindingIndex);
+      return;
+   }
+
+   vertex_binding_divisor(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex), divisor);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexBindingDivisor_no_error(GLuint bindingIndex, GLuint divisor)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   vertex_binding_divisor(ctx, ctx->Array.VAO,
+                          VERT_ATTRIB_GENERIC(bindingIndex), divisor);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
+{
+   GET_CURRENT_CONTEXT(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 || _mesa_is_gles31(ctx)) &&
+       ctx->Array.VAO == ctx->Array.DefaultVAO) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glVertexBindingDivisor(No array object bound)");
       return;
    }
 
-   vertex_binding_divisor(ctx, VERT_ATTRIB_GENERIC(bindingIndex), divisor);
+   vertex_array_binding_divisor(ctx, ctx->Array.VAO,
+                                bindingIndex, divisor,
+                                "glVertexBindingDivisor");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayBindingDivisor_no_error(GLuint vaobj, GLuint bindingIndex,
+                                         GLuint divisor)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_vertex_array_object *vao = _mesa_lookup_vao(ctx, vaobj);
+   vertex_binding_divisor(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex), divisor);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingIndex,
+                                GLuint divisor)
+{
+   struct gl_vertex_array_object *vao;
+   GET_CURRENT_CONTEXT(ctx);
+
+   /* The ARB_direct_state_access specification says:
+    *
+    *   "An INVALID_OPERATION error is generated by VertexArrayBindingDivisor
+    *    if <vaobj> is not [compatibility profile: zero or] the name of an
+    *    existing vertex array object."
+    */
+   vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayBindingDivisor");
+   if (!vao)
+       return;
+
+   vertex_array_binding_divisor(ctx, vao, bindingIndex, divisor,
+                                "glVertexArrayBindingDivisor");
 }
 
 
@@ -1970,16 +2796,14 @@ _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
  */
 void
 _mesa_copy_client_array(struct gl_context *ctx,
-                        struct gl_client_array *dst,
-                        struct gl_client_array *src)
+                        struct gl_vertex_array *dst,
+                        struct gl_vertex_array *src)
 {
    dst->Size = src->Size;
    dst->Type = src->Type;
    dst->Format = src->Format;
-   dst->Stride = src->Stride;
    dst->StrideB = src->StrideB;
    dst->Ptr = src->Ptr;
-   dst->Enabled = src->Enabled;
    dst->Normalized = src->Normalized;
    dst->Integer = src->Integer;
    dst->Doubles = src->Doubles;
@@ -1990,13 +2814,13 @@ _mesa_copy_client_array(struct gl_context *ctx,
 
 void
 _mesa_copy_vertex_attrib_array(struct gl_context *ctx,
-                               struct gl_vertex_attrib_array *dst,
-                               const struct gl_vertex_attrib_array *src)
+                               struct gl_array_attributes *dst,
+                               const struct gl_array_attributes *src)
 {
    dst->Size           = src->Size;
    dst->Type           = src->Type;
    dst->Format         = src->Format;
-   dst->VertexBinding  = src->VertexBinding;
+   dst->BufferBindingIndex = src->BufferBindingIndex;
    dst->RelativeOffset = src->RelativeOffset;
    dst->Format         = src->Format;
    dst->Integer        = src->Integer;
@@ -2020,55 +2844,43 @@ _mesa_copy_vertex_buffer_binding(struct gl_context *ctx,
    _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj);
 }
 
-/**
- * Print vertex array's fields.
- */
-static void
-print_array(const char *name, GLint index, const struct gl_client_array *array)
-{
-   if (index >= 0)
-      fprintf(stderr, "  %s[%d]: ", name, index);
-   else
-      fprintf(stderr, "  %s: ", name);
-   fprintf(stderr, "Ptr=%p, Type=0x%x, Size=%d, ElemSize=%u, Stride=%d, Buffer=%u(Size %lu)\n",
-         array->Ptr, array->Type, array->Size,
-         array->_ElementSize, array->StrideB,
-         array->BufferObj->Name, (unsigned long) array->BufferObj->Size);
-}
-
-
 /**
  * Print current vertex object/array info.  For debug.
  */
 void
 _mesa_print_arrays(struct gl_context *ctx)
 {
-   struct gl_vertex_array_object *vao = ctx->Array.VAO;
-   GLuint i;
+   const struct gl_vertex_array_object *vao = ctx->Array.VAO;
+
+   fprintf(stderr, "Array Object %u\n", vao->Name);
+
+   unsigned i;
+   for (i = 0; i < VERT_ATTRIB_MAX; ++i) {
+      const struct gl_array_attributes *array = &vao->VertexAttrib[i];
+      if (!array->Enabled)
+         continue;
 
-   printf("Array Object %u\n", vao->Name);
-   if (vao->_VertexAttrib[VERT_ATTRIB_POS].Enabled)
-      print_array("Vertex", -1, &vao->_VertexAttrib[VERT_ATTRIB_POS]);
-   if (vao->_VertexAttrib[VERT_ATTRIB_NORMAL].Enabled)
-      print_array("Normal", -1, &vao->_VertexAttrib[VERT_ATTRIB_NORMAL]);
-   if (vao->_VertexAttrib[VERT_ATTRIB_COLOR0].Enabled)
-      print_array("Color", -1, &vao->_VertexAttrib[VERT_ATTRIB_COLOR0]);
-   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++)
-      if (vao->_VertexAttrib[VERT_ATTRIB_TEX(i)].Enabled)
-         print_array("TexCoord", i, &vao->_VertexAttrib[VERT_ATTRIB_TEX(i)]);
-   for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++)
-      if (vao->_VertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
-         print_array("Attrib", i, &vao->_VertexAttrib[VERT_ATTRIB_GENERIC(i)]);
+      const struct gl_vertex_buffer_binding *binding =
+         &vao->BufferBinding[array->BufferBindingIndex];
+      const struct gl_buffer_object *bo = binding->BufferObj;
+
+      fprintf(stderr, "  %s: Ptr=%p, Type=%s, Size=%d, ElemSize=%u, "
+              "Stride=%d, Buffer=%u(Size %lu)\n",
+              gl_vert_attrib_name((gl_vert_attrib)i),
+              array->Ptr, _mesa_enum_to_string(array->Type), array->Size,
+              array->_ElementSize, binding->Stride, bo->Name,
+              (unsigned long) bo->Size);
+   }
 }
 
 
 /**
  * Initialize vertex array state for given context.
  */
-void 
+void
 _mesa_init_varray(struct gl_context *ctx)
 {
-   ctx->Array.DefaultVAO = ctx->Driver.NewArrayObject(ctx, 0);
+   ctx->Array.DefaultVAO = _mesa_new_vao(ctx, 0);
    _mesa_reference_vao(ctx, &ctx->Array.VAO, ctx->Array.DefaultVAO);
    ctx->Array.ActiveTexture = 0;   /* GL_ARB_multitexture */
 
@@ -2091,7 +2903,7 @@ delete_arrayobj_cb(GLuint id, void *data, void *userData)
 /**
  * Free vertex array state for given context.
  */
-void 
+void
 _mesa_free_varray_data(struct gl_context *ctx)
 {
    _mesa_HashDeleteAll(ctx->Array.Objects, delete_arrayobj_cb, ctx);