mesa: add EXT_dsa glVertexArray* functions declarations
[mesa.git] / src / mesa / main / varray.c
index 74d96b3212f028b7743aa261c1c5ad3904d45267..dd54be979d4f5c9d1b7bba8b23efb02f142782bf 100644 (file)
@@ -33,6 +33,7 @@
 #include "context.h"
 #include "enable.h"
 #include "enums.h"
+#include "glformats.h"
 #include "hash.h"
 #include "image.h"
 #include "macros.h"
@@ -125,32 +126,59 @@ type_to_bit(const struct gl_context *ctx, GLenum type)
 }
 
 
+/**
+ * Depending on the position and generic0 attributes enable flags select
+ * the one that is used for both attributes.
+ * The generic0 attribute takes precedence.
+ */
+static inline void
+update_attribute_map_mode(const struct gl_context *ctx,
+                          struct gl_vertex_array_object *vao)
+{
+   /*
+    * There is no need to change the mapping away from the
+    * identity mapping if we are not in compat mode.
+    */
+   if (ctx->API != API_OPENGL_COMPAT)
+      return;
+   /* The generic0 attribute superseeds the position attribute */
+   const GLbitfield enabled = vao->Enabled;
+   if (enabled & VERT_BIT_GENERIC0)
+      vao->_AttributeMapMode = ATTRIBUTE_MAP_MODE_GENERIC0;
+   else if (enabled & VERT_BIT_POS)
+      vao->_AttributeMapMode = ATTRIBUTE_MAP_MODE_POSITION;
+   else
+      vao->_AttributeMapMode = ATTRIBUTE_MAP_MODE_IDENTITY;
+}
+
+
 /**
  * Sets the BufferBindingIndex field for the vertex attribute given by
  * attribIndex.
  */
-static void
-vertex_attrib_binding(struct gl_context *ctx,
-                      struct gl_vertex_array_object *vao,
-                      GLuint attribIndex,
-                      GLuint bindingIndex)
+void
+_mesa_vertex_attrib_binding(struct gl_context *ctx,
+                            struct gl_vertex_array_object *vao,
+                            gl_vert_attrib attribIndex,
+                            GLuint bindingIndex)
 {
    struct gl_array_attributes *array = &vao->VertexAttrib[attribIndex];
+   assert(!vao->SharedAndImmutable);
 
    if (array->BufferBindingIndex != bindingIndex) {
-      const GLbitfield64 array_bit = VERT_BIT(attribIndex);
+      const GLbitfield array_bit = VERT_BIT(attribIndex);
 
       if (_mesa_is_bufferobj(vao->BufferBinding[bindingIndex].BufferObj))
          vao->VertexAttribBufferMask |= array_bit;
-
-      FLUSH_VERTICES(ctx, _NEW_ARRAY);
+      else
+         vao->VertexAttribBufferMask &= ~array_bit;
 
       vao->BufferBinding[array->BufferBindingIndex]._BoundArrays &= ~array_bit;
       vao->BufferBinding[bindingIndex]._BoundArrays |= array_bit;
 
       array->BufferBindingIndex = bindingIndex;
 
-      vao->NewArrays |= array_bit;
+      vao->NewArrays |= vao->Enabled & array_bit;
    }
 }
 
@@ -166,25 +194,27 @@ _mesa_bind_vertex_buffer(struct gl_context *ctx,
                          struct gl_buffer_object *vbo,
                          GLintptr offset, GLsizei stride)
 {
+   assert(index < ARRAY_SIZE(vao->BufferBinding));
+   assert(!vao->SharedAndImmutable);
    struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[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;
 
-      if (!_mesa_is_bufferobj(vbo))
+      if (!_mesa_is_bufferobj(vbo)) {
          vao->VertexAttribBufferMask &= ~binding->_BoundArrays;
-      else
+      } else {
          vao->VertexAttribBufferMask |= binding->_BoundArrays;
+         vbo->UsageHistory |= USAGE_ARRAY_BUFFER;
+      }
 
-      vao->NewArrays |= binding->_BoundArrays;
+      vao->NewArrays |= vao->Enabled & binding->_BoundArrays;
    }
 }
 
@@ -201,15 +231,33 @@ vertex_binding_divisor(struct gl_context *ctx,
 {
    struct gl_vertex_buffer_binding *binding =
       &vao->BufferBinding[bindingIndex];
+   assert(!vao->SharedAndImmutable);
 
    if (binding->InstanceDivisor != divisor) {
-      FLUSH_VERTICES(ctx, _NEW_ARRAY);
       binding->InstanceDivisor = divisor;
-      vao->NewArrays |= binding->_BoundArrays;
+      vao->NewArrays |= vao->Enabled & binding->_BoundArrays;
    }
 }
 
 
+void
+_mesa_set_vertex_format(struct gl_vertex_format *vertex_format,
+                        GLubyte size, GLenum16 type, GLenum16 format,
+                        GLboolean normalized, GLboolean integer,
+                        GLboolean doubles)
+{
+   assert(size <= 4);
+   vertex_format->Type = type;
+   vertex_format->Format = format;
+   vertex_format->Size = size;
+   vertex_format->Normalized = normalized;
+   vertex_format->Integer = integer;
+   vertex_format->Doubles = doubles;
+   vertex_format->_ElementSize = _mesa_bytes_per_vertex_attrib(size, type);
+   assert(vertex_format->_ElementSize <= 4*sizeof(double));
+}
+
+
 /**
  * Examine the API profile and extensions to determine which types are legal
  * for vertex arrays.  This is called once from update_array_format().
@@ -287,36 +335,25 @@ get_array_format(const struct gl_context *ctx, GLint sizeMax, GLint *size)
  * \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,
+                          gl_vert_attrib 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(!vao->SharedAndImmutable);
    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;
+   _mesa_set_vertex_format(&array->Format, size, type, format,
+                           normalized, integer, doubles);
 
-   vao->NewArrays |= VERT_BIT(attrib);
-   ctx->NewState |= _NEW_ARRAY;
+   vao->NewArrays |= vao->Enabled & VERT_BIT(attrib);
 }
 
 /**
@@ -447,6 +484,8 @@ validate_array_format(struct gl_context *ctx, const char *func,
  * Do error checking for glVertex/Color/TexCoord/...Pointer functions.
  *
  * \param func  name of calling function used for error reporting
+ * \param vao the vao to update
+ * \param obj the bound buffer object
  * \param attrib  the attribute array index to update
  * \param legalTypes  bitmask of *_BIT above indicating legal datatypes
  * \param sizeMin  min allowable size value
@@ -461,14 +500,14 @@ validate_array_format(struct gl_context *ctx, const char *func,
  */
 static void
 validate_array(struct gl_context *ctx, const char *func,
+               struct gl_vertex_array_object *vao,
+               struct gl_buffer_object *obj,
                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_array_object *vao = ctx->Array.VAO;
-
    /* Page 407 (page 423 of the PDF) of the OpenGL 3.0 spec says:
     *
     *     "Client vertex arrays - all vertex array attribute pointers must
@@ -490,7 +529,7 @@ validate_array(struct gl_context *ctx, const char *func,
       return;
    }
 
-   if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 &&
+   if (_mesa_is_desktop_gl(ctx) && ctx->Version >= 44 &&
        stride > ctx->Const.MaxVertexAttribStride) {
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride=%d > "
                   "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, stride);
@@ -510,7 +549,7 @@ validate_array(struct gl_context *ctx, const char *func,
     *       2.9.6), and the pointer argument is not NULL."
     */
    if (ptr != NULL && vao != ctx->Array.DefaultVAO &&
-       !_mesa_is_bufferobj(ctx->Array.ArrayBufferObj)) {
+       !_mesa_is_bufferobj(obj)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-VBO array)", func);
       return;
    }
@@ -519,15 +558,16 @@ validate_array(struct gl_context *ctx, const char *func,
 
 static bool
 validate_array_and_format(struct gl_context *ctx, const char *func,
+                          struct gl_vertex_array_object *vao,
+                          struct gl_buffer_object *obj,
                           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)
+                          GLboolean doubles, GLenum format, const GLvoid *ptr)
 {
-   validate_array(ctx, func, attrib, legalTypes, sizeMin, sizeMax, size,
-                  type, stride, normalized, integer, doubles, ptr);
+   validate_array(ctx, func, vao, obj, 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,
@@ -538,6 +578,8 @@ validate_array_and_format(struct gl_context *ctx, const char *func,
 /**
  * Update state for glVertex/Color/TexCoord/...Pointer functions.
  *
+ * \param vao the vao to update
+ * \param obj the bound buffer object
  * \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)
@@ -551,29 +593,35 @@ validate_array_and_format(struct gl_context *ctx, const char *func,
  */
 static void
 update_array(struct gl_context *ctx,
+             struct gl_vertex_array_object *vao,
+             struct gl_buffer_object *obj,
              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, vao, attrib, attrib);
+   _mesa_vertex_attrib_binding(ctx, vao, attrib, attrib);
 
    /* The Stride and Ptr fields are not set by update_array_format() */
    struct gl_array_attributes *array = &vao->VertexAttrib[attrib];
    array->Stride = stride;
+   /* For updating the pointer we would need to add the vao->NewArrays flag
+    * to the VAO. But but that is done already unconditionally in
+    * _mesa_update_array_format called above.
+    */
+   assert((vao->NewArrays | ~vao->Enabled) & VERT_BIT(attrib));
    array->Ptr = ptr;
 
    /* Update the vertex buffer binding */
-   GLsizei effectiveStride = stride != 0 ? stride : array->_ElementSize;
+   GLsizei effectiveStride = stride != 0 ?
+      stride : array->Format._ElementSize;
    _mesa_bind_vertex_buffer(ctx, vao, attrib,
-                            ctx->Array.ArrayBufferObj, (GLintptr) ptr,
+                            obj, (GLintptr) ptr,
                             effectiveStride);
 }
 
@@ -582,9 +630,9 @@ _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,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_POS, GL_RGBA, 4, size, type, stride,
                 GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -594,8 +642,6 @@ _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)
@@ -604,24 +650,34 @@ _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))
+   if (!validate_array_and_format(ctx, "glVertexPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                                  VERT_ATTRIB_POS, legalTypes, 2, 4, size,
+                                  type, stride, GL_FALSE, GL_FALSE, GL_FALSE,
+                                  format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_POS, format, 4, size, type, stride,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_POS, format, 4, size, type, stride,
                 GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayVertexOffsetEXT(GLuint vaobj, GLuint buffer, GLint size,
+                                 GLenum type, GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 void GLAPIENTRY
 _mesa_NormalPointer_no_error(GLenum type, GLsizei stride, const GLvoid *ptr )
 {
    GET_CURRENT_CONTEXT(ctx);
-   FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, VERT_ATTRIB_NORMAL, GL_RGBA, 3, 3, type, stride, GL_TRUE,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_NORMAL, GL_RGBA, 3, 3, type, stride, GL_TRUE,
                 GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -631,8 +687,6 @@ _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)
@@ -642,25 +696,35 @@ _mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr )
          INT_2_10_10_10_REV_BIT);
 
    if (!validate_array_and_format(ctx, "glNormalPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_NORMAL, legalTypes, 3, 3, 3,
                                   type, stride, GL_TRUE, GL_FALSE,
-                                  GL_FALSE, format, ptr, ctx->Array.VAO))
+                                  GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_NORMAL, format, 3, 3, type, stride, GL_TRUE,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_NORMAL, format, 3, 3, type, stride, GL_TRUE,
                 GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayNormalOffsetEXT(GLuint vaobj, GLuint buffer, GLenum type,
+                                 GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 void GLAPIENTRY
 _mesa_ColorPointer_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_COLOR0, format, BGRA_OR_4, size,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_COLOR0, format, BGRA_OR_4, size,
                 type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -671,8 +735,6 @@ _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)
@@ -684,24 +746,33 @@ _mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
          INT_2_10_10_10_REV_BIT);
 
    if (!validate_array_and_format(ctx, "glColorPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_COLOR0, legalTypes, sizeMin,
                                   BGRA_OR_4, size, type, stride, GL_TRUE,
-                                  GL_FALSE, GL_FALSE, format, ptr,
-                                  ctx->Array.VAO))
+                                  GL_FALSE, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_COLOR0, format, BGRA_OR_4, size,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_COLOR0, format, BGRA_OR_4, size,
                 type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayColorOffsetEXT(GLuint vaobj, GLuint buffer, GLint size,
+                                GLenum type, GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 void GLAPIENTRY
 _mesa_FogCoordPointer_no_error(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
-   FLUSH_VERTICES(ctx, 0);
 
-   update_array(ctx, VERT_ATTRIB_FOG, GL_RGBA, 1, 1, type, stride, GL_FALSE,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_FOG, GL_RGBA, 1, 1, type, stride, GL_FALSE,
                 GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -711,29 +782,37 @@ _mesa_FogCoordPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   FLUSH_VERTICES(ctx, 0);
-
    GLenum format = GL_RGBA;
    const GLbitfield legalTypes = (HALF_BIT | FLOAT_BIT | DOUBLE_BIT);
 
    if (!validate_array_and_format(ctx, "glFogCoordPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_FOG, legalTypes, 1, 1, 1,
                                   type, stride, GL_FALSE, GL_FALSE,
-                                  GL_FALSE, format, ptr, ctx->Array.VAO))
+                                  GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_FOG, format, 1, 1, type, stride, GL_FALSE,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_FOG, format, 1, 1, type, stride, GL_FALSE,
                 GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayFogCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLenum type,
+                                   GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 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,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_COLOR_INDEX, GL_RGBA, 1, 1, type, stride,
                 GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -743,33 +822,40 @@ _mesa_IndexPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   FLUSH_VERTICES(ctx, 0);
-
    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",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_COLOR_INDEX,
                                   legalTypes, 1, 1, 1, type, stride,
-                                  GL_FALSE, GL_FALSE, GL_FALSE, format,
-                                  ptr, ctx->Array.VAO))
+                                  GL_FALSE, GL_FALSE, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_COLOR_INDEX, format, 1, 1, type, stride,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_COLOR_INDEX, format, 1, 1, type, stride,
                 GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayIndexOffsetEXT(GLuint vaobj, GLuint buffer, GLenum type,
+                                GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 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,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_COLOR1, format, BGRA_OR_4, size, type,
                 stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -780,8 +866,6 @@ _mesa_SecondaryColorPointer(GLint size, GLenum type,
 {
    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 |
@@ -791,26 +875,35 @@ _mesa_SecondaryColorPointer(GLint size, GLenum type,
                                   INT_2_10_10_10_REV_BIT);
 
    if (!validate_array_and_format(ctx, "glSecondaryColorPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_COLOR1, legalTypes, 3,
                                   BGRA_OR_4, size, type, stride,
-                                  GL_TRUE, GL_FALSE, GL_FALSE, format, ptr,
-                                  ctx->Array.VAO))
+                                  GL_TRUE, GL_FALSE, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_COLOR1, format, BGRA_OR_4, size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_COLOR1, format, BGRA_OR_4, size, type,
                 stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArraySecondaryColorOffsetEXT(GLuint vaobj, GLuint buffer, GLint size,
+                                         GLenum type, GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 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, VERT_ATTRIB_TEX(unit), GL_RGBA, 4, size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_TEX(unit), GL_RGBA, 4, size, type,
                 stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -823,8 +916,6 @@ _mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride,
    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)
@@ -834,26 +925,44 @@ _mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride,
          INT_2_10_10_10_REV_BIT);
 
    if (!validate_array_and_format(ctx, "glTexCoordPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_TEX(unit), legalTypes,
                                   sizeMin, 4, size, type, stride,
-                                  GL_FALSE, GL_FALSE, GL_FALSE, format, ptr,
-                                  ctx->Array.VAO))
+                                  GL_FALSE, GL_FALSE, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_TEX(unit), format, 4, size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_TEX(unit), format, 4, size, type,
                 stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayTexCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLint size,
+                                   GLenum type, GLsizei stride, GLintptr offset)
+{
+
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayMultiTexCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLenum texunit,
+                                        GLint size, GLenum type, GLsizei stride,
+                                        GLintptr offset)
+{
+
+}
+
+
 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, VERT_ATTRIB_EDGEFLAG, GL_RGBA, 1, 1, GL_UNSIGNED_BYTE,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_EDGEFLAG, GL_RGBA, 1, 1, GL_UNSIGNED_BYTE,
                 stride, GL_FALSE, integer, GL_FALSE, ptr);
 }
 
@@ -865,31 +974,38 @@ _mesa_EdgeFlagPointer(GLsizei stride, const GLvoid *ptr)
    const GLboolean integer = GL_FALSE;
    GET_CURRENT_CONTEXT(ctx);
 
-   FLUSH_VERTICES(ctx, 0);
-
    GLenum format = GL_RGBA;
    const GLbitfield legalTypes = UNSIGNED_BYTE_BIT;
 
    if (!validate_array_and_format(ctx, "glEdgeFlagPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_EDGEFLAG, legalTypes,
                                   1, 1, 1, GL_UNSIGNED_BYTE, stride,
-                                  GL_FALSE, integer, GL_FALSE, format, ptr,
-                                  ctx->Array.VAO))
+                                  GL_FALSE, integer, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_EDGEFLAG, format, 1, 1, GL_UNSIGNED_BYTE,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_EDGEFLAG, format, 1, 1, GL_UNSIGNED_BYTE,
                 stride, GL_FALSE, integer, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayEdgeFlagOffsetEXT(GLuint vaobj, GLuint buffer, GLsizei stride,
+                                   GLintptr offset)
+{
+
+}
+
+
 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,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_POINT_SIZE, GL_RGBA, 1, 1, type, stride,
                 GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -899,8 +1015,6 @@ _mesa_PointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   FLUSH_VERTICES(ctx, 0);
-
    GLenum format = GL_RGBA;
    if (ctx->API != API_OPENGLES) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -911,12 +1025,14 @@ _mesa_PointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *ptr)
    const GLbitfield legalTypes = (FLOAT_BIT | FIXED_ES_BIT);
 
    if (!validate_array_and_format(ctx, "glPointSizePointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_POINT_SIZE, legalTypes,
                                   1, 1, 1, type, stride, GL_FALSE, GL_FALSE,
-                                  GL_FALSE, format, ptr, ctx->Array.VAO))
+                                  GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_POINT_SIZE, format, 1, 1, type, stride,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_POINT_SIZE, format, 1, 1, type, stride,
                 GL_FALSE, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -929,7 +1045,8 @@ _mesa_VertexAttribPointer_no_error(GLuint index, GLint size, GLenum type,
    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,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_GENERIC(index), format, BGRA_OR_4,
                 size, type, stride, normalized, GL_FALSE, GL_FALSE, ptr);
 }
 
@@ -962,17 +1079,27 @@ _mesa_VertexAttribPointer(GLuint index, GLint size, GLenum type,
                                   UNSIGNED_INT_10F_11F_11F_REV_BIT);
 
    if (!validate_array_and_format(ctx, "glVertexAttribPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_GENERIC(index), legalTypes,
                                   1, BGRA_OR_4, size, type, stride,
-                                  normalized, GL_FALSE, GL_FALSE, format,
-                                  ptr, ctx->Array.VAO))
+                                  normalized, GL_FALSE, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, BGRA_OR_4,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_GENERIC(index), format, BGRA_OR_4,
                 size, type, stride, normalized, GL_FALSE, GL_FALSE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayVertexAttribOffsetEXT(GLuint vaobj, GLuint buffer, GLuint index, GLint size,
+                                       GLenum type, GLboolean normalized,
+                                       GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 void GLAPIENTRY
 _mesa_VertexAttribIPointer_no_error(GLuint index, GLint size, GLenum type,
                                     GLsizei stride, const GLvoid *ptr)
@@ -981,7 +1108,8 @@ _mesa_VertexAttribIPointer_no_error(GLuint index, GLint size, GLenum type,
    const GLboolean integer = GL_TRUE;
    GET_CURRENT_CONTEXT(ctx);
 
-   update_array(ctx, VERT_ATTRIB_GENERIC(index), GL_RGBA, 4,  size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_GENERIC(index), GL_RGBA, 4,  size, type,
                 stride, normalized, integer, GL_FALSE, ptr);
 }
 
@@ -1011,13 +1139,14 @@ _mesa_VertexAttribIPointer(GLuint index, GLint size, GLenum type,
                                   INT_BIT | UNSIGNED_INT_BIT);
 
    if (!validate_array_and_format(ctx, "glVertexAttribIPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_GENERIC(index), legalTypes,
                                   1, 4, size, type, stride,
-                                  normalized, integer, GL_FALSE, format,
-                                  ptr, ctx->Array.VAO))
+                                  normalized, integer, GL_FALSE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, 4,  size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_GENERIC(index), format, 4,  size, type,
                 stride, normalized, integer, GL_FALSE, ptr);
 }
 
@@ -1028,11 +1157,20 @@ _mesa_VertexAttribLPointer_no_error(GLuint index, GLint size, GLenum type,
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   update_array(ctx, VERT_ATTRIB_GENERIC(index), GL_RGBA, 4, size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_GENERIC(index), GL_RGBA, 4, size, type,
                 stride, GL_FALSE, GL_FALSE, GL_TRUE, ptr);
 }
 
 
+void GLAPIENTRY
+_mesa_VertexArrayVertexAttribIOffsetEXT(GLuint vaobj, GLuint buffer, GLuint index, GLint size,
+                                        GLenum type, GLsizei stride, GLintptr offset)
+{
+
+}
+
+
 void GLAPIENTRY
 _mesa_VertexAttribLPointer(GLuint index, GLint size, GLenum type,
                            GLsizei stride, const GLvoid *ptr)
@@ -1048,30 +1186,36 @@ _mesa_VertexAttribLPointer(GLuint index, GLint size, GLenum type,
    const GLbitfield legalTypes = DOUBLE_BIT;
 
    if (!validate_array_and_format(ctx, "glVertexAttribLPointer",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
                                   VERT_ATTRIB_GENERIC(index), legalTypes,
                                   1, 4, size, type, stride,
-                                  GL_FALSE, GL_FALSE, GL_TRUE, format,
-                                  ptr, ctx->Array.VAO))
+                                  GL_FALSE, GL_FALSE, GL_TRUE, format, ptr))
       return;
 
-   update_array(ctx, VERT_ATTRIB_GENERIC(index), format, 4, size, type,
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                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)
+_mesa_enable_vertex_array_attribs(struct gl_context *ctx,
+                                  struct gl_vertex_array_object *vao,
+                                  GLbitfield attrib_bits)
 {
-   assert(attrib < ARRAY_SIZE(vao->VertexAttrib));
+   assert((attrib_bits & ~VERT_BIT_ALL) == 0);
+   assert(!vao->SharedAndImmutable);
 
-   if (!vao->VertexAttrib[attrib].Enabled) {
+   /* Only work on bits that are disabled */
+   attrib_bits &= ~vao->Enabled;
+   if (attrib_bits) {
       /* 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);
+      vao->Enabled |= attrib_bits;
+      vao->NewArrays |= attrib_bits;
+
+      /* Update the map mode if needed */
+      if (attrib_bits & (VERT_BIT_POS|VERT_BIT_GENERIC0))
+         update_attribute_map_mode(ctx, vao);
    }
 }
 
@@ -1099,6 +1243,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)
 {
@@ -1120,25 +1273,33 @@ _mesa_EnableVertexArrayAttrib(GLuint vaobj, GLuint index)
 }
 
 
-static void
-disable_vertex_array_attrib(struct gl_context *ctx,
-                            struct gl_vertex_array_object *vao,
-                            GLuint index,
-                            const char *func)
+void GLAPIENTRY
+_mesa_EnableVertexArrayAttrib_no_error(GLuint vaobj, GLuint index)
 {
-   if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
-      return;
-   }
+   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));
+}
 
-   assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(vao->VertexAttrib));
 
-   if (vao->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
+void
+_mesa_disable_vertex_array_attribs(struct gl_context *ctx,
+                                   struct gl_vertex_array_object *vao,
+                                   GLbitfield attrib_bits)
+{
+   assert((attrib_bits & ~VERT_BIT_ALL) == 0);
+   assert(!vao->SharedAndImmutable);
+
+   /* Only work on bits that are enabled */
+   attrib_bits &= vao->Enabled;
+   if (attrib_bits) {
       /* was enabled, now being disabled */
-      FLUSH_VERTICES(ctx, _NEW_ARRAY);
-      vao->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_FALSE;
-      vao->_Enabled &= ~VERT_BIT_GENERIC(index);
-      vao->NewArrays |= VERT_BIT_GENERIC(index);
+      vao->Enabled &= ~attrib_bits;
+      vao->NewArrays |= attrib_bits;
+
+      /* Update the map mode if needed */
+      if (attrib_bits & (VERT_BIT_POS|VERT_BIT_GENERIC0))
+         update_attribute_map_mode(ctx, vao);
    }
 }
 
@@ -1147,8 +1308,23 @@ 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;
+   }
+
+   const gl_vert_attrib attrib = VERT_ATTRIB_GENERIC(index);
+   _mesa_disable_vertex_array_attrib(ctx, ctx->Array.VAO, attrib);
+}
+
+
+void GLAPIENTRY
+_mesa_DisableVertexAttribArray_no_error(GLuint index)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   const gl_vert_attrib attrib = VERT_ATTRIB_GENERIC(index);
+   _mesa_disable_vertex_array_attrib(ctx, ctx->Array.VAO, attrib);
 }
 
 
@@ -1169,7 +1345,23 @@ _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;
+   }
+
+   const gl_vert_attrib attrib = VERT_ATTRIB_GENERIC(index);
+   _mesa_disable_vertex_array_attrib(ctx, vao, attrib);
+}
+
+
+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);
+   const gl_vert_attrib attrib = VERT_ATTRIB_GENERIC(index);
+   _mesa_disable_vertex_array_attrib(ctx, vao, attrib);
 }
 
 
@@ -1197,27 +1389,27 @@ get_vertex_array_attrib(struct gl_context *ctx,
 
    switch (pname) {
    case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
-      return array->Enabled;
+      return !!(vao->Enabled & VERT_BIT_GENERIC(index));
    case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB:
-      return (array->Format == GL_BGRA) ? GL_BGRA : array->Size;
+      return (array->Format.Format == GL_BGRA) ? GL_BGRA : array->Format.Size;
    case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB:
       return array->Stride;
    case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB:
-      return array->Type;
+      return array->Format.Type;
    case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
-      return array->Normalized;
+      return array->Format.Normalized;
    case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
       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))
           || _mesa_is_gles3(ctx)) {
-         return array->Integer;
+         return array->Format.Integer;
       }
       goto error;
    case GL_VERTEX_ATTRIB_ARRAY_LONG:
       if (_mesa_is_desktop_gl(ctx)) {
-         return array->Doubles;
+         return array->Format.Doubles;
       }
       goto error;
    case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB:
@@ -1604,6 +1796,33 @@ _mesa_TexCoordPointerEXT(GLint size, GLenum type, GLsizei stride,
 }
 
 
+void GLAPIENTRY
+_mesa_MultiTexCoordPointerEXT(GLenum texunit, GLint size, GLenum type,
+                              GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   const GLint sizeMin = 1;
+   const GLuint unit = texunit - GL_TEXTURE0;
+
+   GLenum format = GL_RGBA;
+   const GLbitfield legalTypes = (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);
+
+   if (!validate_array_and_format(ctx, "glMultiTexCoordPointerEXT",
+                                  ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                                  VERT_ATTRIB_TEX(unit), legalTypes,
+                                  sizeMin, 4, size, type, stride,
+                                  GL_FALSE, GL_FALSE, GL_FALSE, format, ptr))
+      return;
+
+   update_array(ctx, ctx->Array.VAO, ctx->Array.ArrayBufferObj,
+                VERT_ATTRIB_TEX(unit), format, 4, size, type,
+                stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr);
+}
+
+
 void GLAPIENTRY
 _mesa_EdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *ptr)
 {
@@ -1624,8 +1843,6 @@ _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
    GLint defstride;                /* default stride */
    GLint c, f;
 
-   FLUSH_VERTICES(ctx, 0);
-
    f = sizeof(GLfloat);
    c = f * ((4 * sizeof(GLubyte) + (f - 1)) / f);
 
@@ -1795,8 +2012,6 @@ _mesa_LockArraysEXT(GLint first, GLsizei count)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   FLUSH_VERTICES(ctx, 0);
-
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glLockArrays %d %d\n", first, count);
 
@@ -1815,8 +2030,6 @@ _mesa_LockArraysEXT(GLint first, GLsizei count)
 
    ctx->Array.LockFirst = first;
    ctx->Array.LockCount = count;
-
-   ctx->NewState |= _NEW_ARRAY;
 }
 
 
@@ -1825,8 +2038,6 @@ _mesa_UnlockArraysEXT( void )
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   FLUSH_VERTICES(ctx, 0);
-
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glUnlockArrays\n");
 
@@ -1837,56 +2048,27 @@ _mesa_UnlockArraysEXT( void )
 
    ctx->Array.LockFirst = 0;
    ctx->Array.LockCount = 0;
-   ctx->NewState |= _NEW_ARRAY;
 }
 
 
-/* GL_IBM_multimode_draw_arrays */
-void GLAPIENTRY
-_mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
-                             const GLsizei * count,
-                             GLsizei primcount, GLint modestride )
+static void
+primitive_restart_index(struct gl_context *ctx, GLuint index)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   GLint i;
-
-   FLUSH_VERTICES(ctx, 0);
-
-   for ( i = 0 ; i < primcount ; i++ ) {
-      if ( count[i] > 0 ) {
-         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
-        CALL_DrawArrays(ctx->CurrentServerDispatch, ( m, first[i], count[i] ));
-      }
-   }
+   ctx->Array.RestartIndex = index;
 }
 
 
-/* GL_IBM_multimode_draw_arrays */
+/**
+ * GL_NV_primitive_restart and GL 3.1
+ */
 void GLAPIENTRY
-_mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
-                               GLenum type, const GLvoid * const * indices,
-                               GLsizei primcount, GLint modestride )
+_mesa_PrimitiveRestartIndex_no_error(GLuint index)
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLint i;
-
-   FLUSH_VERTICES(ctx, 0);
-
-   /* XXX not sure about ARB_vertex_buffer_object handling here */
-
-   for ( i = 0 ; i < primcount ; i++ ) {
-      if ( count[i] > 0 ) {
-         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
-        CALL_DrawElements(ctx->CurrentServerDispatch, ( m, count[i], type,
-                                                        indices[i] ));
-      }
-   }
+   primitive_restart_index(ctx, index);
 }
 
 
-/**
- * GL_NV_primitive_restart and GL 3.1
- */
 void GLAPIENTRY
 _mesa_PrimitiveRestartIndex(GLuint index)
 {
@@ -1897,10 +2079,7 @@ _mesa_PrimitiveRestartIndex(GLuint index)
       return;
    }
 
-   if (ctx->Array.RestartIndex != index) {
-      FLUSH_VERTICES(ctx, 0);
-      ctx->Array.RestartIndex = index;
-   }
+   primitive_restart_index(ctx, index);
 }
 
 
@@ -1909,7 +2088,7 @@ _mesa_VertexAttribDivisor_no_error(GLuint index, GLuint divisor)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   const GLuint genericIndex = VERT_ATTRIB_GENERIC(index);
+   const gl_vert_attrib genericIndex = VERT_ATTRIB_GENERIC(index);
    struct gl_vertex_array_object * const vao = ctx->Array.VAO;
 
    assert(genericIndex < ARRAY_SIZE(vao->VertexAttrib));
@@ -1925,7 +2104,7 @@ _mesa_VertexAttribDivisor_no_error(GLuint index, GLuint divisor)
     *       VertexAttribBinding(index, index);
     *       VertexBindingDivisor(index, divisor);"
     */
-   vertex_attrib_binding(ctx, vao, genericIndex, genericIndex);
+   _mesa_vertex_attrib_binding(ctx, vao, genericIndex, genericIndex);
    vertex_binding_divisor(ctx, vao, genericIndex, divisor);
 }
 
@@ -1940,7 +2119,7 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   const GLuint genericIndex = VERT_ATTRIB_GENERIC(index);
+   const gl_vert_attrib genericIndex = VERT_ATTRIB_GENERIC(index);
    struct gl_vertex_array_object * const vao = ctx->Array.VAO;
 
    if (!ctx->Extensions.ARB_instanced_arrays) {
@@ -1967,7 +2146,7 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
     *       VertexAttribBinding(index, index);
     *       VertexBindingDivisor(index, divisor);"
     */
-   vertex_attrib_binding(ctx, vao, genericIndex, genericIndex);
+   _mesa_vertex_attrib_binding(ctx, vao, genericIndex, genericIndex);
    vertex_binding_divisor(ctx, vao, genericIndex, divisor);
 }
 
@@ -2058,7 +2237,7 @@ vertex_array_vertex_buffer_err(struct gl_context *ctx,
       return;
    }
 
-   if (((ctx->API == API_OPENGL_CORE && ctx->Version >= 44) || _mesa_is_gles31(ctx)) &&
+   if (((_mesa_is_desktop_gl(ctx) && 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);
@@ -2212,7 +2391,7 @@ vertex_array_vertex_buffers(struct gl_context *ctx,
             continue;
          }
 
-         if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 &&
+         if (_mesa_is_desktop_gl(ctx) && ctx->Version >= 44 &&
              strides[i] > ctx->Const.MaxVertexAttribStride) {
             _mesa_error(ctx, GL_INVALID_VALUE,
                         "%s(strides[%u]=%d > "
@@ -2402,8 +2581,6 @@ vertex_attrib_format(GLuint attribIndex, GLint size, GLenum type,
       }
    }
 
-   FLUSH_VERTICES(ctx, 0);
-
    _mesa_update_array_format(ctx, ctx->Array.VAO,
                              VERT_ATTRIB_GENERIC(attribIndex), size, type,
                              format, normalized, integer, doubles,
@@ -2492,8 +2669,6 @@ vertex_array_attrib_format(GLuint vaobj, GLuint attribIndex, GLint size,
       }
    }
 
-   FLUSH_VERTICES(ctx, 0);
-
    _mesa_update_array_format(ctx, vao, VERT_ATTRIB_GENERIC(attribIndex), size,
                              type, format, normalized, integer, doubles,
                              relativeOffset);
@@ -2569,9 +2744,9 @@ vertex_array_attrib_binding(struct gl_context *ctx,
 
    assert(VERT_ATTRIB_GENERIC(attribIndex) < ARRAY_SIZE(vao->VertexAttrib));
 
-   vertex_attrib_binding(ctx, vao,
-                         VERT_ATTRIB_GENERIC(attribIndex),
-                         VERT_ATTRIB_GENERIC(bindingIndex));
+   _mesa_vertex_attrib_binding(ctx, vao,
+                               VERT_ATTRIB_GENERIC(attribIndex),
+                               VERT_ATTRIB_GENERIC(bindingIndex));
 }
 
 
@@ -2579,9 +2754,9 @@ void GLAPIENTRY
 _mesa_VertexAttribBinding_no_error(GLuint attribIndex, GLuint bindingIndex)
 {
    GET_CURRENT_CONTEXT(ctx);
-   vertex_attrib_binding(ctx, ctx->Array.VAO,
-                         VERT_ATTRIB_GENERIC(attribIndex),
-                         VERT_ATTRIB_GENERIC(bindingIndex));
+   _mesa_vertex_attrib_binding(ctx, ctx->Array.VAO,
+                               VERT_ATTRIB_GENERIC(attribIndex),
+                               VERT_ATTRIB_GENERIC(bindingIndex));
 }
 
 
@@ -2615,9 +2790,9 @@ _mesa_VertexArrayAttribBinding_no_error(GLuint vaobj, GLuint attribIndex,
    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));
+   _mesa_vertex_attrib_binding(ctx, vao,
+                               VERT_ATTRIB_GENERIC(attribIndex),
+                               VERT_ATTRIB_GENERIC(bindingIndex));
 }
 
 
@@ -2672,6 +2847,15 @@ vertex_array_binding_divisor(struct gl_context *ctx,
 }
 
 
+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)
 {
@@ -2695,6 +2879,17 @@ _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
 }
 
 
+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)
@@ -2717,44 +2912,18 @@ _mesa_VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingIndex,
 }
 
 
-/**
- * Copy one client vertex array to another.
- */
-void
-_mesa_copy_client_array(struct gl_context *ctx,
-                        struct gl_vertex_array *dst,
-                        struct gl_vertex_array *src)
-{
-   dst->Size = src->Size;
-   dst->Type = src->Type;
-   dst->Format = src->Format;
-   dst->StrideB = src->StrideB;
-   dst->Ptr = src->Ptr;
-   dst->Normalized = src->Normalized;
-   dst->Integer = src->Integer;
-   dst->Doubles = src->Doubles;
-   dst->InstanceDivisor = src->InstanceDivisor;
-   dst->_ElementSize = src->_ElementSize;
-   _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj);
-}
-
 void
 _mesa_copy_vertex_attrib_array(struct gl_context *ctx,
                                struct gl_array_attributes *dst,
                                const struct gl_array_attributes *src)
 {
-   dst->Size           = src->Size;
-   dst->Type           = src->Type;
-   dst->Format         = src->Format;
-   dst->BufferBindingIndex = src->BufferBindingIndex;
+   dst->Ptr            = src->Ptr;
    dst->RelativeOffset = src->RelativeOffset;
    dst->Format         = src->Format;
-   dst->Integer        = src->Integer;
-   dst->Doubles        = src->Doubles;
-   dst->Normalized     = src->Normalized;
-   dst->Ptr            = src->Ptr;
-   dst->Enabled        = src->Enabled;
-   dst->_ElementSize   = src->_ElementSize;
+   dst->Stride         = src->Stride;
+   dst->BufferBindingIndex = src->BufferBindingIndex;
+   dst->_EffBufferBindingIndex = src->_EffBufferBindingIndex;
+   dst->_EffRelativeOffset = src->_EffRelativeOffset;
 }
 
 void
@@ -2766,6 +2935,8 @@ _mesa_copy_vertex_buffer_binding(struct gl_context *ctx,
    dst->Stride          = src->Stride;
    dst->InstanceDivisor = src->InstanceDivisor;
    dst->_BoundArrays    = src->_BoundArrays;
+   dst->_EffBoundArrays = src->_EffBoundArrays;
+   dst->_EffOffset      = src->_EffOffset;
 
    _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj);
 }
@@ -2780,11 +2951,10 @@ _mesa_print_arrays(struct gl_context *ctx)
 
    fprintf(stderr, "Array Object %u\n", vao->Name);
 
-   unsigned i;
-   for (i = 0; i < VERT_ATTRIB_MAX; ++i) {
+   GLbitfield mask = vao->Enabled;
+   while (mask) {
+      const gl_vert_attrib i = u_bit_scan(&mask);
       const struct gl_array_attributes *array = &vao->VertexAttrib[i];
-      if (!array->Enabled)
-         continue;
 
       const struct gl_vertex_buffer_binding *binding =
          &vao->BufferBinding[array->BufferBindingIndex];
@@ -2793,8 +2963,9 @@ _mesa_print_arrays(struct gl_context *ctx)
       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,
+              array->Ptr, _mesa_enum_to_string(array->Format.Type),
+              array->Format.Size,
+              array->Format._ElementSize, binding->Stride, bo->Name,
               (unsigned long) bo->Size);
    }
 }
@@ -2808,6 +2979,8 @@ _mesa_init_varray(struct gl_context *ctx)
 {
    ctx->Array.DefaultVAO = _mesa_new_vao(ctx, 0);
    _mesa_reference_vao(ctx, &ctx->Array.VAO, ctx->Array.DefaultVAO);
+   ctx->Array._EmptyVAO = _mesa_new_vao(ctx, ~0u);
+   _mesa_reference_vao(ctx, &ctx->Array._DrawVAO, ctx->Array._EmptyVAO);
    ctx->Array.ActiveTexture = 0;   /* GL_ARB_multitexture */
 
    ctx->Array.Objects = _mesa_NewHashTable();