[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
Tue Mar 6 07:48:42 UTC 2018


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

Hi,

The change basically strips down gl_vertex_array to two pointers
into the VAO. Consequently the current vertex attributes in the
vbo module need to be represented by structs present in the VAO
instead of gl_vertex_array instances.
The change prepares the backends somewhat to use the _DrawVAO for
draw operations in the longer term.

The change introduced no piglit quick regressions on classic swrast
to test drivers using tnl, i965 and radeonsi.

Please review!
Thanks!

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.

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          |  30 +++---
 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  |  86 ++++++++++-------
 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                         |  81 ++++++++--------
 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(+), 430 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index d6e3c7807f..ee55c32087 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -1456,7 +1456,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..677eb87729 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,18 @@ brw_merge_inputs(struct brw_context *brw,
        * 2_10_10_10_REV vertex formats.  Set appropriate workaround flags.
        */
       while (mask) {
+         const struct gl_vertex_array *glarray;
+         const struct gl_array_attributes *glattrib;
          uint8_t wa_flags = 0;
 
          i = u_bit_scan64(&mask);
+         glarray = brw->vb.inputs[i].glarray;
+         glattrib = 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 +319,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 +693,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 +780,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 +915,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 +943,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..73ac028505 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,21 @@ 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 *glbinding = a->BufferBinding;
 
-	if (render->mode == VBO && !_mesa_is_bufferobj(a->BufferObj))
+	if (render->mode == VBO && !_mesa_is_bufferobj(glbinding->BufferObj)) {
+		const struct gl_array_attributes *glattrib = a->VertexAttrib;
+		const GLenum16 type = glattrib->Type;
 		/* Pack client buffers. */
-		return align(_mesa_sizeof_type(a->Type) * a->Size, 4);
-	else
-		return a->StrideB;
+		return align(_mesa_sizeof_type(type) * glattrib->Size, 4);
+	} else {
+		return glbinding->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 +79,25 @@ 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 *glbinding =
+			array->BufferBinding;
+		const struct gl_array_attributes *glattrib =
+			array->VertexAttrib;
+		const GLubyte *p =
+			_mesa_vertex_attrib_address(glattrib, glbinding);
 
 		nouveau_init_array(&render->attrs[attr], attr,
 				   get_array_stride(ctx, array),
-				   array->Size, array->Type,
-				   imm ? array->BufferObj : NULL,
-				   array->Ptr, imm, ctx);
+				   glattrib->Size, glattrib->Type,
+				   imm ? glbinding->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 +121,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 +130,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 +139,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 *glbinding = array->BufferBinding;
+	const struct gl_array_attributes *glattrib = array->VertexAttrib;
+	const GLubyte *p = _mesa_vertex_attrib_address(glattrib, glbinding);
 	struct nouveau_array *a = &render->attrs[attr];
 	RENDER_LOCALS(ctx);
 
-	if (!array->StrideB) {
+	if (!glbinding->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, glbinding->Stride, glattrib->Size,
+				   glattrib->Type, glbinding->BufferObj, p,
 				   GL_TRUE, ctx);
 		EMIT_IMM(ctx, a, 0);
 		nouveau_deinit_array(a);
@@ -155,7 +169,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 += glattrib->_ElementSize;
 			render->attr_count = MAX2(render->attr_count,
 						  info->vbo_index + 1);
 		} else {
@@ -168,7 +182,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 +225,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 +251,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 +311,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 +325,28 @@ 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 *glbinding =
+			array->BufferBinding;
+		const struct gl_array_attributes *glattrib =
+			array->VertexAttrib;
+		const GLubyte *p =
+			_mesa_vertex_attrib_address(glattrib, glbinding);
+		struct gl_buffer_object *obj = glbinding->BufferObj;
 		struct nouveau_array *a = &render->attrs[attr];
-		unsigned delta = (base + min_index) * array->StrideB;
+		unsigned delta = (base + min_index) * glbinding->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 +354,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 * glbinding->Stride,
 				       a->stride);
 		}
 
@@ -365,7 +385,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 +435,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 +490,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..859e31076e 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);
+
+/**
+ * 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..f39a76c274 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 *glbinding;
    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;
+   glbinding = arrays[VERT_ATTRIB_EDGEFLAG].BufferBinding;
+   vertdata_edgeflags = edgeflags_enabled && glbinding->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..7dac00e3b2 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 *glbinding;
+      const struct gl_array_attributes *glattrib;
+      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 */
+      glbinding = array->BufferBinding;
+      glattrib = array->VertexAttrib;
+      stride = glbinding->Stride; /* in bytes */
+      ptr = _mesa_vertex_attrib_address(glattrib, glbinding);
 
       /* To keep things simple, don't allow interleaved zero-stride attribs. */
       if (stride == 0)
          return false;
 
-      bufObj = array->BufferObj;
+      bufObj = glbinding->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 *glbinding;
+      const struct gl_array_attributes *glattrib;
 
       array = get_client_array(arrays, vp->index_to_input[0]);
       assert(array);
 
+      glbinding = array->BufferBinding;
+      glattrib = 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 = glbinding->BufferObj;
+      stride = glbinding->Stride;
 
-      low_addr = arrays[vp->index_to_input[0]]->Ptr;
+      low_addr = _mesa_vertex_attrib_address(glattrib, glbinding);
 
       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;
+         glbinding = array->BufferBinding;
+         glattrib = array->VertexAttrib;
+         start = _mesa_vertex_attrib_address(glattrib, glbinding);
          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 *glbinding;
+      const struct gl_array_attributes *glattrib;
+      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));
+      glbinding = array->BufferBinding;
+      glattrib = array->VertexAttrib;
+      ptr = _mesa_vertex_attrib_address(glattrib, glbinding);
+
+      src_offset = (unsigned) (ptr - low_addr);
+      assert(glattrib->_ElementSize ==
+             _mesa_bytes_per_vertex_attrib(glattrib->Size, glattrib->Type));
 
-      src_format = st_pipe_vertex_format(array->Type,
-                                         array->Size,
-                                         array->Format,
-                                         array->Normalized,
-                                         array->Integer);
+      src_format = st_pipe_vertex_format(glattrib->Type,
+                                         glattrib->Size,
+                                         glattrib->Format,
+                                         glattrib->Normalized,
+                                         glattrib->Integer);
 
       init_velement_lowered(vp, velements, src_offset, src_format,
-                            array->InstanceDivisor, 0,
-                            array->Size, array->Doubles, &attr);
+                            glbinding->InstanceDivisor, 0,
+                            glattrib->Size, glattrib->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 *glbinding;
+      const struct gl_array_attributes *glattrib;
       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));
+      glbinding = array->BufferBinding;
+      glattrib = array->VertexAttrib;
+      stride = glbinding->Stride;
+      bufobj = glbinding->BufferObj;
+      assert(glattrib->_ElementSize ==
+             _mesa_bytes_per_vertex_attrib(glattrib->Size, glattrib->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 =
+            glbinding->Offset + glattrib->RelativeOffset;
       }
       else {
          if (stride == 0) {
-            unsigned size = array->_ElementSize;
+            unsigned size = glattrib->_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(glattrib->Ptr);
+            vbuffer[bufidx].buffer.user = glattrib->Ptr;
+            void *ptr = glattrib->Ptr ? (void*)glattrib->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(glattrib->Ptr);
+            vbuffer[bufidx].buffer.user = glattrib->Ptr;
             vbuffer[bufidx].is_user_buffer = true;
             vbuffer[bufidx].buffer_offset = 0;
 
-            if (!array->InstanceDivisor)
+            if (!glbinding->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(glattrib->Type,
+                                         glattrib->Size,
+                                         glattrib->Format,
+                                         glattrib->Normalized,
+                                         glattrib->Integer);
 
       init_velement_lowered(vp, velements, 0, src_format,
-                            array->InstanceDivisor, bufidx,
-                            array->Size, array->Doubles, &attr);
+                            glbinding->InstanceDivisor, bufidx,
+                            glattrib->Size, glattrib->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..17b082ac73 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 glbinding;
+   struct gl_array_attributes glattrib[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->glbinding.Stride = 0;
+   rs->glbinding.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->glattrib[i].Size = 4;
+      rs->glattrib[i].Type = GL_FLOAT;
+      rs->glattrib[i].Format = GL_RGBA;
+      rs->glattrib[i].Ptr = (GLubyte *) ctx->Current.Attrib[i];
+      rs->glattrib[i].Normalized = GL_TRUE;
+      rs->array[i].BufferBinding = &rs->glbinding;
+      rs->array[i].VertexAttrib = &rs->glattrib[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->glattrib[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..b0f8b14e6f 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 *glarray;
+      const struct gl_vertex_buffer_binding *glbinding;
+      const struct gl_array_attributes *glattrib;
+      glarray = &arrays[vp->index_to_input[0]];
+      glbinding = glarray->BufferBinding;
+      glattrib = glarray->VertexAttrib;
+
+      low_addr = _mesa_vertex_attrib_address(glattrib, glbinding);
 
       for (attr = 1; attr < vp->num_inputs; attr++) {
-         const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
+         const GLubyte *start;
+         glarray = &arrays[vp->index_to_input[attr]];
+         glbinding = glarray->BufferBinding;
+         glattrib = glarray->VertexAttrib;
+         start = _mesa_vertex_attrib_address(glattrib, glbinding);
          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 *glarray = &arrays[mesaAttr];
+      const struct gl_vertex_buffer_binding *glbinding;
+      const struct gl_array_attributes *glattrib;
+      struct gl_buffer_object *bufobj;
       void *map;
 
+      glbinding = glarray->BufferBinding;
+      glattrib = glarray->VertexAttrib;
+      bufobj = glbinding->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 = glbinding->Offset
+            + glattrib->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 = glattrib->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 = glbinding->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(glattrib->Type,
+                               glattrib->Size,
+                               glattrib->Format,
+                               glattrib->Normalized,
+                               glattrib->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..cf5cb4bdc8 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 (glattrib->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 += glbinding->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 += glbinding->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 *glbinding,
+                      const struct gl_array_attributes *glattrib,
                       const GLubyte *ptr, GLfloat *fptr,
                       GLuint count )
 {
    GLuint i;
-   assert(input->Normalized);
-   assert(input->Size == 4);
+   assert(glattrib->Normalized);
+   assert(glattrib->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 += glbinding->Stride;
    }
 }
 
 static void
-convert_half_to_float(const struct gl_vertex_array *input,
+convert_half_to_float(const struct gl_vertex_buffer_binding *glbinding,
+                      const struct gl_array_attributes *glattrib,
 		      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 += glbinding->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 *glbinding,
+                       const struct gl_array_attributes *glattrib,
                        const GLubyte *ptr, GLfloat *fptr,
                        GLuint count)
 {
    GLuint i;
    GLint j;
-   const GLint size = input->Size;
+   const GLint size = glattrib->Size;
 
-   if (input->Normalized) {
+   if (glattrib->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 += glbinding->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 += glbinding->Stride;
       }
    }
 }
@@ -174,26 +177,27 @@ convert_fixed_to_float(const struct gl_vertex_array *input,
 static void _tnl_import_array( struct gl_context *ctx,
 			       GLuint attrib,
 			       GLuint count,
-			       const struct gl_vertex_array *input,
+                               const struct gl_vertex_buffer_binding *glbinding,
+                               const struct gl_array_attributes *glattrib,
 			       const GLubyte *ptr )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
-   GLuint stride = input->StrideB;
+   GLuint stride = glbinding->Stride;
 
-   if (input->Type != GL_FLOAT) {
-      const GLuint sz = input->Size;
+   if (glattrib->Type != GL_FLOAT) {
+      const GLuint sz = glattrib->Size;
       GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat));
       GLfloat *fptr = (GLfloat *)buf;
 
-      switch (input->Type) {
+      switch (glattrib->Type) {
       case GL_BYTE: 
 	 CONVERT(GLbyte, BYTE_TO_FLOAT); 
 	 break;
       case GL_UNSIGNED_BYTE: 
-         if (input->Format == GL_BGRA) {
+         if (glattrib->Format == GL_BGRA) {
             /* See GL_EXT_vertex_array_bgra */
-            convert_bgra_to_float(input, ptr, fptr, count);
+            convert_bgra_to_float(glbinding, glattrib, 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(glbinding, glattrib, ptr, fptr, count, sz);
 	 break;
       case GL_FIXED:
-         convert_fixed_to_float(input, ptr, fptr, count);
+         convert_fixed_to_float(glbinding, glattrib, ptr, fptr, count);
          break;
       default:
 	 assert(0);
@@ -234,11 +238,11 @@ static void _tnl_import_array( struct gl_context *ctx,
    VB->AttribPtr[attrib]->start = (GLfloat *)ptr;
    VB->AttribPtr[attrib]->count = count;
    VB->AttribPtr[attrib]->stride = stride;
-   VB->AttribPtr[attrib]->size = input->Size;
+   VB->AttribPtr[attrib]->size = glattrib->Size;
 
    /* This should die, but so should the whole GLvector4f concept: 
     */
-   VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) | 
+   VB->AttribPtr[attrib]->flags = (((1<<glattrib->Size)-1) |
 				   VEC_NOT_WRITEABLE |
 				   (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE));
    
@@ -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 *glarray = &inputs[i];
+      const struct gl_vertex_buffer_binding *glbinding = glarray->BufferBinding;
+      const struct gl_array_attributes *glattrib = glarray->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(glbinding->BufferObj)) {
+	 if (!glbinding->BufferObj->Mappings[MAP_INTERNAL].Pointer) {
+	    bo[*nr_bo] = glbinding->BufferObj;
 	    (*nr_bo)++;
-	    ctx->Driver.MapBufferRange(ctx, 0, inputs[i]->BufferObj->Size,
+	    ctx->Driver.MapBufferRange(ctx, 0, glbinding->BufferObj->Size,
 				       GL_MAP_READ_BIT,
-				       inputs[i]->BufferObj,
+                                       glbinding->BufferObj,
                                        MAP_INTERNAL);
 	    
-	    assert(inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer);
+            assert(glbinding->BufferObj->Mappings[MAP_INTERNAL].Pointer);
 	 }
 	 
-	 ptr = ADD_POINTERS(inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer,
-			    inputs[i]->Ptr);
+         ptr = ADD_POINTERS(glbinding->BufferObj->Mappings[MAP_INTERNAL].Pointer,
+                            glbinding->Offset + glattrib->RelativeOffset);
       }
       else
-	 ptr = inputs[i]->Ptr;
+         ptr = glattrib->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, glbinding, glattrib, 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..532c628305 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 *glattrib,
            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(glattrib, 0, sizeof(*glattrib));
+
+   glattrib->Size = size;
+   glattrib->Type = GL_FLOAT;
+   glattrib->Format = GL_RGBA;
+   glattrib->Stride = 0;
+   glattrib->_ElementSize = size * sizeof(GLfloat);
+   glattrib->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 *glattrib = &vbo->curr_glattrib[attr];
 
-      init_array(ctx, array,
-                 check_size(ctx->Current.Attrib[i]),
-                 ctx->Current.Attrib[i]);
+      init_array(ctx, glattrib, 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 *glattrib = &vbo->curr_glattrib[attr];
 
-      init_array(ctx, array, 1, ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i]);
+      init_array(ctx, glattrib, 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 *glattrib = &vbo->curr_glattrib[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, glattrib, size, ctx->Light.Material.Attrib[i]);
    }
 }
 
@@ -237,6 +235,11 @@ _vbo_CreateContext(struct gl_context *ctx)
       return GL_FALSE;
    }
 
+   vbo->glbinding.Offset = 0;
+   vbo->glbinding.Stride = 0;
+   vbo->glbinding.InstanceDivisor = 0;
+   _mesa_reference_buffer_object(ctx, &vbo->glbinding.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->glbinding.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..98dfbeb583 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->curr_glattrib[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->glbinding;
    }
 
    inputs->current = current;
diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
index 317fc43d1c..6addd75037 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->curr_glattrib[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->curr_glattrib[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->curr_glattrib[i].Size = exec->vtx.attrsz[i] / dmul;
+         vbo->curr_glattrib[i]._ElementSize =
+            vbo->curr_glattrib[i].Size * sizeof(GLfloat) * dmul;
+         vbo->curr_glattrib[i].Type = exec->vtx.attrtype[i];
+         vbo->curr_glattrib[i].Integer =
             vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
-         vbo->currval[i].Doubles =
+         vbo->curr_glattrib[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->curr_glattrib[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->curr_glattrib[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->curr_glattrib[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..d0269ac0d2 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 glbinding;
+   struct gl_array_attributes curr_glattrib[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..fae8681fff 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->curr_glattrib[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..7c1b6ab95b 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 *glattrib)
 {
-   return array->Size * _mesa_sizeof_type(array->Type);
+   return glattrib->Size * _mesa_sizeof_type(glattrib->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 *glarray = &arrays[j];
+         const struct gl_vertex_buffer_binding *glbinding
+            = glarray->BufferBinding;
+         const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+         const GLubyte *ptr = _mesa_vertex_attrib_address(glattrib, glbinding);
+         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, glattrib->Size, glattrib->Type, glbinding->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 + glbinding->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 *glarray = &copy->array[i];
+      const struct gl_vertex_buffer_binding *glbinding = glarray->BufferBinding;
 
-      if (copy->array[i]->StrideB == 0) {
-         copy->dstarray_ptr[i] = copy->array[i];
+      if (glbinding->Stride == 0) {
+         _mesa_copy_vertex_array(&copy->dstarray[i], glarray);
       }
       else {
+         const struct gl_array_attributes *glattrib = glarray->VertexAttrib;
+         struct gl_buffer_object *vbo = glbinding->BufferObj;
+         const GLubyte *ptr = _mesa_vertex_attrib_address(glattrib, glbinding);
          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(glattrib);
+         copy->vertex_size += attr_size(glattrib);
 
          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