[Mesa-dev] [PATCH] mesa: Make gl_vertex_array contain pointers to first order VAO members.

Mathias.Froehlich at gmx.net Mathias.Froehlich at gmx.net
Fri Mar 9 07:32:54 UTC 2018


From: Mathias Fröhlich <mathias.froehlich at web.de>

Hi Brian,

The updated patch to be sure. The changes with removing the gl prefix lead to
an other small change in _tnl_import_array not to have attrib twice in the
argument list. Therefore the v2 again for review.
I did also rename the current values from curr_glattrib to current without
being requested by review.
So, to be sure: your RB is still valid for v2 then?

Plenty thanks for your review these weeks!!
best

Mathias




Instead of keeping a copy of the vertex array content in
struct gl_vertex_array only keep pointers to the first order
information originaly in the VAO.
For that represent the current values by struct gl_array_attributes
and struct gl_vertex_buffer_binding.

v2: Change comments.
    Remove gl... prefix from variables except in the i965 directory where
    it was like that before. Reindent because of that.

Signed-off-by: Mathias Fröhlich <Mathias.Froehlich at web.de>
---
 src/mesa/drivers/dri/i965/brw_context.h       |   2 +-
 src/mesa/drivers/dri/i965/brw_draw.c          |  28 +++---
 src/mesa/drivers/dri/i965/brw_draw_upload.c   | 130 ++++++++++++++------------
 src/mesa/drivers/dri/i965/genX_state_upload.c |  23 +++--
 src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c  |  81 +++++++++-------
 src/mesa/main/arrayobj.c                      |  16 ----
 src/mesa/main/attrib.c                        |   1 -
 src/mesa/main/mtypes.h                        |  47 +++-------
 src/mesa/main/varray.c                        |  21 -----
 src/mesa/main/varray.h                        |  49 +++-------
 src/mesa/state_tracker/st_atom.c              |   7 +-
 src/mesa/state_tracker/st_atom_array.c        | 115 ++++++++++++++---------
 src/mesa/state_tracker/st_cb_rasterpos.c      |  26 +++---
 src/mesa/state_tracker/st_draw_feedback.c     |  46 ++++++---
 src/mesa/tnl/t_draw.c                         |  95 ++++++++++---------
 src/mesa/tnl/t_rebase.c                       |  20 ++--
 src/mesa/tnl/t_rebase.h                       |   2 +-
 src/mesa/vbo/vbo.h                            |   4 +-
 src/mesa/vbo/vbo_context.c                    |  52 +++++------
 src/mesa/vbo/vbo_exec.c                       |  16 ++--
 src/mesa/vbo/vbo_exec_api.c                   |  22 ++---
 src/mesa/vbo/vbo_private.h                    |   3 +-
 src/mesa/vbo/vbo_save_draw.c                  |   2 +-
 src/mesa/vbo/vbo_split.c                      |   2 +-
 src/mesa/vbo/vbo_split.h                      |   4 +-
 src/mesa/vbo/vbo_split_copy.c                 |  97 +++++++++++--------
 src/mesa/vbo/vbo_split_inplace.c              |   6 +-
 27 files changed, 480 insertions(+), 437 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index d3e7c71207..177273c364 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -1459,7 +1459,7 @@ gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx);
 
 /* brw_draw_upload.c */
 unsigned brw_get_vertex_surface_type(struct brw_context *brw,
-                                     const struct gl_vertex_array *glarray);
+                                     const struct gl_array_attributes *glattr);
 
 static inline unsigned
 brw_get_index_type(unsigned index_size)
diff --git a/src/mesa/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c
index 299e7f929e..0d1ae8982c 100644
--- a/src/mesa/drivers/dri/i965/brw_draw.c
+++ b/src/mesa/drivers/dri/i965/brw_draw.c
@@ -277,7 +277,7 @@ brw_emit_prim(struct brw_context *brw,
 
 static void
 brw_merge_inputs(struct brw_context *brw,
-                 const struct gl_vertex_array *arrays[])
+                 const struct gl_vertex_array *arrays)
 {
    const struct gen_device_info *devinfo = &brw->screen->devinfo;
    const struct gl_context *ctx = &brw->ctx;
@@ -291,7 +291,7 @@ brw_merge_inputs(struct brw_context *brw,
 
    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
       brw->vb.inputs[i].buffer = -1;
-      brw->vb.inputs[i].glarray = arrays[i];
+      brw->vb.inputs[i].glarray = &arrays[i];
    }
 
    if (devinfo->gen < 8 && !devinfo->is_haswell) {
@@ -300,14 +300,16 @@ brw_merge_inputs(struct brw_context *brw,
        * 2_10_10_10_REV vertex formats.  Set appropriate workaround flags.
        */
       while (mask) {
+         const struct gl_array_attributes *glattrib;
          uint8_t wa_flags = 0;
 
          i = u_bit_scan64(&mask);
+         glattrib = brw->vb.inputs[i].glarray->VertexAttrib;
 
-         switch (brw->vb.inputs[i].glarray->Type) {
+         switch (glattrib->Type) {
 
          case GL_FIXED:
-            wa_flags = brw->vb.inputs[i].glarray->Size;
+            wa_flags = glattrib->Size;
             break;
 
          case GL_INT_2_10_10_10_REV:
@@ -315,12 +317,12 @@ brw_merge_inputs(struct brw_context *brw,
             /* fallthough */
 
          case GL_UNSIGNED_INT_2_10_10_10_REV:
-            if (brw->vb.inputs[i].glarray->Format == GL_BGRA)
+            if (glattrib->Format == GL_BGRA)
                wa_flags |= BRW_ATTRIB_WA_BGRA;
 
-            if (brw->vb.inputs[i].glarray->Normalized)
+            if (glattrib->Normalized)
                wa_flags |= BRW_ATTRIB_WA_NORMALIZE;
-            else if (!brw->vb.inputs[i].glarray->Integer)
+            else if (!glattrib->Integer)
                wa_flags |= BRW_ATTRIB_WA_SCALE;
 
             break;
@@ -689,7 +691,7 @@ brw_postdraw_reconcile_align_wa_slices(struct brw_context *brw)
 
 static void
 brw_prepare_drawing(struct gl_context *ctx,
-                    const struct gl_vertex_array *arrays[],
+                    const struct gl_vertex_array *arrays,
                     const struct _mesa_index_buffer *ib,
                     bool index_bounds_valid,
                     GLuint min_index,
@@ -776,7 +778,7 @@ brw_finish_drawing(struct gl_context *ctx)
  */
 static void
 brw_draw_single_prim(struct gl_context *ctx,
-                     const struct gl_vertex_array *arrays[],
+                     const struct gl_vertex_array *arrays,
                      const struct _mesa_prim *prim,
                      unsigned prim_id,
                      struct brw_transform_feedback_object *xfb_obj,
@@ -911,13 +913,13 @@ retry:
 
 
 static bool
-all_varyings_in_vbos(const struct gl_vertex_array *arrays[])
+all_varyings_in_vbos(const struct gl_vertex_array *arrays)
 {
    GLuint i;
 
    for (i = 0; i < VERT_ATTRIB_MAX; i++)
-      if (arrays[i]->StrideB &&
-          arrays[i]->BufferObj->Name == 0)
+      if (arrays[i].BufferBinding->Stride &&
+          arrays[i].BufferBinding->BufferObj->Name == 0)
          return false;
 
    return true;
@@ -939,7 +941,7 @@ brw_draw_prims(struct gl_context *ctx,
 {
    unsigned i;
    struct brw_context *brw = brw_context(ctx);
-   const struct gl_vertex_array **arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *arrays = ctx->Array._DrawArrays;
    int predicate_state = brw->predicate.state;
    struct brw_transform_feedback_object *xfb_obj =
       (struct brw_transform_feedback_object *) gl_xfb_obj;
diff --git a/src/mesa/drivers/dri/i965/brw_draw_upload.c b/src/mesa/drivers/dri/i965/brw_draw_upload.c
index c058064403..4ede33aea1 100644
--- a/src/mesa/drivers/dri/i965/brw_draw_upload.c
+++ b/src/mesa/drivers/dri/i965/brw_draw_upload.c
@@ -249,21 +249,21 @@ double_types(struct brw_context *brw,
  */
 unsigned
 brw_get_vertex_surface_type(struct brw_context *brw,
-                            const struct gl_vertex_array *glarray)
+                            const struct gl_array_attributes *glattrib)
 {
-   int size = glarray->Size;
+   int size = glattrib->Size;
    const struct gen_device_info *devinfo = &brw->screen->devinfo;
    const bool is_ivybridge_or_older =
       devinfo->gen <= 7 && !devinfo->is_baytrail && !devinfo->is_haswell;
 
    if (unlikely(INTEL_DEBUG & DEBUG_VERTS))
       fprintf(stderr, "type %s size %d normalized %d\n",
-              _mesa_enum_to_string(glarray->Type),
-              glarray->Size, glarray->Normalized);
+              _mesa_enum_to_string(glattrib->Type),
+              glattrib->Size, glattrib->Normalized);
 
-   if (glarray->Integer) {
-      assert(glarray->Format == GL_RGBA); /* sanity check */
-      switch (glarray->Type) {
+   if (glattrib->Integer) {
+      assert(glattrib->Format == GL_RGBA); /* sanity check */
+      switch (glattrib->Type) {
       case GL_INT: return int_types_direct[size];
       case GL_SHORT:
          if (is_ivybridge_or_older && size == 3)
@@ -288,11 +288,11 @@ brw_get_vertex_surface_type(struct brw_context *brw,
             return ubyte_types_direct[size];
       default: unreachable("not reached");
       }
-   } else if (glarray->Type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
+   } else if (glattrib->Type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
       return ISL_FORMAT_R11G11B10_FLOAT;
-   } else if (glarray->Normalized) {
-      switch (glarray->Type) {
-      case GL_DOUBLE: return double_types(brw, size, glarray->Doubles);
+   } else if (glattrib->Normalized) {
+      switch (glattrib->Type) {
+      case GL_DOUBLE: return double_types(brw, size, glattrib->Doubles);
       case GL_FLOAT: return float_types[size];
       case GL_HALF_FLOAT:
       case GL_HALF_FLOAT_OES:
@@ -306,7 +306,7 @@ brw_get_vertex_surface_type(struct brw_context *brw,
       case GL_UNSIGNED_INT: return uint_types_norm[size];
       case GL_UNSIGNED_SHORT: return ushort_types_norm[size];
       case GL_UNSIGNED_BYTE:
-         if (glarray->Format == GL_BGRA) {
+         if (glattrib->Format == GL_BGRA) {
             /* See GL_EXT_vertex_array_bgra */
             assert(size == 4);
             return ISL_FORMAT_B8G8R8A8_UNORM;
@@ -330,7 +330,7 @@ brw_get_vertex_surface_type(struct brw_context *brw,
       case GL_INT_2_10_10_10_REV:
          assert(size == 4);
          if (devinfo->gen >= 8 || devinfo->is_haswell) {
-            return glarray->Format == GL_BGRA
+            return glattrib->Format == GL_BGRA
                ? ISL_FORMAT_B10G10R10A2_SNORM
                : ISL_FORMAT_R10G10B10A2_SNORM;
          }
@@ -338,7 +338,7 @@ brw_get_vertex_surface_type(struct brw_context *brw,
       case GL_UNSIGNED_INT_2_10_10_10_REV:
          assert(size == 4);
          if (devinfo->gen >= 8 || devinfo->is_haswell) {
-            return glarray->Format == GL_BGRA
+            return glattrib->Format == GL_BGRA
                ? ISL_FORMAT_B10G10R10A2_UNORM
                : ISL_FORMAT_R10G10B10A2_UNORM;
          }
@@ -352,26 +352,26 @@ brw_get_vertex_surface_type(struct brw_context *brw,
        * like to use here, so upload everything as UINT and fix
        * it in the shader
        */
-      if (glarray->Type == GL_INT_2_10_10_10_REV) {
+      if (glattrib->Type == GL_INT_2_10_10_10_REV) {
          assert(size == 4);
          if (devinfo->gen >= 8 || devinfo->is_haswell) {
-            return glarray->Format == GL_BGRA
+            return glattrib->Format == GL_BGRA
                ? ISL_FORMAT_B10G10R10A2_SSCALED
                : ISL_FORMAT_R10G10B10A2_SSCALED;
          }
          return ISL_FORMAT_R10G10B10A2_UINT;
-      } else if (glarray->Type == GL_UNSIGNED_INT_2_10_10_10_REV) {
+      } else if (glattrib->Type == GL_UNSIGNED_INT_2_10_10_10_REV) {
          assert(size == 4);
          if (devinfo->gen >= 8 || devinfo->is_haswell) {
-            return glarray->Format == GL_BGRA
+            return glattrib->Format == GL_BGRA
                ? ISL_FORMAT_B10G10R10A2_USCALED
                : ISL_FORMAT_R10G10B10A2_USCALED;
          }
          return ISL_FORMAT_R10G10B10A2_UINT;
       }
-      assert(glarray->Format == GL_RGBA); /* sanity check */
-      switch (glarray->Type) {
-      case GL_DOUBLE: return double_types(brw, size, glarray->Doubles);
+      assert(glattrib->Format == GL_RGBA); /* sanity check */
+      switch (glattrib->Type) {
+      case GL_DOUBLE: return double_types(brw, size, glattrib->Doubles);
       case GL_FLOAT: return float_types[size];
       case GL_HALF_FLOAT:
       case GL_HALF_FLOAT_OES:
@@ -405,24 +405,25 @@ copy_array_to_vbo_array(struct brw_context *brw,
 			struct brw_vertex_buffer *buffer,
 			GLuint dst_stride)
 {
-   const int src_stride = element->glarray->StrideB;
+   const struct gl_vertex_array *glarray = element->glarray;
+   const struct gl_vertex_buffer_binding *glbinding = glarray->BufferBinding;
+   const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+   const int src_stride = glbinding->Stride;
 
    /* If the source stride is zero, we just want to upload the current
     * attribute once and set the buffer's stride to 0.  There's no need
     * to replicate it out.
     */
    if (src_stride == 0) {
-      brw_upload_data(&brw->upload, element->glarray->Ptr,
-                      element->glarray->_ElementSize,
-                      element->glarray->_ElementSize,
-                      &buffer->bo, &buffer->offset);
+      brw_upload_data(&brw->upload, glattrib->Ptr, glattrib->_ElementSize,
+                      glattrib->_ElementSize, &buffer->bo, &buffer->offset);
 
       buffer->stride = 0;
-      buffer->size = element->glarray->_ElementSize;
+      buffer->size = glattrib->_ElementSize;
       return;
    }
 
-   const unsigned char *src = element->glarray->Ptr + min * src_stride;
+   const unsigned char *src = glattrib->Ptr + min * src_stride;
    int count = max - min + 1;
    GLuint size = count * dst_stride;
    uint8_t *dst = brw_upload_space(&brw->upload, size, dst_stride,
@@ -514,28 +515,30 @@ brw_prepare_vertices(struct brw_context *brw)
    for (i = j = 0; i < brw->vb.nr_enabled; i++) {
       struct brw_vertex_element *input = brw->vb.enabled[i];
       const struct gl_vertex_array *glarray = input->glarray;
+      const struct gl_vertex_buffer_binding *glbinding = glarray->BufferBinding;
+      const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
 
-      if (_mesa_is_bufferobj(glarray->BufferObj)) {
+      if (_mesa_is_bufferobj(glbinding->BufferObj)) {
 	 struct intel_buffer_object *intel_buffer =
-	    intel_buffer_object(glarray->BufferObj);
+	    intel_buffer_object(glbinding->BufferObj);
 
-         const uint32_t offset = (uintptr_t)glarray->Ptr;
+         const uint32_t offset = glbinding->Offset + glattrib->RelativeOffset;
 
          /* Start with the worst case */
          uint32_t start = 0;
          uint32_t range = intel_buffer->Base.Size;
-         if (glarray->InstanceDivisor) {
+         if (glbinding->InstanceDivisor) {
             if (brw->num_instances) {
-               start = offset + glarray->StrideB * brw->baseinstance;
-               range = (glarray->StrideB * ((brw->num_instances - 1) /
-                                            glarray->InstanceDivisor) +
-                        glarray->_ElementSize);
+               start = offset + glbinding->Stride * brw->baseinstance;
+               range = (glbinding->Stride * ((brw->num_instances - 1) /
+                                            glbinding->InstanceDivisor) +
+                        glattrib->_ElementSize);
             }
          } else {
             if (brw->vb.index_bounds_valid) {
-               start = offset + min_index * glarray->StrideB;
-               range = (glarray->StrideB * (max_index - min_index) +
-                        glarray->_ElementSize);
+               start = offset + min_index * glbinding->Stride;
+               range = (glbinding->Stride * (max_index - min_index) +
+                        glattrib->_ElementSize);
             }
          }
 
@@ -546,13 +549,16 @@ brw_prepare_vertices(struct brw_context *brw)
 	 unsigned k;
 	 for (k = 0; k < i; k++) {
 	    const struct gl_vertex_array *other = brw->vb.enabled[k]->glarray;
-	    if (glarray->BufferObj == other->BufferObj &&
-		glarray->StrideB == other->StrideB &&
-		glarray->InstanceDivisor == other->InstanceDivisor &&
-		(uintptr_t)(glarray->Ptr - other->Ptr) < glarray->StrideB)
+            const struct gl_vertex_buffer_binding *obind = other->BufferBinding;
+            const struct gl_array_attributes *oattrib = other->VertexAttrib;
+            const uint32_t ooffset = obind->Offset + oattrib->RelativeOffset;
+	    if (glbinding->BufferObj == obind->BufferObj &&
+		glbinding->Stride == obind->Stride &&
+		glbinding->InstanceDivisor == obind->InstanceDivisor &&
+                (offset - ooffset) < glbinding->Stride)
 	    {
 	       input->buffer = brw->vb.enabled[k]->buffer;
-	       input->offset = glarray->Ptr - other->Ptr;
+               input->offset = offset - ooffset;
 
                buffer_range_start[input->buffer] =
                   MIN2(buffer_range_start[input->buffer], start);
@@ -566,9 +572,9 @@ brw_prepare_vertices(struct brw_context *brw)
 
 	    /* Named buffer object: Just reference its contents directly. */
 	    buffer->offset = offset;
-	    buffer->stride = glarray->StrideB;
-	    buffer->step_rate = glarray->InstanceDivisor;
-            buffer->size = glarray->BufferObj->Size - offset;
+            buffer->stride = glbinding->Stride;
+            buffer->step_rate = glbinding->InstanceDivisor;
+            buffer->size = glbinding->BufferObj->Size - offset;
 
             enabled_buffer[j] = intel_buffer;
             buffer_range_start[j] = start;
@@ -582,13 +588,13 @@ brw_prepare_vertices(struct brw_context *brw)
 	  * when we've decided if we're doing interleaved or not.
 	  */
 	 if (nr_uploads == 0) {
-	    interleaved = glarray->StrideB;
-	    ptr = glarray->Ptr;
+            interleaved = glbinding->Stride;
+            ptr = glattrib->Ptr;
 	 }
-	 else if (interleaved != glarray->StrideB ||
-                  glarray->InstanceDivisor != 0 ||
-                  glarray->Ptr < ptr ||
-                  (uintptr_t)(glarray->Ptr - ptr) + glarray->_ElementSize > interleaved)
+	 else if (interleaved != glbinding->Stride ||
+                  glbinding->InstanceDivisor != 0 ||
+                  glattrib->Ptr < ptr ||
+                  (uintptr_t)(glattrib->Ptr - ptr) + glattrib->_ElementSize > interleaved)
 	 {
             /* If our stride is different from the first attribute's stride,
              * or if we are using an instance divisor or if the first
@@ -654,9 +660,10 @@ brw_prepare_vertices(struct brw_context *brw)
          buffer->step_rate = 0;
 
 	 for (i = 0; i < nr_uploads; i++) {
+            const struct gl_vertex_array *glarray = upload[i]->glarray;
+            const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
 	    /* Then, just point upload[i] at upload[0]'s buffer. */
-	    upload[i]->offset =
-	       ((const unsigned char *)upload[i]->glarray->Ptr - ptr);
+            upload[i]->offset = ((const unsigned char *)glattrib->Ptr - ptr);
 	    upload[i]->buffer = j;
 	 }
 	 j++;
@@ -667,22 +674,25 @@ brw_prepare_vertices(struct brw_context *brw)
    /* Upload non-interleaved arrays */
    for (i = 0; i < nr_uploads; i++) {
       struct brw_vertex_buffer *buffer = &brw->vb.buffers[j];
-      if (upload[i]->glarray->InstanceDivisor == 0) {
+      const struct gl_vertex_array *glarray = upload[i]->glarray;
+      const struct gl_vertex_buffer_binding *glbinding = glarray->BufferBinding;
+      const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+      if (glbinding->InstanceDivisor == 0) {
          copy_array_to_vbo_array(brw, upload[i], min_index, max_index,
-                                 buffer, upload[i]->glarray->_ElementSize);
+                                 buffer, glattrib->_ElementSize);
       } else {
          /* This is an instanced attribute, since its InstanceDivisor
           * is not zero. Therefore, its data will be stepped after the
           * instanced draw has been run InstanceDivisor times.
           */
          uint32_t instanced_attr_max_index =
-            (brw->num_instances - 1) / upload[i]->glarray->InstanceDivisor;
+            (brw->num_instances - 1) / glbinding->InstanceDivisor;
          copy_array_to_vbo_array(brw, upload[i], 0, instanced_attr_max_index,
-                                 buffer, upload[i]->glarray->_ElementSize);
+                                 buffer, glattrib->_ElementSize);
       }
       buffer->offset -= delta * buffer->stride;
       buffer->size += delta * buffer->stride;
-      buffer->step_rate = upload[i]->glarray->InstanceDivisor;
+      buffer->step_rate = glbinding->InstanceDivisor;
       upload[i]->buffer = j++;
       upload[i]->offset = 0;
    }
diff --git a/src/mesa/drivers/dri/i965/genX_state_upload.c b/src/mesa/drivers/dri/i965/genX_state_upload.c
index 211fae58e9..a69a496f1d 100644
--- a/src/mesa/drivers/dri/i965/genX_state_upload.c
+++ b/src/mesa/drivers/dri/i965/genX_state_upload.c
@@ -553,7 +553,9 @@ genX(emit_vertices)(struct brw_context *brw)
     */
    for (unsigned i = 0; i < brw->vb.nr_enabled; i++) {
       struct brw_vertex_element *input = brw->vb.enabled[i];
-      uint32_t format = brw_get_vertex_surface_type(brw, input->glarray);
+      const struct gl_vertex_array *glarray = input->glarray;
+      const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+      uint32_t format = brw_get_vertex_surface_type(brw, glattrib);
 
       if (uploads_needed(format, input->is_dual_slot) > 1)
          nr_elements++;
@@ -646,7 +648,9 @@ genX(emit_vertices)(struct brw_context *brw)
    unsigned i;
    for (i = 0; i < brw->vb.nr_enabled; i++) {
       const struct brw_vertex_element *input = brw->vb.enabled[i];
-      uint32_t format = brw_get_vertex_surface_type(brw, input->glarray);
+      const struct gl_vertex_array *glarray = input->glarray;
+      const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+      uint32_t format = brw_get_vertex_surface_type(brw, glattrib);
       uint32_t comp0 = VFCOMP_STORE_SRC;
       uint32_t comp1 = VFCOMP_STORE_SRC;
       uint32_t comp2 = VFCOMP_STORE_SRC;
@@ -687,17 +691,19 @@ genX(emit_vertices)(struct brw_context *brw)
           * entry. */
          const unsigned offset = input->offset + c * 16;
 
+         const struct gl_vertex_array *glarray = input->glarray;
+         const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
          const int size = (GEN_GEN < 8 && is_passthru_format(format)) ?
-            upload_format_size(upload_format) : input->glarray->Size;
+            upload_format_size(upload_format) : glattrib->Size;
 
          switch (size) {
             case 0: comp0 = VFCOMP_STORE_0;
             case 1: comp1 = VFCOMP_STORE_0;
             case 2: comp2 = VFCOMP_STORE_0;
             case 3:
-               if (GEN_GEN >= 8 && input->glarray->Doubles) {
+               if (GEN_GEN >= 8 && glattrib->Doubles) {
                   comp3 = VFCOMP_STORE_0;
-               } else if (input->glarray->Integer) {
+               } else if (glattrib->Integer) {
                   comp3 = VFCOMP_STORE_1_INT;
                } else {
                   comp3 = VFCOMP_STORE_1_FP;
@@ -722,7 +728,7 @@ genX(emit_vertices)(struct brw_context *brw)
           *     to be specified as VFCOMP_STORE_0 in order to output a 256-bit
           *     vertex element."
           */
-         if (input->glarray->Doubles && !input->is_dual_slot) {
+         if (glattrib->Doubles && !input->is_dual_slot) {
             /* Store vertex elements which correspond to double and dvec2 vertex
              * shader inputs as 128-bit vertex elements, instead of 256-bits.
              */
@@ -810,8 +816,9 @@ genX(emit_vertices)(struct brw_context *brw)
 
 #if GEN_GEN >= 6
    if (gen6_edgeflag_input) {
-      const uint32_t format =
-         brw_get_vertex_surface_type(brw, gen6_edgeflag_input->glarray);
+      const struct gl_vertex_array *glarray = gen6_edgeflag_input->glarray;
+      const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+      const uint32_t format = brw_get_vertex_surface_type(brw, glattrib);
 
       struct GENX(VERTEX_ELEMENT_STATE) elem_state = {
          .Valid = true,
diff --git a/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c b/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c
index b9145e6851..a7b911c50e 100644
--- a/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c
+++ b/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c
@@ -30,6 +30,7 @@
 
 #include "main/bufferobj.h"
 #include "main/glformats.h"
+#include "main/varray.h"
 #include "main/image.h"
 
 /* Arbitrary pushbuf length we can assume we can get with a single
@@ -43,17 +44,20 @@ static int
 get_array_stride(struct gl_context *ctx, const struct gl_vertex_array *a)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
+	const struct gl_vertex_buffer_binding *binding = a->BufferBinding;
 
-	if (render->mode == VBO && !_mesa_is_bufferobj(a->BufferObj))
+	if (render->mode == VBO && !_mesa_is_bufferobj(binding->BufferObj)) {
+		const struct gl_array_attributes *attrib = a->VertexAttrib;
 		/* Pack client buffers. */
-		return align(_mesa_sizeof_type(a->Type) * a->Size, 4);
-	else
-		return a->StrideB;
+		return align(_mesa_sizeof_type(attrib->Type) * attrib->Size, 4);
+	} else {
+		return binding->Stride;
+	}
 }
 
 static void
 vbo_init_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
-		const struct gl_vertex_array **arrays)
+		const struct gl_vertex_array *arrays)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
 	GLboolean imm = (render->mode == IMM);
@@ -74,19 +78,23 @@ vbo_init_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
 	}
 
 	FOR_EACH_BOUND_ATTR(render, i, attr) {
-		const struct gl_vertex_array *array = arrays[attr];
+		const struct gl_vertex_array *array = &arrays[attr];
+		const struct gl_vertex_buffer_binding *binding =
+			array->BufferBinding;
+		const struct gl_array_attributes *attrib = array->VertexAttrib;
+		const GLubyte *p = _mesa_vertex_attrib_address(attrib, binding);
 
 		nouveau_init_array(&render->attrs[attr], attr,
 				   get_array_stride(ctx, array),
-				   array->Size, array->Type,
-				   imm ? array->BufferObj : NULL,
-				   array->Ptr, imm, ctx);
+				   attrib->Size, attrib->Type,
+				   imm ? binding->BufferObj : NULL,
+				   p, imm, ctx);
 	}
 }
 
 static void
 vbo_deinit_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
-		  const struct gl_vertex_array **arrays)
+		  const struct gl_vertex_array *arrays)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
 	int i, attr;
@@ -110,7 +118,7 @@ vbo_deinit_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
 /* Make some rendering decisions from the GL context. */
 
 static void
-vbo_choose_render_mode(struct gl_context *ctx, const struct gl_vertex_array **arrays)
+vbo_choose_render_mode(struct gl_context *ctx, const struct gl_vertex_array *arrays)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
 	int i;
@@ -119,7 +127,7 @@ vbo_choose_render_mode(struct gl_context *ctx, const struct gl_vertex_array **ar
 
 	if (ctx->Light.Enabled) {
 		for (i = 0; i < VERT_ATTRIB_MAT_MAX; i++) {
-			if (arrays[VERT_ATTRIB_MAT(i)]->StrideB) {
+			if (arrays[VERT_ATTRIB_MAT(i)].BufferBinding->Stride) {
 				render->mode = IMM;
 				break;
 			}
@@ -128,23 +136,26 @@ vbo_choose_render_mode(struct gl_context *ctx, const struct gl_vertex_array **ar
 }
 
 static void
-vbo_emit_attr(struct gl_context *ctx, const struct gl_vertex_array **arrays,
+vbo_emit_attr(struct gl_context *ctx, const struct gl_vertex_array *arrays,
 	      int attr)
 {
 	struct nouveau_pushbuf *push = context_push(ctx);
 	struct nouveau_render_state *render = to_render_state(ctx);
-	const struct gl_vertex_array *array = arrays[attr];
+	const struct gl_vertex_array *array = &arrays[attr];
+	const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
+	const struct gl_array_attributes *attrib = array->VertexAttrib;
+	const GLubyte *p = _mesa_vertex_attrib_address(attrib, binding);
 	struct nouveau_array *a = &render->attrs[attr];
 	RENDER_LOCALS(ctx);
 
-	if (!array->StrideB) {
+	if (!binding->Stride) {
 		if (attr >= VERT_ATTRIB_MAT(0))
 			/* nouveau_update_state takes care of materials. */
 			return;
 
 		/* Constant attribute. */
-		nouveau_init_array(a, attr, array->StrideB, array->Size,
-				   array->Type, array->BufferObj, array->Ptr,
+		nouveau_init_array(a, attr, binding->Stride, attrib->Size,
+				   attrib->Type, binding->BufferObj, p,
 				   GL_TRUE, ctx);
 		EMIT_IMM(ctx, a, 0);
 		nouveau_deinit_array(a);
@@ -155,7 +166,7 @@ vbo_emit_attr(struct gl_context *ctx, const struct gl_vertex_array **arrays,
 
 		if (render->mode == VBO) {
 			render->map[info->vbo_index] = attr;
-			render->vertex_size += array->_ElementSize;
+			render->vertex_size += attrib->_ElementSize;
 			render->attr_count = MAX2(render->attr_count,
 						  info->vbo_index + 1);
 		} else {
@@ -168,7 +179,7 @@ vbo_emit_attr(struct gl_context *ctx, const struct gl_vertex_array **arrays,
 #define MAT(a) VERT_ATTRIB_MAT(MAT_ATTRIB_##a)
 
 static void
-vbo_choose_attrs(struct gl_context *ctx, const struct gl_vertex_array **arrays)
+vbo_choose_attrs(struct gl_context *ctx, const struct gl_vertex_array *arrays)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
 	int i;
@@ -211,15 +222,15 @@ vbo_choose_attrs(struct gl_context *ctx, const struct gl_vertex_array **arrays)
 }
 
 static int
-get_max_client_stride(struct gl_context *ctx, const struct gl_vertex_array **arrays)
+get_max_client_stride(struct gl_context *ctx, const struct gl_vertex_array *arrays)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
 	int i, attr, s = 0;
 
 	FOR_EACH_BOUND_ATTR(render, i, attr) {
-		const struct gl_vertex_array *a = arrays[attr];
+		const struct gl_vertex_array *a = &arrays[attr];
 
-		if (!_mesa_is_bufferobj(a->BufferObj))
+		if (!_mesa_is_bufferobj(a->BufferBinding->BufferObj))
 			s = MAX2(s, get_array_stride(ctx, a));
 	}
 
@@ -237,7 +248,7 @@ TAG(vbo_render_prims)(struct gl_context *ctx,
 		      struct gl_buffer_object *indirect);
 
 static GLboolean
-vbo_maybe_split(struct gl_context *ctx, const struct gl_vertex_array **arrays,
+vbo_maybe_split(struct gl_context *ctx, const struct gl_vertex_array *arrays,
 	    const struct _mesa_prim *prims, GLuint nr_prims,
 	    const struct _mesa_index_buffer *ib,
 	    GLuint min_index, GLuint max_index)
@@ -297,7 +308,7 @@ check_update_array(struct nouveau_array *a, unsigned offset,
 }
 
 static void
-vbo_bind_vertices(struct gl_context *ctx, const struct gl_vertex_array **arrays,
+vbo_bind_vertices(struct gl_context *ctx, const struct gl_vertex_array *arrays,
 		  int base, unsigned min_index, unsigned max_index, int *pdelta)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
@@ -311,22 +322,26 @@ vbo_bind_vertices(struct gl_context *ctx, const struct gl_vertex_array **arrays,
 	*pdelta = -1;
 
 	FOR_EACH_BOUND_ATTR(render, i, attr) {
-		const struct gl_vertex_array *array = arrays[attr];
-		struct gl_buffer_object *obj = array->BufferObj;
+		const struct gl_vertex_array *array = &arrays[attr];
+		const struct gl_vertex_buffer_binding *binding =
+			array->BufferBinding;
+		const struct gl_array_attributes *attrib = array->VertexAttrib;
+		const GLubyte *p = _mesa_vertex_attrib_address(attrib, binding);
+		struct gl_buffer_object *obj = binding->BufferObj;
 		struct nouveau_array *a = &render->attrs[attr];
-		unsigned delta = (base + min_index) * array->StrideB;
+		unsigned delta = (base + min_index) * binding->Stride;
 
 		bo[i] = NULL;
 
 		if (nouveau_bufferobj_hw(obj)) {
 			/* Array in a buffer obj. */
 			nouveau_bo_ref(to_nouveau_bufferobj(obj)->bo, &bo[i]);
-			offset[i] = delta + (intptr_t)array->Ptr;
+			offset[i] = delta + (intptr_t)p;
 
 		} else {
 			int n = max_index - min_index + 1;
 			char *sp = (char *)ADD_POINTERS(
-				nouveau_bufferobj_sys(obj), array->Ptr) + delta;
+				nouveau_bufferobj_sys(obj), p) + delta;
 			char *dp  = nouveau_get_scratch(ctx, n * a->stride,
 							&bo[i], &offset[i]);
 
@@ -334,7 +349,7 @@ vbo_bind_vertices(struct gl_context *ctx, const struct gl_vertex_array **arrays,
 			 * scratch buffer obj. */
 			for (j = 0; j < n; j++)
 				memcpy(dp + j * a->stride,
-				       sp + j * array->StrideB,
+				       sp + j * binding->Stride,
 				       a->stride);
 		}
 
@@ -365,7 +380,7 @@ vbo_bind_vertices(struct gl_context *ctx, const struct gl_vertex_array **arrays,
 }
 
 static void
-vbo_draw_vbo(struct gl_context *ctx, const struct gl_vertex_array **arrays,
+vbo_draw_vbo(struct gl_context *ctx, const struct gl_vertex_array *arrays,
 	     const struct _mesa_prim *prims, GLuint nr_prims,
 	     const struct _mesa_index_buffer *ib, GLuint min_index,
 	     GLuint max_index)
@@ -415,7 +430,7 @@ extract_id(struct nouveau_array *a, int i, int j)
 }
 
 static void
-vbo_draw_imm(struct gl_context *ctx, const struct gl_vertex_array **arrays,
+vbo_draw_imm(struct gl_context *ctx, const struct gl_vertex_array *arrays,
 	     const struct _mesa_prim *prims, GLuint nr_prims,
 	     const struct _mesa_index_buffer *ib, GLuint min_index,
 	     GLuint max_index)
@@ -470,7 +485,7 @@ TAG(vbo_render_prims)(struct gl_context *ctx,
 		      struct gl_buffer_object *indirect)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
-	const struct gl_vertex_array **arrays = ctx->Array._DrawArrays;
+	const struct gl_vertex_array *arrays = ctx->Array._DrawArrays;
 
 	if (!index_bounds_valid)
 		vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
diff --git a/src/mesa/main/arrayobj.c b/src/mesa/main/arrayobj.c
index 2526404fda..7cb9833719 100644
--- a/src/mesa/main/arrayobj.c
+++ b/src/mesa/main/arrayobj.c
@@ -284,9 +284,6 @@ unbind_array_object_vbos(struct gl_context *ctx, struct gl_vertex_array_object *
 
    for (i = 0; i < ARRAY_SIZE(obj->BufferBinding); i++)
       _mesa_reference_buffer_object(ctx, &obj->BufferBinding[i].BufferObj, NULL);
-
-   for (i = 0; i < ARRAY_SIZE(obj->_VertexArray); i++)
-      _mesa_reference_buffer_object(ctx, &obj->_VertexArray[i].BufferObj, NULL);
 }
 
 
@@ -462,21 +459,8 @@ void
 _mesa_update_vao_derived_arrays(struct gl_context *ctx,
                                 struct gl_vertex_array_object *vao)
 {
-   GLbitfield arrays = vao->NewArrays;
-
    /* Make sure we do not run into problems with shared objects */
    assert(!vao->SharedAndImmutable || vao->NewArrays == 0);
-
-   while (arrays) {
-      const int attrib = u_bit_scan(&arrays);
-      struct gl_vertex_array *array = &vao->_VertexArray[attrib];
-      const struct gl_array_attributes *attribs =
-         &vao->VertexAttrib[attrib];
-      const struct gl_vertex_buffer_binding *buffer_binding =
-         &vao->BufferBinding[attribs->BufferBindingIndex];
-
-      _mesa_update_vertex_array(ctx, array, attribs, buffer_binding);
-   }
 }
 
 
diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c
index dd6b98ce04..9d3aa728a1 100644
--- a/src/mesa/main/attrib.c
+++ b/src/mesa/main/attrib.c
@@ -1507,7 +1507,6 @@ copy_array_object(struct gl_context *ctx,
    /* skip RefCount */
 
    for (i = 0; i < ARRAY_SIZE(src->VertexAttrib); i++) {
-      _mesa_copy_vertex_array(ctx, &dest->_VertexArray[i], &src->_VertexArray[i]);
       _mesa_copy_vertex_attrib_array(ctx, &dest->VertexAttrib[i], &src->VertexAttrib[i]);
       _mesa_copy_vertex_buffer_binding(ctx, &dest->BufferBinding[i], &src->BufferBinding[i]);
    }
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 2df2288899..734fefc97f 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1503,29 +1503,6 @@ struct gl_pixelstore_attrib
 };
 
 
-/**
- * Vertex array information which is derived from gl_array_attributes
- * and gl_vertex_buffer_binding information.  Used by the VBO module and
- * device drivers.
- */
-struct gl_vertex_array
-{
-   /** if NULL, vertex data are in user memory */
-   struct gl_buffer_object *BufferObj;
-   /** Pointer into user memory, or offset into the BufferObj */
-   const GLubyte *Ptr;
-   GLsizei StrideB;		/**< actual stride in bytes */
-   GLuint InstanceDivisor;      /**< GL_ARB_instanced_arrays */
-   GLenum16 Type;               /**< datatype: GL_FLOAT, GL_INT, etc */
-   GLenum16 Format;             /**< default: GL_RGBA, but may be GL_BGRA */
-   unsigned Size:4;             /**< components per element (1,2,3,4) */
-   unsigned _ElementSize:8;     /**< in bytes, up to 4*sizeof(GLdouble) */
-   unsigned Normalized:1;       /**< GL_ARB_vertex_program */
-   unsigned Integer:1;          /**< Integer-valued? */
-   unsigned Doubles:1;          /**< doubles not converted to floats */
-};
-
-
 /**
  * Enum for defining the mapping for the position/generic0 attribute.
  *
@@ -1589,6 +1566,20 @@ struct gl_vertex_buffer_binding
 };
 
 
+/**
+ * Vertex array information which is derived from gl_array_attributes
+ * and gl_vertex_buffer_binding information.  Used by the VBO module and
+ * device drivers.
+ */
+struct gl_vertex_array
+{
+   /** Vertex attribute array */
+   const struct gl_array_attributes *VertexAttrib;
+   /** Vertex buffer binding */
+   const struct gl_vertex_buffer_binding *BufferBinding;
+};
+
+
 /**
  * A representation of "Vertex Array Objects" (VAOs) from OpenGL 3.1+ /
  * the GL_ARB_vertex_array_object extension.
@@ -1614,14 +1605,6 @@ struct gl_vertex_array_object
     */
    bool SharedAndImmutable;
 
-   /**
-    * Derived vertex attribute arrays
-    *
-    * This is a legacy data structure created from gl_array_attributes and
-    * gl_vertex_buffer_binding, only used by the VBO module at this time.
-    */
-   struct gl_vertex_array _VertexArray[VERT_ATTRIB_MAX];
-
    /** Vertex attribute arrays */
    struct gl_array_attributes VertexAttrib[VERT_ATTRIB_MAX];
 
@@ -1724,7 +1707,7 @@ struct gl_array_attrib
     * Vertex arrays as consumed by a driver.
     * The array pointer is set up only by the VBO module.
     */
-   const struct gl_vertex_array **_DrawArrays; /**< 0..VERT_ATTRIB_MAX-1 */
+   const struct gl_vertex_array *_DrawArrays; /**< 0..VERT_ATTRIB_MAX-1 */
 
    /** Legal array datatypes and the API for which they have been computed */
    GLbitfield LegalTypesMask;
diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c
index c6cacf426c..69a08a646f 100644
--- a/src/mesa/main/varray.c
+++ b/src/mesa/main/varray.c
@@ -2845,27 +2845,6 @@ _mesa_VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingIndex,
 }
 
 
-/**
- * Copy one vertex array to another.
- */
-void
-_mesa_copy_vertex_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,
diff --git a/src/mesa/main/varray.h b/src/mesa/main/varray.h
index b65b82cea7..77027be800 100644
--- a/src/mesa/main/varray.h
+++ b/src/mesa/main/varray.h
@@ -48,37 +48,6 @@ _mesa_vertex_attrib_address(const struct gl_array_attributes *array,
 }
 
 
-/**
- * Sets the fields in a gl_vertex_array to values derived from a
- * gl_array_attributes and a gl_vertex_buffer_binding.
- */
-static inline void
-_mesa_update_vertex_array(struct gl_context *ctx,
-                          struct gl_vertex_array *dst,
-                          const struct gl_array_attributes *attribs,
-                          const struct gl_vertex_buffer_binding *binding)
-{
-   if (attribs->Enabled) {
-      dst->Size = attribs->Size;
-      dst->Type = attribs->Type;
-      dst->Format = attribs->Format;
-      dst->StrideB = binding->Stride;
-      dst->Ptr = _mesa_vertex_attrib_address(attribs, binding);
-      dst->Normalized = attribs->Normalized;
-      dst->Integer = attribs->Integer;
-      dst->Doubles = attribs->Doubles;
-      dst->InstanceDivisor = binding->InstanceDivisor;
-      dst->_ElementSize = attribs->_ElementSize;
-      _mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj);
-   } else {
-      /* Disabled arrays shall not be consumed */
-      dst->Size = 0;
-      dst->Ptr = NULL;
-      _mesa_reference_buffer_object(ctx, &dst->BufferObj, NULL);
-   }
-}
-
-
 static inline bool
 _mesa_attr_zero_aliases_vertex(const struct gl_context *ctx)
 {
@@ -91,7 +60,7 @@ _mesa_attr_zero_aliases_vertex(const struct gl_context *ctx)
  */
 static inline void
 _mesa_set_drawing_arrays(struct gl_context *ctx,
-                         const struct gl_vertex_array **arrays)
+                         const struct gl_vertex_array *arrays)
 {
    if (ctx->Array._DrawArrays != arrays) {
       ctx->Array._DrawArrays = arrays;
@@ -495,10 +464,18 @@ extern void GLAPIENTRY
 _mesa_VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingIndex,
                                 GLuint divisor);
 
-extern void
-_mesa_copy_vertex_array(struct gl_context *ctx,
-                        struct gl_vertex_array *dst,
-                        struct gl_vertex_array *src);
+
+/**
+ * Shallow copy one vertex array to another.
+ */
+static inline void
+_mesa_copy_vertex_array(struct gl_vertex_array *dst,
+                        const struct gl_vertex_array *src)
+{
+   dst->VertexAttrib = src->VertexAttrib;
+   dst->BufferBinding = src->BufferBinding;
+}
+
 
 extern void
 _mesa_copy_vertex_attrib_array(struct gl_context *ctx,
diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c
index b597c62632..45a45960a3 100644
--- a/src/mesa/state_tracker/st_atom.c
+++ b/src/mesa/state_tracker/st_atom.c
@@ -138,7 +138,8 @@ static void check_program_state( struct st_context *st )
 
 static void check_attrib_edgeflag(struct st_context *st)
 {
-   const struct gl_vertex_array **arrays = st->ctx->Array._DrawArrays;
+   const struct gl_vertex_array *arrays = st->ctx->Array._DrawArrays;
+   const struct gl_vertex_buffer_binding *binding;
    GLboolean vertdata_edgeflags, edgeflag_culls_prims, edgeflags_enabled;
    struct gl_program *vp = st->ctx->VertexProgram._Current;
 
@@ -148,8 +149,8 @@ static void check_attrib_edgeflag(struct st_context *st)
    edgeflags_enabled = st->ctx->Polygon.FrontMode != GL_FILL ||
                        st->ctx->Polygon.BackMode != GL_FILL;
 
-   vertdata_edgeflags = edgeflags_enabled &&
-                        arrays[VERT_ATTRIB_EDGEFLAG]->StrideB != 0;
+   binding = arrays[VERT_ATTRIB_EDGEFLAG].BufferBinding;
+   vertdata_edgeflags = edgeflags_enabled && binding->Stride != 0;
    if (vertdata_edgeflags != st->vertdata_edgeflags) {
       st->vertdata_edgeflags = vertdata_edgeflags;
       if (vp)
diff --git a/src/mesa/state_tracker/st_atom_array.c b/src/mesa/state_tracker/st_atom_array.c
index 6af1355ee1..ff7a5d0746 100644
--- a/src/mesa/state_tracker/st_atom_array.c
+++ b/src/mesa/state_tracker/st_atom_array.c
@@ -47,6 +47,7 @@
 #include "util/u_upload_mgr.h"
 #include "main/bufferobj.h"
 #include "main/glformats.h"
+#include "main/varray.h"
 
 /* vertex_formats[gltype - GL_BYTE][integer*2 + normalized][size - 1] */
 static const uint16_t vertex_formats[][4][4] = {
@@ -301,13 +302,13 @@ st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
 }
 
 static const struct gl_vertex_array *
-get_client_array(const struct gl_vertex_array **arrays,
+get_client_array(const struct gl_vertex_array *arrays,
                  unsigned mesaAttr)
 {
    /* st_program uses 0xffffffff to denote a double placeholder attribute */
    if (mesaAttr == ST_DOUBLE_ATTRIB_PLACEHOLDER)
       return NULL;
-   return arrays[mesaAttr];
+   return &arrays[mesaAttr];
 }
 
 /**
@@ -316,7 +317,7 @@ get_client_array(const struct gl_vertex_array **arrays,
  */
 static GLboolean
 is_interleaved_arrays(const struct st_vertex_program *vp,
-                      const struct gl_vertex_array **arrays,
+                      const struct gl_vertex_array *arrays,
                       unsigned num_inputs)
 {
    GLuint attr;
@@ -327,6 +328,9 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
 
    for (attr = 0; attr < num_inputs; attr++) {
       const struct gl_vertex_array *array;
+      const struct gl_vertex_buffer_binding *binding;
+      const struct gl_array_attributes *attrib;
+      const GLubyte *ptr;
       const struct gl_buffer_object *bufObj;
       GLsizei stride;
 
@@ -334,19 +338,22 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
       if (!array)
 	 continue;
 
-      stride = array->StrideB; /* in bytes */
+      binding = array->BufferBinding;
+      attrib = array->VertexAttrib;
+      stride = binding->Stride; /* in bytes */
+      ptr = _mesa_vertex_attrib_address(attrib, binding);
 
       /* To keep things simple, don't allow interleaved zero-stride attribs. */
       if (stride == 0)
          return false;
 
-      bufObj = array->BufferObj;
+      bufObj = binding->BufferObj;
       if (attr == 0) {
          /* save info about the first array */
          firstStride = stride;
-         firstPtr = array->Ptr;
+         firstPtr = ptr;
          firstBufObj = bufObj;
-         userSpaceBuffer = !bufObj || !bufObj->Name;
+         userSpaceBuffer = !_mesa_is_bufferobj(bufObj);
       }
       else {
          /* check if other arrays interleave with the first, in same buffer */
@@ -356,7 +363,7 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
          if (bufObj != firstBufObj)
             return GL_FALSE; /* arrays in different VBOs */
 
-         if (llabs(array->Ptr - firstPtr) > firstStride)
+         if (llabs(ptr - firstPtr) > firstStride)
             return GL_FALSE; /* arrays start too far apart */
 
          if ((!_mesa_is_bufferobj(bufObj)) != userSpaceBuffer)
@@ -454,7 +461,7 @@ set_vertex_attribs(struct st_context *st,
 static void
 setup_interleaved_attribs(struct st_context *st,
                           const struct st_vertex_program *vp,
-                          const struct gl_vertex_array **arrays,
+                          const struct gl_vertex_array *arrays,
                           unsigned num_inputs)
 {
    struct pipe_vertex_buffer vbuffer;
@@ -470,25 +477,32 @@ setup_interleaved_attribs(struct st_context *st,
     */
    if (num_inputs) {
       const struct gl_vertex_array *array;
+      const struct gl_vertex_buffer_binding *binding;
+      const struct gl_array_attributes *attrib;
 
       array = get_client_array(arrays, vp->index_to_input[0]);
       assert(array);
 
+      binding = array->BufferBinding;
+      attrib = array->VertexAttrib;
+
       /* Since we're doing interleaved arrays, we know there'll be at most
        * one buffer object and the stride will be the same for all arrays.
        * Grab them now.
        */
-      bufobj = array->BufferObj;
-      stride = array->StrideB;
+      bufobj = binding->BufferObj;
+      stride = binding->Stride;
 
-      low_addr = arrays[vp->index_to_input[0]]->Ptr;
+      low_addr = _mesa_vertex_attrib_address(attrib, binding);
 
       for (attr = 1; attr < num_inputs; attr++) {
          const GLubyte *start;
          array = get_client_array(arrays, vp->index_to_input[attr]);
          if (!array)
             continue;
-         start = array->Ptr;
+         binding = array->BufferBinding;
+         attrib = array->VertexAttrib;
+         start = _mesa_vertex_attrib_address(attrib, binding);
          low_addr = MIN2(low_addr, start);
       }
    }
@@ -504,25 +518,32 @@ setup_interleaved_attribs(struct st_context *st,
 
    for (attr = 0; attr < num_inputs;) {
       const struct gl_vertex_array *array;
+      const struct gl_vertex_buffer_binding *binding;
+      const struct gl_array_attributes *attrib;
+      const GLubyte *ptr;
       unsigned src_offset;
       unsigned src_format;
 
       array = get_client_array(arrays, vp->index_to_input[attr]);
       assert(array);
 
-      src_offset = (unsigned) (array->Ptr - low_addr);
-      assert(array->_ElementSize ==
-             _mesa_bytes_per_vertex_attrib(array->Size, array->Type));
+      binding = array->BufferBinding;
+      attrib = array->VertexAttrib;
+      ptr = _mesa_vertex_attrib_address(attrib, binding);
+
+      src_offset = (unsigned) (ptr - low_addr);
+      assert(attrib->_ElementSize ==
+             _mesa_bytes_per_vertex_attrib(attrib->Size, attrib->Type));
 
-      src_format = st_pipe_vertex_format(array->Type,
-                                         array->Size,
-                                         array->Format,
-                                         array->Normalized,
-                                         array->Integer);
+      src_format = st_pipe_vertex_format(attrib->Type,
+                                         attrib->Size,
+                                         attrib->Format,
+                                         attrib->Normalized,
+                                         attrib->Integer);
 
       init_velement_lowered(vp, velements, src_offset, src_format,
-                            array->InstanceDivisor, 0,
-                            array->Size, array->Doubles, &attr);
+                            binding->InstanceDivisor, 0,
+                            attrib->Size, attrib->Doubles, &attr);
    }
 
    /*
@@ -573,7 +594,7 @@ setup_interleaved_attribs(struct st_context *st,
 static void
 setup_non_interleaved_attribs(struct st_context *st,
                               const struct st_vertex_program *vp,
-                              const struct gl_vertex_array **arrays,
+                              const struct gl_vertex_array *arrays,
                               unsigned num_inputs)
 {
    struct gl_context *ctx = st->ctx;
@@ -586,6 +607,8 @@ setup_non_interleaved_attribs(struct st_context *st,
    for (attr = 0; attr < num_inputs;) {
       const unsigned mesaAttr = vp->index_to_input[attr];
       const struct gl_vertex_array *array;
+      const struct gl_vertex_buffer_binding *binding;
+      const struct gl_array_attributes *attrib;
       struct gl_buffer_object *bufobj;
       GLsizei stride;
       unsigned src_format;
@@ -596,10 +619,12 @@ setup_non_interleaved_attribs(struct st_context *st,
 
       bufidx = num_vbuffers++;
 
-      stride = array->StrideB;
-      bufobj = array->BufferObj;
-      assert(array->_ElementSize ==
-             _mesa_bytes_per_vertex_attrib(array->Size, array->Type));
+      binding = array->BufferBinding;
+      attrib = array->VertexAttrib;
+      stride = binding->Stride;
+      bufobj = binding->BufferObj;
+      assert(attrib->_ElementSize ==
+             _mesa_bytes_per_vertex_attrib(attrib->Size, attrib->Type));
 
       if (_mesa_is_bufferobj(bufobj)) {
          /* Attribute data is in a VBO.
@@ -615,17 +640,21 @@ setup_non_interleaved_attribs(struct st_context *st,
 
          vbuffer[bufidx].buffer.resource = stobj->buffer;
          vbuffer[bufidx].is_user_buffer = false;
-         vbuffer[bufidx].buffer_offset = pointer_to_offset(array->Ptr);
+         vbuffer[bufidx].buffer_offset =
+            binding->Offset + attrib->RelativeOffset;
       }
       else {
          if (stride == 0) {
-            unsigned size = array->_ElementSize;
+            unsigned size = attrib->_ElementSize;
             /* This is optimal for GPU cache line usage if the upload size
              * is <= cache line size.
              */
             unsigned alignment = util_next_power_of_two(size);
-            void *ptr = array->Ptr ? (void*)array->Ptr :
-                                     (void*)ctx->Current.Attrib[mesaAttr];
+
+            assert(attrib->Ptr);
+            vbuffer[bufidx].buffer.user = attrib->Ptr;
+            void *ptr = attrib->Ptr ? (void*)attrib->Ptr :
+                                      (void*)ctx->Current.Attrib[mesaAttr];
 
             vbuffer[bufidx].is_user_buffer = false;
             vbuffer[bufidx].buffer.resource = NULL;
@@ -646,12 +675,12 @@ setup_non_interleaved_attribs(struct st_context *st,
                           &vbuffer[bufidx].buffer.resource);
             unref_buffers |= 1u << bufidx;
          } else {
-            assert(array->Ptr);
-            vbuffer[bufidx].buffer.user = array->Ptr;
+            assert(attrib->Ptr);
+            vbuffer[bufidx].buffer.user = attrib->Ptr;
             vbuffer[bufidx].is_user_buffer = true;
             vbuffer[bufidx].buffer_offset = 0;
 
-            if (!array->InstanceDivisor)
+            if (!binding->InstanceDivisor)
                st->draw_needs_minmax_index = true;
          }
       }
@@ -659,15 +688,15 @@ setup_non_interleaved_attribs(struct st_context *st,
       /* common-case setup */
       vbuffer[bufidx].stride = stride; /* in bytes */
 
-      src_format = st_pipe_vertex_format(array->Type,
-                                         array->Size,
-                                         array->Format,
-                                         array->Normalized,
-                                         array->Integer);
+      src_format = st_pipe_vertex_format(attrib->Type,
+                                         attrib->Size,
+                                         attrib->Format,
+                                         attrib->Normalized,
+                                         attrib->Integer);
 
       init_velement_lowered(vp, velements, 0, src_format,
-                            array->InstanceDivisor, bufidx,
-                            array->Size, array->Doubles, &attr);
+                            binding->InstanceDivisor, bufidx,
+                            attrib->Size, attrib->Doubles, &attr);
    }
 
    if (!ctx->Const.AllowMappedBuffersDuringExecution) {
@@ -686,7 +715,7 @@ setup_non_interleaved_attribs(struct st_context *st,
 void st_update_array(struct st_context *st)
 {
    struct gl_context *ctx = st->ctx;
-   const struct gl_vertex_array **arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *arrays = ctx->Array._DrawArrays;
    const struct st_vertex_program *vp;
    unsigned num_inputs;
 
diff --git a/src/mesa/state_tracker/st_cb_rasterpos.c b/src/mesa/state_tracker/st_cb_rasterpos.c
index e266296a77..4e5417baad 100644
--- a/src/mesa/state_tracker/st_cb_rasterpos.c
+++ b/src/mesa/state_tracker/st_cb_rasterpos.c
@@ -60,8 +60,9 @@ struct rastpos_stage
    struct gl_context *ctx;            /**< Rendering context */
 
    /* vertex attrib info we can setup once and re-use */
+   struct gl_vertex_buffer_binding binding;
+   struct gl_array_attributes attrib[VERT_ATTRIB_MAX];
    struct gl_vertex_array array[VERT_ATTRIB_MAX];
-   const struct gl_vertex_array *arrays[VERT_ATTRIB_MAX];
    struct _mesa_prim prim;
 };
 
@@ -193,15 +194,16 @@ new_draw_rastpos_stage(struct gl_context *ctx, struct draw_context *draw)
    rs->stage.destroy = rastpos_destroy;
    rs->ctx = ctx;
 
+   rs->binding.Stride = 0;
+   rs->binding.BufferObj = NULL;
    for (i = 0; i < ARRAY_SIZE(rs->array); i++) {
-      rs->array[i].Size = 4;
-      rs->array[i].Type = GL_FLOAT;
-      rs->array[i].Format = GL_RGBA;
-      rs->array[i].StrideB = 0;
-      rs->array[i].Ptr = (GLubyte *) ctx->Current.Attrib[i];
-      rs->array[i].Normalized = GL_TRUE;
-      rs->array[i].BufferObj = NULL;
-      rs->arrays[i] = &rs->array[i];
+      rs->attrib[i].Size = 4;
+      rs->attrib[i].Type = GL_FLOAT;
+      rs->attrib[i].Format = GL_RGBA;
+      rs->attrib[i].Ptr = (GLubyte *) ctx->Current.Attrib[i];
+      rs->attrib[i].Normalized = GL_TRUE;
+      rs->array[i].BufferBinding = &rs->binding;
+      rs->array[i].VertexAttrib = &rs->attrib[i];
    }
 
    rs->prim.mode = GL_POINTS;
@@ -222,7 +224,7 @@ st_RasterPos(struct gl_context *ctx, const GLfloat v[4])
    struct st_context *st = st_context(ctx);
    struct draw_context *draw = st_get_draw_context(st);
    struct rastpos_stage *rs;
-   const struct gl_vertex_array **saved_arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *saved_arrays = ctx->Array._DrawArrays;
 
    if (!st->draw)
       return;
@@ -258,13 +260,13 @@ st_RasterPos(struct gl_context *ctx, const GLfloat v[4])
    /* All vertex attribs but position were previously initialized above.
     * Just plug in position pointer now.
     */
-   rs->array[0].Ptr = (GLubyte *) v;
+   rs->attrib[0].Ptr = (GLubyte *) v;
 
    /* Draw the point.
     *
     * Don't set DriverFlags.NewArray.
     * st_feedback_draw_vbo doesn't check for that flag. */
-   ctx->Array._DrawArrays = rs->arrays;
+   ctx->Array._DrawArrays = rs->array;
    st_feedback_draw_vbo(ctx, &rs->prim, 1, NULL, GL_TRUE, 0, 1,
                         NULL, 0, NULL);
    ctx->Array._DrawArrays = saved_arrays;
diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c
index 987a1564e2..46a12848c0 100644
--- a/src/mesa/state_tracker/st_draw_feedback.c
+++ b/src/mesa/state_tracker/st_draw_feedback.c
@@ -28,6 +28,7 @@
 #include "main/imports.h"
 #include "main/image.h"
 #include "main/macros.h"
+#include "main/varray.h"
 
 #include "vbo/vbo.h"
 
@@ -130,7 +131,7 @@ st_feedback_draw_vbo(struct gl_context *ctx,
    struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
    struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = {NULL};
    struct pipe_transfer *ib_transfer = NULL;
-   const struct gl_vertex_array **arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *arrays = ctx->Array._DrawArrays;
    GLuint attr, i;
    const GLubyte *low_addr = NULL;
    const void *mapped_indices = NULL;
@@ -169,10 +170,21 @@ st_feedback_draw_vbo(struct gl_context *ctx,
 
    /* Find the lowest address of the arrays we're drawing */
    if (vp->num_inputs) {
-      low_addr = arrays[vp->index_to_input[0]]->Ptr;
+      const struct gl_vertex_array *array;
+      const struct gl_vertex_buffer_binding *binding;
+      const struct gl_array_attributes *attrib;
+      array = &arrays[vp->index_to_input[0]];
+      binding = array->BufferBinding;
+      attrib = array->VertexAttrib;
+
+      low_addr = _mesa_vertex_attrib_address(attrib, binding);
 
       for (attr = 1; attr < vp->num_inputs; attr++) {
-         const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
+         const GLubyte *start;
+         array = &arrays[vp->index_to_input[attr]];
+         binding = array->BufferBinding;
+         attrib = array->VertexAttrib;
+         start = _mesa_vertex_attrib_address(attrib, binding);
          low_addr = MIN2(low_addr, start);
       }
    }
@@ -182,9 +194,16 @@ st_feedback_draw_vbo(struct gl_context *ctx,
     */
    for (attr = 0; attr < vp->num_inputs; attr++) {
       const GLuint mesaAttr = vp->index_to_input[attr];
-      struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
+      const struct gl_vertex_array *array = &arrays[mesaAttr];
+      const struct gl_vertex_buffer_binding *binding;
+      const struct gl_array_attributes *attrib;
+      struct gl_buffer_object *bufobj;
       void *map;
 
+      binding = array->BufferBinding;
+      attrib = array->VertexAttrib;
+      bufobj = binding->BufferObj;
+
       if (bufobj && bufobj->Name) {
          /* Attribute data is in a VBO.
           * Recall that for VBOs, the gl_vertex_array->Ptr field is
@@ -197,7 +216,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
          vbuffers[attr].is_user_buffer = false;
          pipe_resource_reference(&vbuffers[attr].buffer.resource, stobj->buffer);
          vbuffers[attr].buffer_offset = pointer_to_offset(low_addr);
-         velements[attr].src_offset = arrays[mesaAttr]->Ptr - low_addr;
+         velements[attr].src_offset = binding->Offset
+            + attrib->RelativeOffset - pointer_to_offset(low_addr);
 
          /* map the attrib buffer */
          map = pipe_buffer_map(pipe, vbuffers[attr].buffer.resource,
@@ -207,7 +227,7 @@ st_feedback_draw_vbo(struct gl_context *ctx,
                                        vbuffers[attr].buffer.resource->width0);
       }
       else {
-         vbuffers[attr].buffer.user = arrays[mesaAttr]->Ptr;
+         vbuffers[attr].buffer.user = attrib->Ptr;
          vbuffers[attr].is_user_buffer = true;
          vbuffers[attr].buffer_offset = 0;
          velements[attr].src_offset = 0;
@@ -217,15 +237,15 @@ st_feedback_draw_vbo(struct gl_context *ctx,
       }
 
       /* common-case setup */
-      vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */
+      vbuffers[attr].stride = binding->Stride; /* in bytes */
       velements[attr].instance_divisor = 0;
       velements[attr].vertex_buffer_index = attr;
-      velements[attr].src_format = 
-         st_pipe_vertex_format(arrays[mesaAttr]->Type,
-                               arrays[mesaAttr]->Size,
-                               arrays[mesaAttr]->Format,
-                               arrays[mesaAttr]->Normalized,
-                               arrays[mesaAttr]->Integer);
+      velements[attr].src_format =
+         st_pipe_vertex_format(attrib->Type,
+                               attrib->Size,
+                               attrib->Format,
+                               attrib->Normalized,
+                               attrib->Integer);
       assert(velements[attr].src_format);
 
       /* tell draw about this attribute */
diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index c19d77d641..b314278889 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -68,14 +68,14 @@ static void free_space(struct gl_context *ctx)
  */
 #define CONVERT( TYPE, MACRO ) do {		\
    GLuint i, j;					\
-   if (input->Normalized) {			\
+   if (attrib->Normalized) {			\
       for (i = 0; i < count; i++) {		\
 	 const TYPE *in = (TYPE *)ptr;		\
 	 for (j = 0; j < sz; j++) {		\
 	    *fptr++ = MACRO(*in);		\
 	    in++;				\
 	 }					\
-	 ptr += input->StrideB;			\
+         ptr += binding->Stride;		\
       }						\
    } else {					\
       for (i = 0; i < count; i++) {		\
@@ -84,7 +84,7 @@ static void free_space(struct gl_context *ctx)
 	    *fptr++ = (GLfloat)(*in);		\
 	    in++;				\
 	 }					\
-	 ptr += input->StrideB;			\
+         ptr += binding->Stride;		\
       }						\
    }						\
 } while (0)
@@ -96,25 +96,27 @@ static void free_space(struct gl_context *ctx)
  * \param fptr  output/float array
  */
 static void
-convert_bgra_to_float(const struct gl_vertex_array *input,
+convert_bgra_to_float(const struct gl_vertex_buffer_binding *binding,
+                      const struct gl_array_attributes *attrib,
                       const GLubyte *ptr, GLfloat *fptr,
                       GLuint count )
 {
    GLuint i;
-   assert(input->Normalized);
-   assert(input->Size == 4);
+   assert(attrib->Normalized);
+   assert(attrib->Size == 4);
    for (i = 0; i < count; i++) {
       const GLubyte *in = (GLubyte *) ptr;  /* in is in BGRA order */
       *fptr++ = UBYTE_TO_FLOAT(in[2]);  /* red */
       *fptr++ = UBYTE_TO_FLOAT(in[1]);  /* green */
       *fptr++ = UBYTE_TO_FLOAT(in[0]);  /* blue */
       *fptr++ = UBYTE_TO_FLOAT(in[3]);  /* alpha */
-      ptr += input->StrideB;
+      ptr += binding->Stride;
    }
 }
 
 static void
-convert_half_to_float(const struct gl_vertex_array *input,
+convert_half_to_float(const struct gl_vertex_buffer_binding *binding,
+                      const struct gl_array_attributes *attrib,
 		      const GLubyte *ptr, GLfloat *fptr,
 		      GLuint count, GLuint sz)
 {
@@ -126,7 +128,7 @@ convert_half_to_float(const struct gl_vertex_array *input,
       for (j = 0; j < sz; j++) {
 	 *fptr++ = _mesa_half_to_float(in[j]);
       }
-      ptr += input->StrideB;
+      ptr += binding->Stride;
    }
 }
 
@@ -141,21 +143,22 @@ convert_half_to_float(const struct gl_vertex_array *input,
  * is used to map the fixed-point numbers into the range [-1, 1].
  */
 static void
-convert_fixed_to_float(const struct gl_vertex_array *input,
+convert_fixed_to_float(const struct gl_vertex_buffer_binding *binding,
+                       const struct gl_array_attributes *attrib,
                        const GLubyte *ptr, GLfloat *fptr,
                        GLuint count)
 {
    GLuint i;
    GLint j;
-   const GLint size = input->Size;
+   const GLint size = attrib->Size;
 
-   if (input->Normalized) {
+   if (attrib->Normalized) {
       for (i = 0; i < count; ++i) {
          const GLfixed *in = (GLfixed *) ptr;
          for (j = 0; j < size; ++j) {
             *fptr++ = (GLfloat) (2 * in[j] + 1) / (GLfloat) ((1 << 16) - 1);
          }
-         ptr += input->StrideB;
+         ptr += binding->Stride;
       }
    } else {
       for (i = 0; i < count; ++i) {
@@ -163,7 +166,7 @@ convert_fixed_to_float(const struct gl_vertex_array *input,
          for (j = 0; j < size; ++j) {
             *fptr++ = in[j] / (GLfloat) (1 << 16);
          }
-         ptr += input->StrideB;
+         ptr += binding->Stride;
       }
    }
 }
@@ -172,28 +175,29 @@ convert_fixed_to_float(const struct gl_vertex_array *input,
  * floating point, populate VB->AttribPtr[].
  */
 static void _tnl_import_array( struct gl_context *ctx,
-			       GLuint attrib,
+                               GLuint attr,
 			       GLuint count,
-			       const struct gl_vertex_array *input,
+                               const struct gl_vertex_buffer_binding *binding,
+                               const struct gl_array_attributes *attrib,
 			       const GLubyte *ptr )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
-   GLuint stride = input->StrideB;
+   GLuint stride = binding->Stride;
 
-   if (input->Type != GL_FLOAT) {
-      const GLuint sz = input->Size;
+   if (attrib->Type != GL_FLOAT) {
+      const GLuint sz = attrib->Size;
       GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat));
       GLfloat *fptr = (GLfloat *)buf;
 
-      switch (input->Type) {
+      switch (attrib->Type) {
       case GL_BYTE: 
 	 CONVERT(GLbyte, BYTE_TO_FLOAT); 
 	 break;
       case GL_UNSIGNED_BYTE: 
-         if (input->Format == GL_BGRA) {
+         if (attrib->Format == GL_BGRA) {
             /* See GL_EXT_vertex_array_bgra */
-            convert_bgra_to_float(input, ptr, fptr, count);
+            convert_bgra_to_float(binding, attrib, ptr, fptr, count);
          }
          else {
             CONVERT(GLubyte, UBYTE_TO_FLOAT); 
@@ -215,10 +219,10 @@ static void _tnl_import_array( struct gl_context *ctx,
 	 CONVERT(GLdouble, (GLfloat)); 
 	 break;
       case GL_HALF_FLOAT:
-	 convert_half_to_float(input, ptr, fptr, count, sz);
+	 convert_half_to_float(binding, attrib, ptr, fptr, count, sz);
 	 break;
       case GL_FIXED:
-         convert_fixed_to_float(input, ptr, fptr, count);
+         convert_fixed_to_float(binding, attrib, ptr, fptr, count);
          break;
       default:
 	 assert(0);
@@ -229,20 +233,20 @@ static void _tnl_import_array( struct gl_context *ctx,
       stride = sz * sizeof(GLfloat);
    }
 
-   VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib];
-   VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr;
-   VB->AttribPtr[attrib]->start = (GLfloat *)ptr;
-   VB->AttribPtr[attrib]->count = count;
-   VB->AttribPtr[attrib]->stride = stride;
-   VB->AttribPtr[attrib]->size = input->Size;
+   VB->AttribPtr[attr] = &tnl->tmp_inputs[attr];
+   VB->AttribPtr[attr]->data = (GLfloat (*)[4])ptr;
+   VB->AttribPtr[attr]->start = (GLfloat *)ptr;
+   VB->AttribPtr[attr]->count = count;
+   VB->AttribPtr[attr]->stride = stride;
+   VB->AttribPtr[attr]->size = attrib->Size;
 
    /* This should die, but so should the whole GLvector4f concept: 
     */
-   VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) | 
+   VB->AttribPtr[attr]->flags = (((1<<attrib->Size)-1) |
 				   VEC_NOT_WRITEABLE |
 				   (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE));
    
-   VB->AttribPtr[attrib]->storage = NULL;
+   VB->AttribPtr[attr]->storage = NULL;
 }
 
 #define CLIPVERTS  ((6 + MAX_CLIP_PLANES) * 2)
@@ -268,7 +272,7 @@ static GLboolean *_tnl_import_edgeflag( struct gl_context *ctx,
 
 
 static void bind_inputs( struct gl_context *ctx, 
-			 const struct gl_vertex_array *inputs[],
+			 const struct gl_vertex_array *inputs,
 			 GLint count,
 			 struct gl_buffer_object **bo,
 			 GLuint *nr_bo )
@@ -280,25 +284,28 @@ static void bind_inputs( struct gl_context *ctx,
    /* Map all the VBOs
     */
    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      const struct gl_vertex_array *array = &inputs[i];
+      const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
+      const struct gl_array_attributes *attrib = array->VertexAttrib;
       const void *ptr;
 
-      if (inputs[i]->BufferObj->Name) { 
-	 if (!inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer) {
-	    bo[*nr_bo] = inputs[i]->BufferObj;
+      if (_mesa_is_bufferobj(binding->BufferObj)) {
+	 if (!binding->BufferObj->Mappings[MAP_INTERNAL].Pointer) {
+	    bo[*nr_bo] = binding->BufferObj;
 	    (*nr_bo)++;
-	    ctx->Driver.MapBufferRange(ctx, 0, inputs[i]->BufferObj->Size,
+	    ctx->Driver.MapBufferRange(ctx, 0, binding->BufferObj->Size,
 				       GL_MAP_READ_BIT,
-				       inputs[i]->BufferObj,
+                                       binding->BufferObj,
                                        MAP_INTERNAL);
 	    
-	    assert(inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer);
+            assert(binding->BufferObj->Mappings[MAP_INTERNAL].Pointer);
 	 }
 	 
-	 ptr = ADD_POINTERS(inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer,
-			    inputs[i]->Ptr);
+         ptr = ADD_POINTERS(binding->BufferObj->Mappings[MAP_INTERNAL].Pointer,
+                            binding->Offset + attrib->RelativeOffset);
       }
       else
-	 ptr = inputs[i]->Ptr;
+         ptr = attrib->Ptr;
 
       /* Just make sure the array is floating point, otherwise convert to
        * temporary storage.  
@@ -306,7 +313,7 @@ static void bind_inputs( struct gl_context *ctx,
        * XXX: remove the GLvector4f type at some stage and just use
        * client arrays.
        */
-      _tnl_import_array(ctx, i, count, inputs[i], ptr);
+      _tnl_import_array(ctx, i, count, binding, attrib, ptr);
    }
 
    /* We process only the vertices between min & max index:
@@ -431,7 +438,7 @@ void _tnl_draw_prims(struct gl_context *ctx,
 			 struct gl_buffer_object *indirect)
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
-   const struct gl_vertex_array **arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *arrays = ctx->Array._DrawArrays;
    const GLuint TEST_SPLIT = 0;
    const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;
    GLint max_basevertex = prim->basevertex;
diff --git a/src/mesa/tnl/t_rebase.c b/src/mesa/tnl/t_rebase.c
index b781781cb0..0fcee03b24 100644
--- a/src/mesa/tnl/t_rebase.c
+++ b/src/mesa/tnl/t_rebase.c
@@ -47,6 +47,7 @@
  */
 
 #include <stdio.h>
+#include "main/bufferobj.h"
 #include "main/glheader.h"
 #include "main/imports.h"
 #include "main/mtypes.h"
@@ -101,7 +102,7 @@ REBASE(GLubyte)
  *      all or nothing.
  */
 void t_rebase_prims( struct gl_context *ctx,
-                     const struct gl_vertex_array *arrays[],
+                     const struct gl_vertex_array *arrays,
                      const struct _mesa_prim *prim,
                      GLuint nr_prims,
                      const struct _mesa_index_buffer *ib,
@@ -109,12 +110,12 @@ void t_rebase_prims( struct gl_context *ctx,
                      GLuint max_index,
                      vbo_draw_func draw )
 {
+   struct gl_array_attributes tmp_attribs[VERT_ATTRIB_MAX];
    struct gl_vertex_array tmp_arrays[VERT_ATTRIB_MAX];
-   const struct gl_vertex_array *tmp_array_pointers[VERT_ATTRIB_MAX];
 
    struct _mesa_index_buffer tmp_ib;
    struct _mesa_prim *tmp_prims = NULL;
-   const struct gl_vertex_array **saved_arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *saved_arrays = ctx->Array._DrawArrays;
    void *tmp_indices = NULL;
    GLuint i;
 
@@ -220,14 +221,19 @@ void t_rebase_prims( struct gl_context *ctx,
     * are forced to, eg non-VBO indexed rendering with start != 0.
     */
    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
-      tmp_arrays[i] = *arrays[i];
-      tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
-      tmp_array_pointers[i] = &tmp_arrays[i];
+      tmp_attribs[i] = *(arrays[i].VertexAttrib);
+      tmp_arrays[i].BufferBinding = arrays[i].BufferBinding;
+      tmp_arrays[i].VertexAttrib = &tmp_attribs[i];
+      if (_mesa_is_bufferobj(arrays[i].BufferBinding->BufferObj))
+         tmp_attribs[i].RelativeOffset +=
+            min_index * arrays[i].BufferBinding->Stride;
+      else
+         tmp_attribs[i].Ptr += min_index * arrays[i].BufferBinding->Stride;
    }
    
    /* Re-issue the draw call.
     */
-   ctx->Array._DrawArrays = tmp_array_pointers;
+   ctx->Array._DrawArrays = tmp_arrays;
    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
    draw( ctx, 
diff --git a/src/mesa/tnl/t_rebase.h b/src/mesa/tnl/t_rebase.h
index 35175868d5..16a3a2b5a3 100644
--- a/src/mesa/tnl/t_rebase.h
+++ b/src/mesa/tnl/t_rebase.h
@@ -28,7 +28,7 @@
 #include "vbo/vbo.h"
 
 void t_rebase_prims( struct gl_context *ctx,
-                     const struct gl_vertex_array *arrays[],
+                     const struct gl_vertex_array *arrays,
                      const struct _mesa_prim *prim,
                      GLuint nr_prims,
                      const struct _mesa_index_buffer *ib,
diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index 345aa6b0d2..d6cf8e2afe 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -216,7 +216,7 @@ struct split_limits
 
 void
 vbo_split_prims(struct gl_context *ctx,
-                const struct gl_vertex_array *arrays[],
+                const struct gl_vertex_array *arrays,
                 const struct _mesa_prim *prim,
                 GLuint nr_prims,
                 const struct _mesa_index_buffer *ib,
@@ -266,7 +266,7 @@ struct vbo_inputs
     * current values. The array of pointers is updated incrementally
     * based on the current and vertex_processing_mode values below.
     */
-   const struct gl_vertex_array *inputs[VERT_ATTRIB_MAX];
+   struct gl_vertex_array inputs[VERT_ATTRIB_MAX];
    /** Those VERT_BIT_'s where the inputs array point to current values. */
    GLbitfield current;
    /** Store which aliasing current values - generics or materials - are set. */
diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c
index 3dc3222c0d..acb28d0293 100644
--- a/src/mesa/vbo/vbo_context.c
+++ b/src/mesa/vbo/vbo_context.c
@@ -53,20 +53,17 @@ check_size(const GLfloat *attr)
  * Helper for initializing a vertex array.
  */
 static void
-init_array(struct gl_context *ctx, struct gl_vertex_array *array,
+init_array(struct gl_context *ctx, struct gl_array_attributes *attrib,
            unsigned size, const void *pointer)
 {
-   memset(array, 0, sizeof(*array));
-
-   array->Size = size;
-   array->Type = GL_FLOAT;
-   array->Format = GL_RGBA;
-   array->StrideB = 0;
-   array->_ElementSize = array->Size * sizeof(GLfloat);
-   array->Ptr = pointer;
-
-   _mesa_reference_buffer_object(ctx, &array->BufferObj,
-                                 ctx->Shared->NullBufferObj);
+   memset(attrib, 0, sizeof(*attrib));
+
+   attrib->Size = size;
+   attrib->Type = GL_FLOAT;
+   attrib->Format = GL_RGBA;
+   attrib->Stride = 0;
+   attrib->_ElementSize = size * sizeof(GLfloat);
+   attrib->Ptr = pointer;
 }
 
 
@@ -80,15 +77,15 @@ init_legacy_currval(struct gl_context *ctx)
    struct vbo_context *vbo = vbo_context(ctx);
    GLuint i;
 
-   /* Set up a constant (StrideB == 0) array for each current
+   /* Set up a constant (Stride == 0) array for each current
     * attribute:
     */
    for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
-      struct gl_vertex_array *array = &vbo->currval[VERT_ATTRIB_FF(i)];
+      const unsigned attr = VERT_ATTRIB_FF(i);
+      struct gl_array_attributes *attrib = &vbo->current[attr];
 
-      init_array(ctx, array,
-                 check_size(ctx->Current.Attrib[i]),
-                 ctx->Current.Attrib[i]);
+      init_array(ctx, attrib, check_size(ctx->Current.Attrib[attr]),
+                 ctx->Current.Attrib[attr]);
    }
 }
 
@@ -100,9 +97,10 @@ init_generic_currval(struct gl_context *ctx)
    GLuint i;
 
    for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
-      struct gl_vertex_array *array = &vbo->currval[VBO_ATTRIB_GENERIC0 + i];
+      const unsigned attr = VBO_ATTRIB_GENERIC0 + i;
+      struct gl_array_attributes *attrib = &vbo->current[attr];
 
-      init_array(ctx, array, 1, ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i]);
+      init_array(ctx, attrib, 1, ctx->Current.Attrib[attr]);
    }
 }
 
@@ -117,8 +115,8 @@ init_mat_currval(struct gl_context *ctx)
     * attribute:
     */
    for (i = 0; i < MAT_ATTRIB_MAX; i++) {
-      struct gl_vertex_array *array =
-         &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT + i];
+      const unsigned attr = VBO_ATTRIB_MAT_FRONT_AMBIENT + i;
+      struct gl_array_attributes *attrib = &vbo->current[attr];
       unsigned size;
 
       /* Size is fixed for the material attributes, for others will
@@ -138,7 +136,7 @@ init_mat_currval(struct gl_context *ctx)
          break;
       }
 
-      init_array(ctx, array, size, ctx->Light.Material.Attrib[i]);
+      init_array(ctx, attrib, size, ctx->Light.Material.Attrib[i]);
    }
 }
 
@@ -237,6 +235,11 @@ _vbo_CreateContext(struct gl_context *ctx)
       return GL_FALSE;
    }
 
+   vbo->binding.Offset = 0;
+   vbo->binding.Stride = 0;
+   vbo->binding.InstanceDivisor = 0;
+   _mesa_reference_buffer_object(ctx, &vbo->binding.BufferObj,
+                                 ctx->Shared->NullBufferObj);
    init_legacy_currval(ctx);
    init_generic_currval(ctx);
    init_mat_currval(ctx);
@@ -276,11 +279,8 @@ _vbo_DestroyContext(struct gl_context *ctx)
    }
 
    if (vbo) {
-      GLuint i;
 
-      for (i = 0; i < VBO_ATTRIB_MAX; i++) {
-         _mesa_reference_buffer_object(ctx, &vbo->currval[i].BufferObj, NULL);
-      }
+      _mesa_reference_buffer_object(ctx, &vbo->binding.BufferObj, NULL);
 
       vbo_exec_destroy(ctx);
       if (ctx->API == API_OPENGL_COMPAT)
diff --git a/src/mesa/vbo/vbo_exec.c b/src/mesa/vbo/vbo_exec.c
index 69a150c78b..c0b0a11fe5 100644
--- a/src/mesa/vbo/vbo_exec.c
+++ b/src/mesa/vbo/vbo_exec.c
@@ -267,11 +267,14 @@ update_vao_inputs(struct gl_context *ctx,
 
    /* Fill in the client arrays from the VAO */
    const GLubyte *const map = _mesa_vao_attribute_map[vao->_AttributeMapMode];
-   const struct gl_vertex_array *array = vao->_VertexArray;
-   const struct gl_vertex_array **iarray = &inputs->inputs[0];
+   const struct gl_array_attributes *attribs = &vao->VertexAttrib[0];
+   const struct gl_vertex_buffer_binding *bindings = &vao->BufferBinding[0];
    while (enable) {
       const int attr = u_bit_scan(&enable);
-      iarray[attr] = &array[map[attr]];
+      struct gl_vertex_array *input = &inputs->inputs[attr];
+      const struct gl_array_attributes *attrib = &attribs[map[attr]];
+      input->VertexAttrib = attrib;
+      input->BufferBinding = &bindings[attrib->BufferBindingIndex];
    }
 }
 
@@ -294,12 +297,13 @@ update_current_inputs(struct gl_context *ctx,
       mask |= current & VERT_BIT_MAT_ALL;
 
    struct vbo_context *vbo = vbo_context(ctx);
-   const struct gl_vertex_array *const currval = &vbo->currval[0];
-   const struct gl_vertex_array **iarray = &inputs->inputs[0];
+   const struct gl_array_attributes *const currval = &vbo->current[0];
    const GLubyte *const map = _vbo_attribute_alias_map[mode];
    while (mask) {
       const int attr = u_bit_scan(&mask);
-      iarray[attr] = &currval[map[attr]];
+      struct gl_vertex_array *input = &inputs->inputs[attr];
+      input->VertexAttrib = &currval[map[attr]];
+      input->BufferBinding = &vbo->binding;
    }
 
    inputs->current = current;
diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
index 317fc43d1c..b3971715b5 100644
--- a/src/mesa/vbo/vbo_exec_api.c
+++ b/src/mesa/vbo/vbo_exec_api.c
@@ -174,7 +174,7 @@ vbo_exec_copy_to_current(struct vbo_exec_context *exec)
       /* Note: the exec->vtx.current[i] pointers point into the
        * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
        */
-      GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+      GLfloat *current = (GLfloat *)vbo->current[i].Ptr;
       fi_type tmp[8]; /* space for doubles */
       int dmul = 1;
 
@@ -195,7 +195,7 @@ vbo_exec_copy_to_current(struct vbo_exec_context *exec)
                                      exec->vtx.attrtype[i]);
       }
 
-      if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
+      if (exec->vtx.attrtype[i] != vbo->current[i].Type ||
           memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
          memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul);
 
@@ -205,13 +205,13 @@ vbo_exec_copy_to_current(struct vbo_exec_context *exec)
           * directly.
           */
          /* Size here is in components - not bytes */
-         vbo->currval[i].Size = exec->vtx.attrsz[i] / dmul;
-         vbo->currval[i]._ElementSize =
-            vbo->currval[i].Size * sizeof(GLfloat) * dmul;
-         vbo->currval[i].Type = exec->vtx.attrtype[i];
-         vbo->currval[i].Integer =
+         vbo->current[i].Size = exec->vtx.attrsz[i] / dmul;
+         vbo->current[i]._ElementSize =
+            vbo->current[i].Size * sizeof(GLfloat) * dmul;
+         vbo->current[i].Type = exec->vtx.attrtype[i];
+         vbo->current[i].Integer =
             vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
-         vbo->currval[i].Doubles =
+         vbo->current[i].Doubles =
             vbo_attrtype_to_double_flag(exec->vtx.attrtype[i]);
 
          /* This triggers rather too much recalculation of Mesa state
@@ -248,10 +248,10 @@ vbo_exec_copy_from_current(struct vbo_exec_context *exec)
    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
       if (exec->vtx.attrtype[i] == GL_DOUBLE ||
           exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB) {
-         memcpy(exec->vtx.attrptr[i], vbo->currval[i].Ptr,
+         memcpy(exec->vtx.attrptr[i], vbo->current[i].Ptr,
                 exec->vtx.attrsz[i] * sizeof(GLfloat));
       } else {
-         const fi_type *current = (fi_type *) vbo->currval[i].Ptr;
+         const fi_type *current = (fi_type *) vbo->current[i].Ptr;
          switch (exec->vtx.attrsz[i]) {
          case 4: exec->vtx.attrptr[i][3] = current[3];
          case 3: exec->vtx.attrptr[i][2] = current[2];
@@ -379,7 +379,7 @@ vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
                                               exec->vtx.attrtype[j]);
                   COPY_SZ_4V(dest + new_offset, newSize, tmp);
                } else {
-                  fi_type *current = (fi_type *)vbo->currval[j].Ptr;
+                  fi_type *current = (fi_type *)vbo->current[j].Ptr;
                   COPY_SZ_4V(dest + new_offset, sz, current);
                }
             }
diff --git a/src/mesa/vbo/vbo_private.h b/src/mesa/vbo/vbo_private.h
index 1f3d31f577..112a4605c7 100644
--- a/src/mesa/vbo/vbo_private.h
+++ b/src/mesa/vbo/vbo_private.h
@@ -44,7 +44,8 @@ struct _mesa_prim;
 
 
 struct vbo_context {
-   struct gl_vertex_array currval[VBO_ATTRIB_MAX];
+   struct gl_vertex_buffer_binding binding;
+   struct gl_array_attributes current[VBO_ATTRIB_MAX];
    /* The array of inputs used for _DrawVAO draws. */
    struct vbo_inputs draw_arrays;
 
diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c
index 137fb6e3fd..69d28312d3 100644
--- a/src/mesa/vbo/vbo_save_draw.c
+++ b/src/mesa/vbo/vbo_save_draw.c
@@ -52,7 +52,7 @@ copy_vao(struct gl_context *ctx, const struct gl_vertex_array_object *vao,
    while (mask) {
       const int i = u_bit_scan(&mask);
       const struct gl_array_attributes *attrib = &vao->VertexAttrib[i];
-      struct gl_vertex_array *currval = &vbo->currval[shift + i];
+      struct gl_array_attributes *currval = &vbo->current[shift + i];
       const GLubyte size = attrib->Size;
       const GLenum16 type = attrib->Type;
       fi_type tmp[4];
diff --git a/src/mesa/vbo/vbo_split.c b/src/mesa/vbo/vbo_split.c
index 974a708dcb..ffe1d67489 100644
--- a/src/mesa/vbo/vbo_split.c
+++ b/src/mesa/vbo/vbo_split.c
@@ -100,7 +100,7 @@ split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr)
 
 void
 vbo_split_prims(struct gl_context *ctx,
-                const struct gl_vertex_array *arrays[],
+                const struct gl_vertex_array arrays[],
                 const struct _mesa_prim *prim,
                 GLuint nr_prims,
                 const struct _mesa_index_buffer *ib,
diff --git a/src/mesa/vbo/vbo_split.h b/src/mesa/vbo/vbo_split.h
index dbd629979d..fea2b48aec 100644
--- a/src/mesa/vbo/vbo_split.h
+++ b/src/mesa/vbo/vbo_split.h
@@ -51,7 +51,7 @@ split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr);
 
 void
 vbo_split_inplace(struct gl_context *ctx,
-                  const struct gl_vertex_array *arrays[],
+                  const struct gl_vertex_array arrays[],
                   const struct _mesa_prim *prim,
                   GLuint nr_prims,
                   const struct _mesa_index_buffer *ib,
@@ -64,7 +64,7 @@ vbo_split_inplace(struct gl_context *ctx,
  */
 void
 vbo_split_copy(struct gl_context *ctx,
-               const struct gl_vertex_array *arrays[],
+               const struct gl_vertex_array arrays[],
                const struct _mesa_prim *prim,
                GLuint nr_prims,
                const struct _mesa_index_buffer *ib,
diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c
index 2de909f512..09b5b3b651 100644
--- a/src/mesa/vbo/vbo_split_copy.c
+++ b/src/mesa/vbo/vbo_split_copy.c
@@ -37,6 +37,7 @@
 #include "main/glformats.h"
 #include "main/macros.h"
 #include "main/mtypes.h"
+#include "main/varray.h"
 
 #include "vbo_split.h"
 #include "vbo.h"
@@ -51,7 +52,7 @@
  */
 struct copy_context {
    struct gl_context *ctx;
-   const struct gl_vertex_array **array;
+   const struct gl_vertex_array *array;
    const struct _mesa_prim *prim;
    GLuint nr_prims;
    const struct _mesa_index_buffer *ib;
@@ -62,15 +63,15 @@ struct copy_context {
    struct {
       GLuint attr;
       GLuint size;
-      const struct gl_vertex_array *array;
       const GLubyte *src_ptr;
 
-      struct gl_vertex_array dstarray;
+      struct gl_vertex_buffer_binding dstbinding;
+      struct gl_array_attributes dstattribs;
 
    } varying[VERT_ATTRIB_MAX];
    GLuint nr_varying;
 
-   const struct gl_vertex_array *dstarray_ptr[VERT_ATTRIB_MAX];
+   struct gl_vertex_array dstarray[VERT_ATTRIB_MAX];
    struct _mesa_index_buffer dstib;
 
    GLuint *translated_elt_buf;
@@ -103,9 +104,9 @@ struct copy_context {
 
 
 static GLuint
-attr_size(const struct gl_vertex_array *array)
+attr_size(const struct gl_array_attributes *attrib)
 {
-   return array->Size * _mesa_sizeof_type(array->Type);
+   return attrib->Size * _mesa_sizeof_type(attrib->Type);
 }
 
 
@@ -139,7 +140,7 @@ check_flush(struct copy_context *copy)
  */
 static void
 dump_draw_info(struct gl_context *ctx,
-               const struct gl_vertex_array **arrays,
+               const struct gl_vertex_array *arrays,
                const struct _mesa_prim *prims,
                GLuint nr_prims,
                const struct _mesa_index_buffer *ib,
@@ -154,13 +155,17 @@ dump_draw_info(struct gl_context *ctx,
       printf("  Prim mode 0x%x\n", prims[i].mode);
       printf("  IB: %p\n", (void*) ib);
       for (j = 0; j < VERT_ATTRIB_MAX; j++) {
-         printf("    array %d at %p:\n", j, (void*) arrays[j]);
+         const struct gl_vertex_array *array = &arrays[j];
+         const struct gl_vertex_buffer_binding *binding
+            = array->BufferBinding;
+         const struct gl_array_attributes *attrib = array->VertexAttrib;
+         const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
+         printf("    array %d at %p:\n", j, (void*) &arrays[j]);
          printf("      ptr %p, size %d, type 0x%x, stride %d\n",
-                arrays[j]->Ptr,
-                arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
+                ptr, attrib->Size, attrib->Type, binding->Stride);
          if (0) {
             GLint k = prims[i].start + prims[i].count - 1;
-            GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->StrideB * k);
+            GLfloat *last = (GLfloat *) (ptr + binding->Stride * k);
             printf("        last: %f %f %f\n",
                    last[0], last[1], last[2]);
          }
@@ -173,7 +178,7 @@ static void
 flush(struct copy_context *copy)
 {
    struct gl_context *ctx = copy->ctx;
-   const struct gl_vertex_array **saved_arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *saved_arrays = ctx->Array._DrawArrays;
    GLuint i;
 
    /* Set some counters:
@@ -182,7 +187,7 @@ flush(struct copy_context *copy)
 
 #if 0
    dump_draw_info(copy->ctx,
-                  copy->dstarray_ptr,
+                  copy->dstarray,
                   copy->dstprim,
                   copy->dstprim_nr,
                   &copy->dstib,
@@ -192,7 +197,7 @@ flush(struct copy_context *copy)
    (void) dump_draw_info;
 #endif
 
-   ctx->Array._DrawArrays = copy->dstarray_ptr;
+   ctx->Array._DrawArrays = copy->dstarray;
    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
    copy->draw(ctx,
@@ -253,8 +258,11 @@ elt(struct copy_context *copy, GLuint elt_idx)
       GLuint i;
 
       for (i = 0; i < copy->nr_varying; i++) {
-         const struct gl_vertex_array *srcarray = copy->varying[i].array;
-         const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
+         const struct gl_vertex_array *srcarray = &copy->array[i];
+         const struct gl_vertex_buffer_binding* srcbinding
+            = srcarray->BufferBinding;
+         const GLubyte *srcptr
+            = copy->varying[i].src_ptr + elt * srcbinding->Stride;
 
          memcpy(csr, srcptr, copy->varying[i].size);
          csr += copy->varying[i].size;
@@ -428,18 +436,21 @@ replay_init(struct copy_context *copy)
     */
    copy->vertex_size = 0;
    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
-      struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
+      const struct gl_vertex_array *array = &copy->array[i];
+      const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
 
-      if (copy->array[i]->StrideB == 0) {
-         copy->dstarray_ptr[i] = copy->array[i];
+      if (binding->Stride == 0) {
+         _mesa_copy_vertex_array(&copy->dstarray[i], array);
       }
       else {
+         const struct gl_array_attributes *attrib = array->VertexAttrib;
+         struct gl_buffer_object *vbo = binding->BufferObj;
+         const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
          GLuint j = copy->nr_varying++;
 
          copy->varying[j].attr = i;
-         copy->varying[j].array = copy->array[i];
-         copy->varying[j].size = attr_size(copy->array[i]);
-         copy->vertex_size += attr_size(copy->array[i]);
+         copy->varying[j].size = attr_size(attrib);
+         copy->vertex_size += attr_size(attrib);
 
          if (_mesa_is_bufferobj(vbo) &&
              !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
@@ -447,10 +458,10 @@ replay_init(struct copy_context *copy)
                                        MAP_INTERNAL);
 
          copy->varying[j].src_ptr =
-               ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer,
-                            copy->array[i]->Ptr);
+               ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr);
 
-         copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
+         copy->dstarray[i].VertexAttrib = &copy->varying[j].dstattribs;
+         copy->dstarray[i].BufferBinding = &copy->varying[j].dstbinding;
       }
    }
 
@@ -509,19 +520,24 @@ replay_init(struct copy_context *copy)
    /* Setup new vertex arrays to point into the output buffer:
     */
    for (offset = 0, i = 0; i < copy->nr_varying; i++) {
-      const struct gl_vertex_array *src = copy->varying[i].array;
-      struct gl_vertex_array *dst = &copy->varying[i].dstarray;
-
-      dst->Size = src->Size;
-      dst->Type = src->Type;
-      dst->Format = GL_RGBA;
-      dst->StrideB = copy->vertex_size;
-      dst->Ptr = copy->dstbuf + offset;
-      dst->Normalized = src->Normalized;
-      dst->Integer = src->Integer;
-      dst->Doubles = src->Doubles;
-      dst->BufferObj = ctx->Shared->NullBufferObj;
-      dst->_ElementSize = src->_ElementSize;
+      const struct gl_vertex_array *src = &copy->array[i];
+      const struct gl_array_attributes *srcattr = src->VertexAttrib;
+      struct gl_vertex_array *dst = &copy->dstarray[i];
+      struct gl_vertex_buffer_binding *dstbind = &copy->varying[i].dstbinding;
+      struct gl_array_attributes *dstattr = &copy->varying[i].dstattribs;
+
+      dstattr->Size = srcattr->Size;
+      dstattr->Type = srcattr->Type;
+      dstattr->Format = GL_RGBA;
+      dstbind->Stride = copy->vertex_size;
+      dstattr->Ptr = copy->dstbuf + offset;
+      dstattr->Normalized = srcattr->Normalized;
+      dstattr->Integer = srcattr->Integer;
+      dstattr->Doubles = srcattr->Doubles;
+      dstbind->BufferObj = ctx->Shared->NullBufferObj;
+      dstattr->_ElementSize = srcattr->_ElementSize;
+      dst->BufferBinding = dstbind;
+      dst->VertexAttrib = dstattr;
 
       offset += copy->varying[i].size;
    }
@@ -559,7 +575,8 @@ replay_finish(struct copy_context *copy)
 
    /* Unmap VBO's */
    for (i = 0; i < copy->nr_varying; i++) {
-      struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
+      struct gl_buffer_object *vbo =
+         copy->array[i].BufferBinding->BufferObj;
       if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
          ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL);
    }
@@ -577,7 +594,7 @@ replay_finish(struct copy_context *copy)
  */
 void
 vbo_split_copy(struct gl_context *ctx,
-               const struct gl_vertex_array *arrays[],
+               const struct gl_vertex_array *arrays,
                const struct _mesa_prim *prim,
                GLuint nr_prims,
                const struct _mesa_index_buffer *ib,
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
index 2c363c2776..971c52a078 100644
--- a/src/mesa/vbo/vbo_split_inplace.c
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -41,7 +41,7 @@
  */
 struct split_context {
    struct gl_context *ctx;
-   const struct gl_vertex_array **array;
+   const struct gl_vertex_array *array;
    const struct _mesa_prim *prim;
    GLuint nr_prims;
    const struct _mesa_index_buffer *ib;
@@ -63,7 +63,7 @@ static void
 flush_vertex( struct split_context *split)
 {
    struct gl_context *ctx = split->ctx;
-   const struct gl_vertex_array **saved_arrays = ctx->Array._DrawArrays;
+   const struct gl_vertex_array *saved_arrays = ctx->Array._DrawArrays;
    struct _mesa_index_buffer ib;
    GLuint i;
 
@@ -268,7 +268,7 @@ split_prims(struct split_context *split)
 
 void
 vbo_split_inplace(struct gl_context *ctx,
-                  const struct gl_vertex_array *arrays[],
+                  const struct gl_vertex_array *arrays,
                   const struct _mesa_prim *prim,
                   GLuint nr_prims,
                   const struct _mesa_index_buffer *ib,
-- 
2.14.3



More information about the mesa-dev mailing list