[Mesa-dev] [PATCH 1/4] gallium: decrease the size of pipe_vertex_buffer - 24 -> 16 bytes

Marek Olšák maraeo at gmail.com
Fri Apr 28 23:12:06 UTC 2017


From: Marek Olšák <marek.olsak at amd.com>

---
 src/gallium/auxiliary/cso_cache/cso_context.c      | 24 +++----
 src/gallium/auxiliary/draw/draw_context.c          |  5 +-
 src/gallium/auxiliary/draw/draw_llvm.c             | 14 ++--
 src/gallium/auxiliary/draw/draw_llvm.h             |  2 +-
 src/gallium/auxiliary/hud/hud_context.c            | 14 ++--
 src/gallium/auxiliary/util/u_blitter.c             | 17 ++---
 src/gallium/auxiliary/util/u_blitter.h             |  6 +-
 src/gallium/auxiliary/util/u_draw.c                |  8 +--
 src/gallium/auxiliary/util/u_draw_quad.c           |  5 +-
 src/gallium/auxiliary/util/u_dump_state.c          |  4 +-
 src/gallium/auxiliary/util/u_helpers.c             | 17 ++---
 src/gallium/auxiliary/util/u_inlines.h             | 19 +++++
 src/gallium/auxiliary/util/u_vbuf.c                | 80 ++++++++++------------
 src/gallium/auxiliary/vl/vl_bicubic_filter.c       |  6 +-
 src/gallium/auxiliary/vl/vl_compositor.c           |  7 +-
 src/gallium/auxiliary/vl/vl_deint_filter.c         |  6 +-
 src/gallium/auxiliary/vl/vl_matrix_filter.c        |  6 +-
 src/gallium/auxiliary/vl/vl_median_filter.c        |  6 +-
 src/gallium/auxiliary/vl/vl_mpeg12_decoder.c       |  4 +-
 src/gallium/auxiliary/vl/vl_vertex_buffers.c       | 24 +++----
 src/gallium/drivers/ddebug/dd_draw.c               | 15 ++--
 src/gallium/drivers/etnaviv/etnaviv_context.c      |  4 +-
 src/gallium/drivers/etnaviv/etnaviv_state.c        |  8 +--
 src/gallium/drivers/freedreno/a2xx/fd2_draw.c      |  4 +-
 src/gallium/drivers/freedreno/a3xx/fd3_emit.c      |  2 +-
 src/gallium/drivers/freedreno/a4xx/fd4_emit.c      |  2 +-
 src/gallium/drivers/freedreno/a5xx/fd5_emit.c      |  2 +-
 src/gallium/drivers/freedreno/freedreno_context.c  |  6 +-
 src/gallium/drivers/freedreno/freedreno_draw.c     |  4 +-
 src/gallium/drivers/freedreno/freedreno_resource.c |  2 +-
 src/gallium/drivers/freedreno/freedreno_state.c    |  4 +-
 src/gallium/drivers/i915/i915_context.c            |  5 +-
 src/gallium/drivers/llvmpipe/lp_context.c          |  2 +-
 src/gallium/drivers/llvmpipe/lp_draw_arrays.c      |  9 +--
 src/gallium/drivers/nouveau/nv30/nv30_context.c    |  2 +-
 src/gallium/drivers/nouveau/nv30/nv30_draw.c       |  7 +-
 src/gallium/drivers/nouveau/nv30/nv30_push.c       |  8 +--
 src/gallium/drivers/nouveau/nv30/nv30_resource.c   |  4 +-
 src/gallium/drivers/nouveau/nv30/nv30_vbo.c        | 18 ++---
 src/gallium/drivers/nouveau/nv50/nv50_context.c    |  8 +--
 src/gallium/drivers/nouveau/nv50/nv50_push.c       |  6 +-
 src/gallium/drivers/nouveau/nv50/nv50_state.c      |  6 +-
 src/gallium/drivers/nouveau/nv50/nv50_vbo.c        | 19 ++---
 src/gallium/drivers/nouveau/nvc0/nvc0_context.c    |  8 +--
 src/gallium/drivers/nouveau/nvc0/nvc0_state.c      |  6 +-
 src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c        | 16 ++---
 .../drivers/nouveau/nvc0/nvc0_vbo_translate.c      | 14 ++--
 src/gallium/drivers/r300/r300_context.c            |  4 +-
 src/gallium/drivers/r300/r300_emit.c               |  6 +-
 src/gallium/drivers/r300/r300_render.c             |  6 +-
 src/gallium/drivers/r300/r300_screen_buffer.c      |  2 +-
 src/gallium/drivers/r300/r300_state.c              |  8 +--
 src/gallium/drivers/r600/evergreen_compute.c       |  4 +-
 src/gallium/drivers/r600/evergreen_state.c         |  2 +-
 src/gallium/drivers/r600/r600_state.c              |  2 +-
 src/gallium/drivers/r600/r600_state_common.c       | 12 ++--
 src/gallium/drivers/radeonsi/si_descriptors.c      | 16 ++---
 src/gallium/drivers/radeonsi/si_state.c            | 12 ++--
 src/gallium/drivers/rbug/rbug_context.c            |  7 +-
 src/gallium/drivers/softpipe/sp_context.c          |  2 +-
 src/gallium/drivers/softpipe/sp_draw_arrays.c      |  9 +--
 src/gallium/drivers/svga/svga_draw.c               | 18 ++---
 src/gallium/drivers/svga/svga_pipe_vertex.c        |  2 +-
 src/gallium/drivers/svga/svga_state_vdecl.c        |  8 +--
 src/gallium/drivers/svga/svga_swtnl_backend.c      |  4 +-
 src/gallium/drivers/svga/svga_swtnl_draw.c         |  6 +-
 src/gallium/drivers/swr/swr_state.cpp              | 14 ++--
 src/gallium/drivers/trace/tr_dump_state.c          |  4 +-
 src/gallium/drivers/vc4/vc4_draw.c                 |  2 +-
 src/gallium/drivers/virgl/virgl_context.c          |  2 +-
 src/gallium/drivers/virgl/virgl_encode.c           |  2 +-
 src/gallium/include/pipe/p_state.h                 | 11 +--
 src/gallium/state_trackers/nine/device9.c          | 26 +++----
 src/gallium/state_trackers/nine/nine_csmt_helper.h | 13 +++-
 src/gallium/state_trackers/nine/nine_state.c       | 41 ++++++-----
 src/mesa/state_tracker/st_atom_array.c             | 20 +++---
 src/mesa/state_tracker/st_cb_bitmap.c              |  4 +-
 src/mesa/state_tracker/st_draw.c                   |  6 +-
 src/mesa/state_tracker/st_draw_feedback.c          | 20 +++---
 src/mesa/state_tracker/st_pbo.c                    |  8 +--
 80 files changed, 400 insertions(+), 368 deletions(-)

diff --git a/src/gallium/auxiliary/cso_cache/cso_context.c b/src/gallium/auxiliary/cso_cache/cso_context.c
index 3d3c44c..68f7b9e 100644
--- a/src/gallium/auxiliary/cso_cache/cso_context.c
+++ b/src/gallium/auxiliary/cso_cache/cso_context.c
@@ -401,22 +401,22 @@ void cso_destroy_context( struct cso_context *ctx )
    }
 
    for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
       pipe_sampler_view_reference(&ctx->fragment_views[i], NULL);
       pipe_sampler_view_reference(&ctx->fragment_views_saved[i], NULL);
    }
 
    util_unreference_framebuffer_state(&ctx->fb);
    util_unreference_framebuffer_state(&ctx->fb_saved);
 
-   pipe_resource_reference(&ctx->aux_vertex_buffer_current.buffer, NULL);
-   pipe_resource_reference(&ctx->aux_vertex_buffer_saved.buffer, NULL);
+   pipe_vertex_buffer_unreference(&ctx->aux_vertex_buffer_current);
+   pipe_vertex_buffer_unreference(&ctx->aux_vertex_buffer_saved);
 
    for (i = 0; i < PIPE_SHADER_TYPES; i++) {
       pipe_resource_reference(&ctx->aux_constbuf_current[i].buffer, NULL);
       pipe_resource_reference(&ctx->aux_constbuf_saved[i].buffer, NULL);
    }
 
    pipe_resource_reference(&ctx->fragment_image0_current.resource, NULL);
    pipe_resource_reference(&ctx->fragment_image0_saved.resource, NULL);
 
    for (i = 0; i < PIPE_MAX_SO_BUFFERS; i++) {
@@ -1143,64 +1143,56 @@ void cso_set_vertex_buffers(struct cso_context *ctx,
    }
 
    /* Save what's in the auxiliary slot, so that we can save and restore it
     * for meta ops. */
    if (start_slot <= ctx->aux_vertex_buffer_index &&
        start_slot+count > ctx->aux_vertex_buffer_index) {
       if (buffers) {
          const struct pipe_vertex_buffer *vb =
                buffers + (ctx->aux_vertex_buffer_index - start_slot);
 
-         pipe_resource_reference(&ctx->aux_vertex_buffer_current.buffer,
-                                 vb->buffer);
-         memcpy(&ctx->aux_vertex_buffer_current, vb,
-                sizeof(struct pipe_vertex_buffer));
-      }
-      else {
-         pipe_resource_reference(&ctx->aux_vertex_buffer_current.buffer,
-                                 NULL);
-         ctx->aux_vertex_buffer_current.user_buffer = NULL;
+         pipe_vertex_buffer_reference(&ctx->aux_vertex_buffer_current, vb);
+      } else {
+         pipe_vertex_buffer_unreference(&ctx->aux_vertex_buffer_current);
       }
    }
 
    ctx->pipe->set_vertex_buffers(ctx->pipe, start_slot, count, buffers);
 }
 
 static void
 cso_save_aux_vertex_buffer_slot(struct cso_context *ctx)
 {
    struct u_vbuf *vbuf = ctx->vbuf;
 
    if (vbuf) {
       u_vbuf_save_aux_vertex_buffer_slot(vbuf);
       return;
    }
 
-   pipe_resource_reference(&ctx->aux_vertex_buffer_saved.buffer,
-                           ctx->aux_vertex_buffer_current.buffer);
-   memcpy(&ctx->aux_vertex_buffer_saved, &ctx->aux_vertex_buffer_current,
-          sizeof(struct pipe_vertex_buffer));
+   pipe_vertex_buffer_reference(&ctx->aux_vertex_buffer_saved,
+                                &ctx->aux_vertex_buffer_current);
 }
 
 static void
 cso_restore_aux_vertex_buffer_slot(struct cso_context *ctx)
 {
    struct u_vbuf *vbuf = ctx->vbuf;
 
    if (vbuf) {
       u_vbuf_restore_aux_vertex_buffer_slot(vbuf);
       return;
    }
 
    cso_set_vertex_buffers(ctx, ctx->aux_vertex_buffer_index, 1,
                           &ctx->aux_vertex_buffer_saved);
-   pipe_resource_reference(&ctx->aux_vertex_buffer_saved.buffer, NULL);
+   pipe_vertex_buffer_unreference(&ctx->aux_vertex_buffer_saved);
 }
 
 unsigned cso_get_aux_vertex_buffer_slot(struct cso_context *ctx)
 {
    return ctx->aux_vertex_buffer_index;
 }
 
 
 
 enum pipe_error
diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c
index 8f1189a..0eee075 100644
--- a/src/gallium/auxiliary/draw/draw_context.c
+++ b/src/gallium/auxiliary/draw/draw_context.c
@@ -199,23 +199,22 @@ void draw_destroy( struct draw_context *draw )
    /* free any rasterizer CSOs that we may have created.
     */
    for (i = 0; i < 2; i++) {
       for (j = 0; j < 2; j++) {
          if (draw->rasterizer_no_cull[i][j]) {
             pipe->delete_rasterizer_state(pipe, draw->rasterizer_no_cull[i][j]);
          }
       }
    }
 
-   for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
-      pipe_resource_reference(&draw->pt.vertex_buffer[i].buffer, NULL);
-   }
+   for (i = 0; i < draw->pt.nr_vertex_buffers; i++)
+      pipe_vertex_buffer_unreference(&draw->pt.vertex_buffer[i]);
 
    /* Not so fast -- we're just borrowing this at the moment.
     * 
    if (draw->render)
       draw->render->destroy( draw->render );
    */
 
    draw_prim_assembler_destroy(draw->ia);
    draw_pipeline_destroy( draw );
    draw_pt_destroy( draw );
diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index bb08f66..2035720 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -345,33 +345,37 @@ create_gs_jit_input_type(struct gallivm_state *gallivm)
  * Create LLVM type for struct pipe_vertex_buffer
  */
 static LLVMTypeRef
 create_jit_vertex_buffer_type(struct gallivm_state *gallivm,
                               const char *struct_name)
 {
    LLVMTargetDataRef target = gallivm->target;
    LLVMTypeRef elem_types[4];
    LLVMTypeRef vb_type;
 
-   elem_types[0] =
-   elem_types[1] = LLVMInt32TypeInContext(gallivm->context);
-   elem_types[2] =
+   elem_types[0] = LLVMInt16TypeInContext(gallivm->context);
+   elem_types[1] = LLVMInt8TypeInContext(gallivm->context);
+   elem_types[2] = LLVMInt32TypeInContext(gallivm->context);
    elem_types[3] = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0);
 
    vb_type = LLVMStructTypeInContext(gallivm->context, elem_types,
                                      ARRAY_SIZE(elem_types), 0);
 
    (void) target; /* silence unused var warning for non-debug build */
    LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, stride,
                           target, vb_type, 0);
-   LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer_offset,
+   LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, is_user_buffer,
                           target, vb_type, 1);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer_offset,
+                          target, vb_type, 2);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer.resource,
+                          target, vb_type, 3);
 
    LP_CHECK_STRUCT_SIZE(struct pipe_vertex_buffer, target, vb_type);
 
    return vb_type;
 }
 
 
 /**
  * Create LLVM type for struct vertex_header;
  */
@@ -1692,20 +1696,22 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
       LLVMValueRef bsize = lp_build_const_int32(gallivm,
                                                 util_format_get_blocksize(velem->src_format));
       LLVMValueRef src_offset = lp_build_const_int32(gallivm,
                                                      velem->src_offset);
       struct lp_build_if_state if_ctx;
 
       if (velem->src_format != PIPE_FORMAT_NONE) {
          vbuffer_ptr = LLVMBuildGEP(builder, vbuffers_ptr, &vb_index, 1, "");
          vb_info = LLVMBuildGEP(builder, vb_ptr, &vb_index, 1, "");
          vb_stride[j] = draw_jit_vbuffer_stride(gallivm, vb_info);
+         vb_stride[j] = LLVMBuildZExt(gallivm->builder, vb_stride[j],
+                                      LLVMInt32TypeInContext(context), "");
          vb_buffer_offset = draw_jit_vbuffer_offset(gallivm, vb_info);
          map_ptr[j] = draw_jit_dvbuffer_map(gallivm, vbuffer_ptr);
          buffer_size = draw_jit_dvbuffer_size(gallivm, vbuffer_ptr);
 
          ofbit = NULL;
          /*
           * We'll set buffer_size_adj to zero if we have of, so it will
           * always overflow later automatically without having to keep ofbit.
           * Overflows (with normal wraparound) doing the actual offset
           * calculation should be ok, just not for the buffer size calc.
diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h
index 57c9e72..a968be0 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.h
+++ b/src/gallium/auxiliary/draw/draw_llvm.h
@@ -165,21 +165,21 @@ enum {
    lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_VERTEX_CLIP_POS, "clip_pos")
 
 #define draw_jit_header_data(_gallivm, _ptr)            \
    lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_VERTEX_DATA, "data")
 
 
 #define draw_jit_vbuffer_stride(_gallivm, _ptr)         \
    lp_build_struct_get(_gallivm, _ptr, 0, "stride")
 
 #define draw_jit_vbuffer_offset(_gallivm, _ptr)         \
-   lp_build_struct_get(_gallivm, _ptr, 1, "buffer_offset")
+   lp_build_struct_get(_gallivm, _ptr, 2, "buffer_offset")
 
 enum {
    DRAW_JIT_DVBUFFER_MAP = 0,
    DRAW_JIT_DVBUFFER_SIZE,
    DRAW_JIT_DVBUFFER_NUM_FIELDS  /* number of fields above */
 };
 
 #define draw_jit_dvbuffer_map(_gallivm, _ptr)         \
    lp_build_struct_get(_gallivm, _ptr, DRAW_JIT_DVBUFFER_MAP, "map")
 
diff --git a/src/gallium/auxiliary/hud/hud_context.c b/src/gallium/auxiliary/hud/hud_context.c
index f492c81..9dd2fbf 100644
--- a/src/gallium/auxiliary/hud/hud_context.c
+++ b/src/gallium/auxiliary/hud/hud_context.c
@@ -572,29 +572,29 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex)
    hud_prepare_vertices(hud, &hud->color_prims, 32 * 1024, 2 * sizeof(float));
 
    /* Allocate everything once and divide the storage into 3 portions
     * manually, because u_upload_alloc can unmap memory from previous calls.
     */
    u_upload_alloc(hud->pipe->stream_uploader, 0,
                   hud->bg.buffer_size +
                   hud->whitelines.buffer_size +
                   hud->text.buffer_size +
                   hud->color_prims.buffer_size,
-                  16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer,
+                  16, &hud->bg.vbuf.buffer_offset, &hud->bg.vbuf.buffer.resource,
                   (void**)&hud->bg.vertices);
    if (!hud->bg.vertices) {
       goto out;
    }
 
-   pipe_resource_reference(&hud->whitelines.vbuf.buffer, hud->bg.vbuf.buffer);
-   pipe_resource_reference(&hud->text.vbuf.buffer, hud->bg.vbuf.buffer);
-   pipe_resource_reference(&hud->color_prims.vbuf.buffer, hud->bg.vbuf.buffer);
+   pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
+   pipe_resource_reference(&hud->text.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
+   pipe_resource_reference(&hud->color_prims.vbuf.buffer.resource, hud->bg.vbuf.buffer.resource);
 
    hud->whitelines.vbuf.buffer_offset = hud->bg.vbuf.buffer_offset +
                                         hud->bg.buffer_size;
    hud->whitelines.vertices = hud->bg.vertices +
                               hud->bg.buffer_size / sizeof(float);
 
    hud->text.vbuf.buffer_offset = hud->whitelines.vbuf.buffer_offset +
                                   hud->whitelines.buffer_size;
    hud->text.vertices = hud->whitelines.vertices +
                         hud->whitelines.buffer_size / sizeof(float);
@@ -647,52 +647,52 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex)
       hud->constants.translate[0] = 0;
       hud->constants.translate[1] = 0;
       hud->constants.scale[0] = 1;
       hud->constants.scale[1] = 1;
 
       cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
       cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
                              &hud->bg.vbuf);
       cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->bg.num_vertices);
    }
-   pipe_resource_reference(&hud->bg.vbuf.buffer, NULL);
+   pipe_resource_reference(&hud->bg.vbuf.buffer.resource, NULL);
 
    /* draw accumulated vertices for white lines */
    cso_set_blend(cso, &hud->no_blend);
 
    hud->constants.color[0] = 1;
    hud->constants.color[1] = 1;
    hud->constants.color[2] = 1;
    hud->constants.color[3] = 1;
    hud->constants.translate[0] = 0;
    hud->constants.translate[1] = 0;
    hud->constants.scale[0] = 1;
    hud->constants.scale[1] = 1;
    cso_set_constant_buffer(cso, PIPE_SHADER_VERTEX, 0, &hud->constbuf);
 
    if (hud->whitelines.num_vertices) {
       cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
                              &hud->whitelines.vbuf);
       cso_set_fragment_shader_handle(hud->cso, hud->fs_color);
       cso_draw_arrays(cso, PIPE_PRIM_LINES, 0, hud->whitelines.num_vertices);
    }
-   pipe_resource_reference(&hud->whitelines.vbuf.buffer, NULL);
+   pipe_resource_reference(&hud->whitelines.vbuf.buffer.resource, NULL);
 
    /* draw accumulated vertices for text */
    cso_set_blend(cso, &hud->alpha_blend);
    if (hud->text.num_vertices) {
       cso_set_vertex_buffers(cso, cso_get_aux_vertex_buffer_slot(cso), 1,
                              &hud->text.vbuf);
       cso_set_fragment_shader_handle(hud->cso, hud->fs_text);
       cso_draw_arrays(cso, PIPE_PRIM_QUADS, 0, hud->text.num_vertices);
    }
-   pipe_resource_reference(&hud->text.vbuf.buffer, NULL);
+   pipe_resource_reference(&hud->text.vbuf.buffer.resource, NULL);
 
    /* draw the rest */
    cso_set_rasterizer(cso, &hud->rasterizer_aa_lines);
    LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
       if (pane)
          hud_pane_draw_colored_objects(hud, pane);
    }
 
 out:
    cso_restore_state(cso);
diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c
index 447d8d2..13fa965 100644
--- a/src/gallium/auxiliary/util/u_blitter.c
+++ b/src/gallium/auxiliary/util/u_blitter.c
@@ -532,21 +532,21 @@ static void blitter_check_saved_vertex_states(struct blitter_context_priv *ctx)
 
 void util_blitter_restore_vertex_states(struct blitter_context *blitter)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_context *pipe = ctx->base.pipe;
    unsigned i;
 
    /* Vertex buffer. */
    pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1,
                             &ctx->base.saved_vertex_buffer);
-   pipe_resource_reference(&ctx->base.saved_vertex_buffer.buffer, NULL);
+   pipe_vertex_buffer_unreference(&ctx->base.saved_vertex_buffer);
 
    /* Vertex elements. */
    pipe->bind_vertex_elements_state(pipe, ctx->base.saved_velem_state);
    ctx->base.saved_velem_state = INVALID_PTR;
 
    /* Vertex shader. */
    pipe->bind_vs_state(pipe, ctx->base.saved_vs);
    ctx->base.saved_vs = INVALID_PTR;
 
    /* Geometry shader. */
@@ -1202,29 +1202,29 @@ static void blitter_draw(struct blitter_context_priv *ctx,
                          unsigned num_instances)
 {
    struct pipe_context *pipe = ctx->base.pipe;
    struct pipe_vertex_buffer vb = {0};
 
    blitter_set_rectangle(ctx, x1, y1, x2, y2, depth);
 
    vb.stride = 8 * sizeof(float);
 
    u_upload_data(pipe->stream_uploader, 0, sizeof(ctx->vertices), 4, ctx->vertices,
-                 &vb.buffer_offset, &vb.buffer);
-   if (!vb.buffer)
+                 &vb.buffer_offset, &vb.buffer.resource);
+   if (!vb.buffer.resource)
       return;
    u_upload_unmap(pipe->stream_uploader);
 
    pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
    util_draw_arrays_instanced(pipe, PIPE_PRIM_TRIANGLE_FAN, 0, 4,
                               0, num_instances);
-   pipe_resource_reference(&vb.buffer, NULL);
+   pipe_resource_reference(&vb.buffer.resource, NULL);
 }
 
 void util_blitter_draw_rectangle(struct blitter_context *blitter,
                                  int x1, int y1, int x2, int y2, float depth,
                                  enum blitter_attrib_type type,
                                  const union pipe_color_union *attrib)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
 
    switch (type) {
@@ -2192,21 +2192,22 @@ void util_blitter_copy_buffer(struct blitter_context *blitter,
       struct pipe_box box;
       u_box_1d(srcx, size, &box);
       util_resource_copy_region(pipe, dst, 0, dstx, 0, 0, src, 0, &box);
       return;
    }
 
    util_blitter_set_running_flag(blitter);
    blitter_check_saved_vertex_states(ctx);
    blitter_disable_render_cond(ctx);
 
-   vb.buffer = src;
+   vb.is_user_buffer = false;
+   vb.buffer.resource = src;
    vb.buffer_offset = srcx;
    vb.stride = 4;
 
    pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state_readbuf[0]);
    bind_vs_pos_only(ctx, 1);
    if (ctx->has_geometry_shader)
       pipe->bind_gs_state(pipe, NULL);
    if (ctx->has_tessellation) {
       pipe->bind_tcs_state(pipe, NULL);
@@ -2252,22 +2253,22 @@ void util_blitter_clear_buffer(struct blitter_context *blitter,
       return;
    }
 
    /* Some alignment is required. */
    if (offset % 4 != 0 || size % 4 != 0) {
       assert(!"Bad alignment in util_blitter_clear_buffer()");
       return;
    }
 
    u_upload_data(pipe->stream_uploader, 0, num_channels*4, 4, clear_value,
-                 &vb.buffer_offset, &vb.buffer);
-   if (!vb.buffer)
+                 &vb.buffer_offset, &vb.buffer.resource);
+   if (!vb.buffer.resource)
       goto out;
 
    vb.stride = 0;
 
    util_blitter_set_running_flag(blitter);
    blitter_check_saved_vertex_states(ctx);
    blitter_disable_render_cond(ctx);
 
    pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
    pipe->bind_vertex_elements_state(pipe,
@@ -2284,21 +2285,21 @@ void util_blitter_clear_buffer(struct blitter_context *blitter,
    so_target = pipe->create_stream_output_target(pipe, dst, offset, size);
    pipe->set_stream_output_targets(pipe, 1, &so_target, offsets);
 
    util_draw_arrays(pipe, PIPE_PRIM_POINTS, 0, size / 4);
 
 out:
    util_blitter_restore_vertex_states(blitter);
    util_blitter_restore_render_cond(blitter);
    util_blitter_unset_running_flag(blitter);
    pipe_so_target_reference(&so_target, NULL);
-   pipe_resource_reference(&vb.buffer, NULL);
+   pipe_resource_reference(&vb.buffer.resource, NULL);
 }
 
 /* probably radeon specific */
 void util_blitter_custom_resolve_color(struct blitter_context *blitter,
 				       struct pipe_resource *dst,
 				       unsigned dst_level,
 				       unsigned dst_layer,
 				       struct pipe_resource *src,
 				       unsigned src_layer,
 				       unsigned sample_mask,
diff --git a/src/gallium/auxiliary/util/u_blitter.h b/src/gallium/auxiliary/util/u_blitter.h
index f47c3dd..fd4fe7a 100644
--- a/src/gallium/auxiliary/util/u_blitter.h
+++ b/src/gallium/auxiliary/util/u_blitter.h
@@ -496,24 +496,22 @@ util_blitter_save_fragment_constant_buffer_slot(
    pipe_resource_reference(&blitter->saved_fs_constant_buffer.buffer,
                            constant_buffers[blitter->cb_slot].buffer);
    memcpy(&blitter->saved_fs_constant_buffer, &constant_buffers[blitter->cb_slot],
           sizeof(struct pipe_constant_buffer));
 }
 
 static inline void
 util_blitter_save_vertex_buffer_slot(struct blitter_context *blitter,
                                      struct pipe_vertex_buffer *vertex_buffers)
 {
-   pipe_resource_reference(&blitter->saved_vertex_buffer.buffer,
-                           vertex_buffers[blitter->vb_slot].buffer);
-   memcpy(&blitter->saved_vertex_buffer, &vertex_buffers[blitter->vb_slot],
-          sizeof(struct pipe_vertex_buffer));
+   pipe_vertex_buffer_reference(&blitter->saved_vertex_buffer,
+                                &vertex_buffers[blitter->vb_slot]);
 }
 
 static inline void
 util_blitter_save_so_targets(struct blitter_context *blitter,
                              unsigned num_targets,
                              struct pipe_stream_output_target **targets)
 {
    unsigned i;
    assert(num_targets <= ARRAY_SIZE(blitter->saved_so_targets));
 
diff --git a/src/gallium/auxiliary/util/u_draw.c b/src/gallium/auxiliary/util/u_draw.c
index b9f8fcd..ca78648 100644
--- a/src/gallium/auxiliary/util/u_draw.c
+++ b/src/gallium/auxiliary/util/u_draw.c
@@ -55,27 +55,27 @@ util_draw_max_index(
    max_index = ~0U - 1;
    for (i = 0; i < nr_vertex_elements; i++) {
       const struct pipe_vertex_element *element =
          &vertex_elements[i];
       const struct pipe_vertex_buffer *buffer =
          &vertex_buffers[element->vertex_buffer_index];
       unsigned buffer_size;
       const struct util_format_description *format_desc;
       unsigned format_size;
 
-      if (!buffer->buffer) {
+      if (buffer->is_user_buffer || !buffer->buffer.resource) {
          continue;
       }
 
-      assert(buffer->buffer->height0 == 1);
-      assert(buffer->buffer->depth0 == 1);
-      buffer_size = buffer->buffer->width0;
+      assert(buffer->buffer.resource->height0 == 1);
+      assert(buffer->buffer.resource->depth0 == 1);
+      buffer_size = buffer->buffer.resource->width0;
 
       format_desc = util_format_description(element->src_format);
       assert(format_desc->block.width == 1);
       assert(format_desc->block.height == 1);
       assert(format_desc->block.bits % 8 == 0);
       format_size = format_desc->block.bits/8;
 
       if (buffer->buffer_offset >= buffer_size) {
          /* buffer is too small */
          return 0;
diff --git a/src/gallium/auxiliary/util/u_draw_quad.c b/src/gallium/auxiliary/util/u_draw_quad.c
index ce3fa41..fe9558e 100644
--- a/src/gallium/auxiliary/util/u_draw_quad.c
+++ b/src/gallium/auxiliary/util/u_draw_quad.c
@@ -47,21 +47,21 @@ util_draw_vertex_buffer(struct pipe_context *pipe,
                         uint prim_type,
                         uint num_verts,
                         uint num_attribs)
 {
    struct pipe_vertex_buffer vbuffer;
 
    assert(num_attribs <= PIPE_MAX_ATTRIBS);
 
    /* tell pipe about the vertex buffer */
    memset(&vbuffer, 0, sizeof(vbuffer));
-   vbuffer.buffer = vbuf;
+   vbuffer.buffer.resource = vbuf;
    vbuffer.stride = num_attribs * 4 * sizeof(float);  /* vertex size */
    vbuffer.buffer_offset = offset;
 
    /* note: vertex elements already set by caller */
 
    if (cso) {
       cso_set_vertex_buffers(cso, vbuf_slot, 1, &vbuffer);
       cso_draw_arrays(cso, prim_type, 0, num_verts);
    } else {
       pipe->set_vertex_buffers(pipe, vbuf_slot, 1, &vbuffer);
@@ -75,18 +75,19 @@ util_draw_vertex_buffer(struct pipe_context *pipe,
  * Limited to float[4] vertex attribs, tightly packed.
  */
 void
 util_draw_user_vertex_buffer(struct cso_context *cso, void *buffer,
                              uint prim_type, uint num_verts, uint num_attribs)
 {
    struct pipe_vertex_buffer vbuffer = {0};
 
    assert(num_attribs <= PIPE_MAX_ATTRIBS);
 
-   vbuffer.user_buffer = buffer;
+   vbuffer.is_user_buffer = true;
+   vbuffer.buffer.user = buffer;
    vbuffer.stride = num_attribs * 4 * sizeof(float);  /* vertex size */
 
    /* note: vertex elements already set by caller */
 
    cso_set_vertex_buffers(cso, 0, 1, &vbuffer);
    cso_draw_arrays(cso, prim_type, 0, num_verts);
 }
diff --git a/src/gallium/auxiliary/util/u_dump_state.c b/src/gallium/auxiliary/util/u_dump_state.c
index 105e5c4..0af81f7 100644
--- a/src/gallium/auxiliary/util/u_dump_state.c
+++ b/src/gallium/auxiliary/util/u_dump_state.c
@@ -854,23 +854,23 @@ void
 util_dump_vertex_buffer(FILE *stream, const struct pipe_vertex_buffer *state)
 {
    if (!state) {
       util_dump_null(stream);
       return;
    }
 
    util_dump_struct_begin(stream, "pipe_vertex_buffer");
 
    util_dump_member(stream, uint, state, stride);
+   util_dump_member(stream, bool, state, is_user_buffer);
    util_dump_member(stream, uint, state, buffer_offset);
-   util_dump_member(stream, ptr, state, buffer);
-   util_dump_member(stream, ptr, state, user_buffer);
+   util_dump_member(stream, ptr, state, buffer.resource);
 
    util_dump_struct_end(stream);
 }
 
 
 void
 util_dump_vertex_element(FILE *stream, const struct pipe_vertex_element *state)
 {
    if (!state) {
       util_dump_null(stream);
diff --git a/src/gallium/auxiliary/util/u_helpers.c b/src/gallium/auxiliary/util/u_helpers.c
index 5b46fa1..f91cb0c 100644
--- a/src/gallium/auxiliary/util/u_helpers.c
+++ b/src/gallium/auxiliary/util/u_helpers.c
@@ -44,57 +44,58 @@ void util_set_vertex_buffers_mask(struct pipe_vertex_buffer *dst,
                                   const struct pipe_vertex_buffer *src,
                                   unsigned start_slot, unsigned count)
 {
    unsigned i;
    uint32_t bitmask = 0;
 
    dst += start_slot;
 
    if (src) {
       for (i = 0; i < count; i++) {
-         if (src[i].buffer || src[i].user_buffer) {
+         if (src[i].buffer.resource)
             bitmask |= 1 << i;
-         }
-         pipe_resource_reference(&dst[i].buffer, src[i].buffer);
+
+         pipe_vertex_buffer_unreference(&dst[i]);
+
+         if (!src[i].is_user_buffer)
+            pipe_resource_reference(&dst[i].buffer.resource, src[i].buffer.resource);
       }
 
       /* Copy over the other members of pipe_vertex_buffer. */
       memcpy(dst, src, count * sizeof(struct pipe_vertex_buffer));
 
       *enabled_buffers &= ~(((1ull << count) - 1) << start_slot);
       *enabled_buffers |= bitmask << start_slot;
    }
    else {
       /* Unreference the buffers. */
-      for (i = 0; i < count; i++) {
-         pipe_resource_reference(&dst[i].buffer, NULL);
-         dst[i].user_buffer = NULL;
-      }
+      for (i = 0; i < count; i++)
+         pipe_vertex_buffer_unreference(&dst[i]);
 
       *enabled_buffers &= ~(((1ull << count) - 1) << start_slot);
    }
 }
 
 /**
  * Same as util_set_vertex_buffers_mask, but it only returns the number
  * of bound buffers.
  */
 void util_set_vertex_buffers_count(struct pipe_vertex_buffer *dst,
                                    unsigned *dst_count,
                                    const struct pipe_vertex_buffer *src,
                                    unsigned start_slot, unsigned count)
 {
    unsigned i;
    uint32_t enabled_buffers = 0;
 
    for (i = 0; i < *dst_count; i++) {
-      if (dst[i].buffer || dst[i].user_buffer)
+      if (dst[i].buffer.resource)
          enabled_buffers |= (1ull << i);
    }
 
    util_set_vertex_buffers_mask(dst, &enabled_buffers, src, start_slot,
                                 count);
 
    *dst_count = util_last_bit(enabled_buffers);
 }
 
 
diff --git a/src/gallium/auxiliary/util/u_inlines.h b/src/gallium/auxiliary/util/u_inlines.h
index 6bc5e66..6a3d504 100644
--- a/src/gallium/auxiliary/util/u_inlines.h
+++ b/src/gallium/auxiliary/util/u_inlines.h
@@ -181,20 +181,39 @@ pipe_so_target_reference(struct pipe_stream_output_target **ptr,
 {
    struct pipe_stream_output_target *old = *ptr;
 
    if (pipe_reference_described(&(*ptr)->reference, &target->reference,
                      (debug_reference_descriptor)debug_describe_so_target))
       old->context->stream_output_target_destroy(old->context, old);
    *ptr = target;
 }
 
 static inline void
+pipe_vertex_buffer_unreference(struct pipe_vertex_buffer *dst)
+{
+   if (dst->is_user_buffer)
+      dst->buffer.user = NULL;
+   else
+      pipe_resource_reference(&dst->buffer.resource, NULL);
+}
+
+static inline void
+pipe_vertex_buffer_reference(struct pipe_vertex_buffer *dst,
+                             const struct pipe_vertex_buffer *src)
+{
+   pipe_vertex_buffer_unreference(dst);
+   if (!src->is_user_buffer)
+      pipe_resource_reference(&dst->buffer.resource, src->buffer.resource);
+   memcpy(dst, src, sizeof(*src));
+}
+
+static inline void
 pipe_surface_reset(struct pipe_context *ctx, struct pipe_surface* ps,
                    struct pipe_resource *pt, unsigned level, unsigned layer)
 {
    pipe_resource_reference(&ps->texture, pt);
    ps->format = pt->format;
    ps->width = u_minify(pt->width0, level);
    ps->height = u_minify(pt->height0, level);
    ps->u.tex.level = level;
    ps->u.tex.first_layer = ps->u.tex.last_layer = layer;
    ps->context = ctx;
diff --git a/src/gallium/auxiliary/util/u_vbuf.c b/src/gallium/auxiliary/util/u_vbuf.c
index f040f4a..62b88ac 100644
--- a/src/gallium/auxiliary/util/u_vbuf.c
+++ b/src/gallium/auxiliary/util/u_vbuf.c
@@ -370,27 +370,26 @@ void u_vbuf_destroy(struct u_vbuf *mgr)
    struct pipe_screen *screen = mgr->pipe->screen;
    unsigned i;
    unsigned num_vb = screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
                                               PIPE_SHADER_CAP_MAX_INPUTS);
 
    mgr->pipe->set_index_buffer(mgr->pipe, NULL);
    pipe_resource_reference(&mgr->index_buffer.buffer, NULL);
 
    mgr->pipe->set_vertex_buffers(mgr->pipe, 0, num_vb, NULL);
 
-   for (i = 0; i < PIPE_MAX_ATTRIBS; i++) {
-      pipe_resource_reference(&mgr->vertex_buffer[i].buffer, NULL);
-   }
-   for (i = 0; i < PIPE_MAX_ATTRIBS; i++) {
-      pipe_resource_reference(&mgr->real_vertex_buffer[i].buffer, NULL);
-   }
-   pipe_resource_reference(&mgr->aux_vertex_buffer_saved.buffer, NULL);
+   for (i = 0; i < PIPE_MAX_ATTRIBS; i++)
+      pipe_vertex_buffer_unreference(&mgr->vertex_buffer[i]);
+   for (i = 0; i < PIPE_MAX_ATTRIBS; i++)
+      pipe_vertex_buffer_unreference(&mgr->real_vertex_buffer[i]);
+
+   pipe_vertex_buffer_unreference(&mgr->aux_vertex_buffer_saved);
 
    translate_cache_destroy(mgr->translate_cache);
    cso_cache_delete(mgr->cso_cache);
    FREE(mgr);
 }
 
 static enum pipe_error
 u_vbuf_translate_buffers(struct u_vbuf *mgr, struct translate_key *key,
                          unsigned vb_mask, unsigned out_vb,
                          int start_vertex, unsigned num_vertices,
@@ -410,31 +409,31 @@ u_vbuf_translate_buffers(struct u_vbuf *mgr, struct translate_key *key,
    mask = vb_mask;
    while (mask) {
       struct pipe_vertex_buffer *vb;
       unsigned offset;
       uint8_t *map;
       unsigned i = u_bit_scan(&mask);
 
       vb = &mgr->vertex_buffer[i];
       offset = vb->buffer_offset + vb->stride * start_vertex;
 
-      if (vb->user_buffer) {
-         map = (uint8_t*)vb->user_buffer + offset;
+      if (vb->is_user_buffer) {
+         map = (uint8_t*)vb->buffer.user + offset;
       } else {
          unsigned size = vb->stride ? num_vertices * vb->stride
                                     : sizeof(double)*4;
 
-         if (offset+size > vb->buffer->width0) {
-            size = vb->buffer->width0 - offset;
+         if (offset+size > vb->buffer.resource->width0) {
+            size = vb->buffer.resource->width0 - offset;
          }
 
-         map = pipe_buffer_map_range(mgr->pipe, vb->buffer, offset, size,
+         map = pipe_buffer_map_range(mgr->pipe, vb->buffer.resource, offset, size,
                                      PIPE_TRANSFER_READ, &vb_transfer[i]);
       }
 
       /* Subtract min_index so that indexing with the index buffer works. */
       if (unroll_indices) {
          map -= (ptrdiff_t)vb->stride * min_index;
       }
 
       tr->set_buffer(tr, i, map, vb->stride, ~0);
    }
@@ -503,22 +502,22 @@ u_vbuf_translate_buffers(struct u_vbuf *mgr, struct translate_key *key,
          pipe_buffer_unmap(mgr->pipe, vb_transfer[i]);
       }
    }
 
    /* Setup the new vertex buffer. */
    mgr->real_vertex_buffer[out_vb].buffer_offset = out_offset;
    mgr->real_vertex_buffer[out_vb].stride = key->output_stride;
 
    /* Move the buffer reference. */
    pipe_resource_reference(
-      &mgr->real_vertex_buffer[out_vb].buffer, NULL);
-   mgr->real_vertex_buffer[out_vb].buffer = out_buffer;
+      &mgr->real_vertex_buffer[out_vb].buffer.resource, NULL);
+   mgr->real_vertex_buffer[out_vb].buffer.resource = out_buffer;
 
    return PIPE_OK;
 }
 
 static boolean
 u_vbuf_translate_find_free_vb_slots(struct u_vbuf *mgr,
                                     unsigned mask[VB_NUM])
 {
    unsigned type;
    unsigned fallback_vbs[VB_NUM];
@@ -714,21 +713,21 @@ static void u_vbuf_translate_end(struct u_vbuf *mgr)
    unsigned i;
 
    /* Restore vertex elements. */
    mgr->pipe->bind_vertex_elements_state(mgr->pipe, mgr->ve->driver_cso);
    mgr->using_translate = FALSE;
 
    /* Unreference the now-unused VBOs. */
    for (i = 0; i < VB_NUM; i++) {
       unsigned vb = mgr->fallback_vbs[i];
       if (vb != ~0u) {
-         pipe_resource_reference(&mgr->real_vertex_buffer[vb].buffer, NULL);
+         pipe_resource_reference(&mgr->real_vertex_buffer[vb].buffer.resource, NULL);
          mgr->fallback_vbs[i] = ~0;
 
          /* This will cause the buffer to be unbound in the driver later. */
          mgr->dirty_real_vb_mask |= 1 << vb;
       }
    }
 }
 
 static void *
 u_vbuf_create_vertex_elements(struct u_vbuf *mgr, unsigned count,
@@ -823,68 +822,68 @@ void u_vbuf_set_vertex_buffers(struct u_vbuf *mgr,
    mgr->enabled_vb_mask &= mask;
 
    if (!bufs) {
       struct pipe_context *pipe = mgr->pipe;
       /* Unbind. */
       mgr->dirty_real_vb_mask &= mask;
 
       for (i = 0; i < count; i++) {
          unsigned dst_index = start_slot + i;
 
-         pipe_resource_reference(&mgr->vertex_buffer[dst_index].buffer, NULL);
-         pipe_resource_reference(&mgr->real_vertex_buffer[dst_index].buffer,
+         pipe_vertex_buffer_unreference(&mgr->vertex_buffer[dst_index]);
+         pipe_resource_reference(&mgr->real_vertex_buffer[dst_index].buffer.resource,
                                  NULL);
       }
 
       pipe->set_vertex_buffers(pipe, start_slot, count, NULL);
       return;
    }
 
    for (i = 0; i < count; i++) {
       unsigned dst_index = start_slot + i;
       const struct pipe_vertex_buffer *vb = &bufs[i];
       struct pipe_vertex_buffer *orig_vb = &mgr->vertex_buffer[dst_index];
       struct pipe_vertex_buffer *real_vb = &mgr->real_vertex_buffer[dst_index];
 
-      if (!vb->buffer && !vb->user_buffer) {
-         pipe_resource_reference(&orig_vb->buffer, NULL);
-         pipe_resource_reference(&real_vb->buffer, NULL);
-         real_vb->user_buffer = NULL;
+      if (!vb->buffer.resource) {
+         pipe_vertex_buffer_unreference(orig_vb);
+         pipe_vertex_buffer_unreference(real_vb);
          continue;
       }
 
-      pipe_resource_reference(&orig_vb->buffer, vb->buffer);
-      orig_vb->user_buffer = vb->user_buffer;
-
-      real_vb->buffer_offset = orig_vb->buffer_offset = vb->buffer_offset;
-      real_vb->stride = orig_vb->stride = vb->stride;
+      pipe_vertex_buffer_reference(orig_vb, vb);
 
       if (vb->stride) {
          nonzero_stride_vb_mask |= 1 << dst_index;
       }
       enabled_vb_mask |= 1 << dst_index;
 
       if ((!mgr->caps.buffer_offset_unaligned && vb->buffer_offset % 4 != 0) ||
           (!mgr->caps.buffer_stride_unaligned && vb->stride % 4 != 0)) {
          incompatible_vb_mask |= 1 << dst_index;
-         pipe_resource_reference(&real_vb->buffer, NULL);
+         real_vb->buffer_offset = vb->buffer_offset;
+         real_vb->stride = vb->stride;
+         pipe_vertex_buffer_unreference(real_vb);
+         real_vb->is_user_buffer = false;
          continue;
       }
 
-      if (!mgr->caps.user_vertex_buffers && vb->user_buffer) {
+      if (!mgr->caps.user_vertex_buffers && vb->is_user_buffer) {
          user_vb_mask |= 1 << dst_index;
-         pipe_resource_reference(&real_vb->buffer, NULL);
+         real_vb->buffer_offset = vb->buffer_offset;
+         real_vb->stride = vb->stride;
+         pipe_vertex_buffer_unreference(real_vb);
+         real_vb->is_user_buffer = false;
          continue;
       }
 
-      pipe_resource_reference(&real_vb->buffer, vb->buffer);
-      real_vb->user_buffer = vb->user_buffer;
+      pipe_vertex_buffer_reference(real_vb, vb);
    }
 
    mgr->user_vb_mask |= user_vb_mask;
    mgr->incompatible_vb_mask |= incompatible_vb_mask;
    mgr->nonzero_stride_vb_mask |= nonzero_stride_vb_mask;
    mgr->enabled_vb_mask |= enabled_vb_mask;
 
    /* All changed buffers are marked as dirty, even the NULL ones,
     * which will cause the NULL buffers to be unbound in the driver later. */
    mgr->dirty_real_vb_mask |= ~mask;
@@ -926,21 +925,21 @@ u_vbuf_upload_buffers(struct u_vbuf *mgr,
       struct pipe_vertex_buffer *vb = &mgr->vertex_buffer[index];
       unsigned instance_div, first, size, index_bit;
 
       /* Skip the buffers generated by translate. */
       if (index == mgr->fallback_vbs[VB_VERTEX] ||
           index == mgr->fallback_vbs[VB_INSTANCE] ||
           index == mgr->fallback_vbs[VB_CONST]) {
          continue;
       }
 
-      if (!vb->user_buffer) {
+      if (!vb->is_user_buffer) {
          continue;
       }
 
       instance_div = velem->instance_divisor;
       first = vb->buffer_offset + velem->src_offset;
 
       if (!vb->stride) {
          /* Constant attrib. */
          size = mgr->ve->src_format_size[i];
       } else if (instance_div) {
@@ -976,25 +975,25 @@ u_vbuf_upload_buffers(struct u_vbuf *mgr,
       struct pipe_vertex_buffer *real_vb;
       const uint8_t *ptr;
 
       i = u_bit_scan(&buffer_mask);
 
       start = start_offset[i];
       end = end_offset[i];
       assert(start < end);
 
       real_vb = &mgr->real_vertex_buffer[i];
-      ptr = mgr->vertex_buffer[i].user_buffer;
+      ptr = mgr->vertex_buffer[i].buffer.user;
 
-      u_upload_data(mgr->pipe->stream_uploader, start, end - start, 4, ptr + start,
-                    &real_vb->buffer_offset, &real_vb->buffer);
-      if (!real_vb->buffer)
+      u_upload_data(mgr->pipe->stream_uploader, start, end - start, 4,
+                    ptr + start, &real_vb->buffer_offset, &real_vb->buffer.resource);
+      if (!real_vb->buffer.resource)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
       real_vb->buffer_offset -= start;
    }
 
    return PIPE_OK;
 }
 
 static boolean u_vbuf_need_minmax_index(const struct u_vbuf *mgr)
 {
@@ -1313,23 +1312,20 @@ void u_vbuf_restore_vertex_elements(struct u_vbuf *mgr)
 
       mgr->ve = mgr->ve_saved;
       pipe->bind_vertex_elements_state(pipe,
                                        mgr->ve ? mgr->ve->driver_cso : NULL);
    }
    mgr->ve_saved = NULL;
 }
 
 void u_vbuf_save_aux_vertex_buffer_slot(struct u_vbuf *mgr)
 {
-   struct pipe_vertex_buffer *vb =
-         &mgr->vertex_buffer[mgr->aux_vertex_buffer_slot];
-
-   pipe_resource_reference(&mgr->aux_vertex_buffer_saved.buffer, vb->buffer);
-   memcpy(&mgr->aux_vertex_buffer_saved, vb, sizeof(*vb));
+   pipe_vertex_buffer_reference(&mgr->aux_vertex_buffer_saved,
+                           &mgr->vertex_buffer[mgr->aux_vertex_buffer_slot]);
 }
 
 void u_vbuf_restore_aux_vertex_buffer_slot(struct u_vbuf *mgr)
 {
    u_vbuf_set_vertex_buffers(mgr, mgr->aux_vertex_buffer_slot, 1,
                              &mgr->aux_vertex_buffer_saved);
-   pipe_resource_reference(&mgr->aux_vertex_buffer_saved.buffer, NULL);
+   pipe_vertex_buffer_unreference(&mgr->aux_vertex_buffer_saved);
 }
diff --git a/src/gallium/auxiliary/vl/vl_bicubic_filter.c b/src/gallium/auxiliary/vl/vl_bicubic_filter.c
index efd8a1c..a3dc6c8 100644
--- a/src/gallium/auxiliary/vl/vl_bicubic_filter.c
+++ b/src/gallium/auxiliary/vl/vl_bicubic_filter.c
@@ -288,21 +288,21 @@ vl_bicubic_filter_init(struct vl_bicubic_filter *filter, struct pipe_context *pi
    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    sampler.compare_func = PIPE_FUNC_ALWAYS;
    sampler.normalized_coords = 1;
    filter->sampler = pipe->create_sampler_state(pipe, &sampler);
    if (!filter->sampler)
       goto error_sampler;
 
    filter->quad = vl_vb_upload_quads(pipe);
-   if(!filter->quad.buffer)
+   if(!filter->quad.buffer.resource)
       goto error_quad;
 
    memset(&ve, 0, sizeof(ve));
    ve.src_offset = 0;
    ve.instance_divisor = 0;
    ve.vertex_buffer_index = 0;
    ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
    filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
    if (!filter->ves)
       goto error_ves;
@@ -342,21 +342,21 @@ vl_bicubic_filter_init(struct vl_bicubic_filter *filter, struct pipe_context *pi
 
    return true;
 
 error_fs:
    pipe->delete_vs_state(pipe, filter->vs);
 
 error_vs:
    pipe->delete_vertex_elements_state(pipe, filter->ves);
 
 error_ves:
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
 error_quad:
    pipe->delete_sampler_state(pipe, filter->sampler);
 
 error_sampler:
    pipe->delete_blend_state(pipe, filter->blend);
 
 error_blend:
    pipe->delete_rasterizer_state(pipe, filter->rs_state);
 
@@ -366,21 +366,21 @@ error_rs_state:
 
 void
 vl_bicubic_filter_cleanup(struct vl_bicubic_filter *filter)
 {
    assert(filter);
 
    filter->pipe->delete_sampler_state(filter->pipe, filter->sampler);
    filter->pipe->delete_blend_state(filter->pipe, filter->blend);
    filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
    filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
    filter->pipe->delete_vs_state(filter->pipe, filter->vs);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs);
 }
 
 void
 vl_bicubic_filter_render(struct vl_bicubic_filter *filter,
                         struct pipe_sampler_view *src,
                         struct pipe_surface *dst,
                         struct u_rect *dst_area,
diff --git a/src/gallium/auxiliary/vl/vl_compositor.c b/src/gallium/auxiliary/vl/vl_compositor.c
index 693d685..a79bf11 100644
--- a/src/gallium/auxiliary/vl/vl_compositor.c
+++ b/src/gallium/auxiliary/vl/vl_compositor.c
@@ -598,21 +598,22 @@ init_buffers(struct vl_compositor *c)
 {
    struct pipe_vertex_element vertex_elems[3];
 
    assert(c);
 
    /*
     * Create our vertex buffer and vertex buffer elements
     */
    c->vertex_buf.stride = sizeof(struct vertex2f) + sizeof(struct vertex4f) * 2;
    c->vertex_buf.buffer_offset = 0;
-   c->vertex_buf.buffer = NULL;
+   c->vertex_buf.buffer.resource = NULL;
+   c->vertex_buf.is_user_buffer = false;
 
    vertex_elems[0].src_offset = 0;
    vertex_elems[0].instance_divisor = 0;
    vertex_elems[0].vertex_buffer_index = 0;
    vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
    vertex_elems[1].src_offset = sizeof(struct vertex2f);
    vertex_elems[1].instance_divisor = 0;
    vertex_elems[1].vertex_buffer_index = 0;
    vertex_elems[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
    vertex_elems[2].src_offset = sizeof(struct vertex2f) + sizeof(struct vertex4f);
@@ -623,21 +624,21 @@ init_buffers(struct vl_compositor *c)
 
    return true;
 }
 
 static void
 cleanup_buffers(struct vl_compositor *c)
 {
    assert(c);
 
    c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
-   pipe_resource_reference(&c->vertex_buf.buffer, NULL);
+   pipe_resource_reference(&c->vertex_buf.buffer.resource, NULL);
 }
 
 static inline struct u_rect
 default_rect(struct vl_compositor_layer *layer)
 {
    struct pipe_resource *res = layer->sampler_views[0]->texture;
    struct u_rect rect = { 0, res->width0, 0, res->height0 * res->array_size };
    return rect;
 }
 
@@ -805,21 +806,21 @@ gen_vertex_data(struct vl_compositor *c, struct vl_compositor_state *s, struct u
 {
    struct vertex2f *vb;
    unsigned i;
 
    assert(c);
 
    /* Allocate new memory for vertices. */
    u_upload_alloc(c->pipe->stream_uploader, 0,
                   c->vertex_buf.stride * VL_COMPOSITOR_MAX_LAYERS * 4, /* size */
                   4, /* alignment */
-                  &c->vertex_buf.buffer_offset, &c->vertex_buf.buffer,
+                  &c->vertex_buf.buffer_offset, &c->vertex_buf.buffer.resource,
                   (void**)&vb);
 
    for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; i++) {
       if (s->used_layers & (1 << i)) {
          struct vl_compositor_layer *layer = &s->layers[i];
          gen_rect_verts(vb, layer);
          vb += 20;
 
          if (!layer->viewport_valid) {
             layer->viewport.scale[0] = c->fb_state.width;
diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.c b/src/gallium/auxiliary/vl/vl_deint_filter.c
index 2eec5cb..d2c48bd 100644
--- a/src/gallium/auxiliary/vl/vl_deint_filter.c
+++ b/src/gallium/auxiliary/vl/vl_deint_filter.c
@@ -301,21 +301,21 @@ vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe,
    sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
    sampler.normalized_coords = 1;
    filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler);
    filter->sampler[1] = filter->sampler[2] = filter->sampler[3] = filter->sampler[0];
    if (!filter->sampler[0])
       goto error_sampler;
 
    filter->quad = vl_vb_upload_quads(pipe);
-   if(!filter->quad.buffer)
+   if(!filter->quad.buffer.resource)
       goto error_quad;
 
    memset(&ve, 0, sizeof(ve));
    ve.src_offset = 0;
    ve.instance_divisor = 0;
    ve.vertex_buffer_index = 0;
    ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
    filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
    if (!filter->ves)
       goto error_ves;
@@ -354,21 +354,21 @@ error_fs_deint_top:
 error_fs_copy_bottom:
    pipe->delete_fs_state(pipe, filter->fs_copy_top);
 
 error_fs_copy_top:
    pipe->delete_vs_state(pipe, filter->vs);
 
 error_vs:
    pipe->delete_vertex_elements_state(pipe, filter->ves);
 
 error_ves:
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
 error_quad:
    pipe->delete_sampler_state(pipe, filter->sampler);
 
 error_sampler:
    pipe->delete_blend_state(pipe, filter->blend[2]);
 
 error_blendB:
    pipe->delete_blend_state(pipe, filter->blend[1]);
 
@@ -389,21 +389,21 @@ void
 vl_deint_filter_cleanup(struct vl_deint_filter *filter)
 {
    assert(filter);
 
    filter->pipe->delete_sampler_state(filter->pipe, filter->sampler[0]);
    filter->pipe->delete_blend_state(filter->pipe, filter->blend[0]);
    filter->pipe->delete_blend_state(filter->pipe, filter->blend[1]);
    filter->pipe->delete_blend_state(filter->pipe, filter->blend[2]);
    filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
    filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
    filter->pipe->delete_vs_state(filter->pipe, filter->vs);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_top);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_bottom);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_top);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_bottom);
 
    filter->video_buffer->destroy(filter->video_buffer);
 }
 
diff --git a/src/gallium/auxiliary/vl/vl_matrix_filter.c b/src/gallium/auxiliary/vl/vl_matrix_filter.c
index b498d1f..1dacc7c 100644
--- a/src/gallium/auxiliary/vl/vl_matrix_filter.c
+++ b/src/gallium/auxiliary/vl/vl_matrix_filter.c
@@ -177,21 +177,21 @@ vl_matrix_filter_init(struct vl_matrix_filter *filter, struct pipe_context *pipe
    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    sampler.compare_func = PIPE_FUNC_ALWAYS;
    sampler.normalized_coords = 1;
    filter->sampler = pipe->create_sampler_state(pipe, &sampler);
    if (!filter->sampler)
       goto error_sampler;
 
    filter->quad = vl_vb_upload_quads(pipe);
-   if(!filter->quad.buffer)
+   if(!filter->quad.buffer.resource)
       goto error_quad;
 
    memset(&ve, 0, sizeof(ve));
    ve.src_offset = 0;
    ve.instance_divisor = 0;
    ve.vertex_buffer_index = 0;
    ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
    filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
    if (!filter->ves)
       goto error_ves;
@@ -226,21 +226,21 @@ vl_matrix_filter_init(struct vl_matrix_filter *filter, struct pipe_context *pipe
 error_fs:
    pipe->delete_vs_state(pipe, filter->vs);
 
 error_vs:
    FREE(offsets);
 
 error_offsets:
    pipe->delete_vertex_elements_state(pipe, filter->ves);
 
 error_ves:
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
 error_quad:
    pipe->delete_sampler_state(pipe, filter->sampler);
 
 error_sampler:
    pipe->delete_blend_state(pipe, filter->blend);
 
 error_blend:
    pipe->delete_rasterizer_state(pipe, filter->rs_state);
 
@@ -250,21 +250,21 @@ error_rs_state:
 
 void
 vl_matrix_filter_cleanup(struct vl_matrix_filter *filter)
 {
    assert(filter);
 
    filter->pipe->delete_sampler_state(filter->pipe, filter->sampler);
    filter->pipe->delete_blend_state(filter->pipe, filter->blend);
    filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
    filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
    filter->pipe->delete_vs_state(filter->pipe, filter->vs);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs);
 }
 
 void
 vl_matrix_filter_render(struct vl_matrix_filter *filter,
                         struct pipe_sampler_view *src,
                         struct pipe_surface *dst)
 {
diff --git a/src/gallium/auxiliary/vl/vl_median_filter.c b/src/gallium/auxiliary/vl/vl_median_filter.c
index 0183b875..273afaf 100644
--- a/src/gallium/auxiliary/vl/vl_median_filter.c
+++ b/src/gallium/auxiliary/vl/vl_median_filter.c
@@ -288,21 +288,21 @@ vl_median_filter_init(struct vl_median_filter *filter, struct pipe_context *pipe
    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    sampler.compare_func = PIPE_FUNC_ALWAYS;
    sampler.normalized_coords = 1;
    filter->sampler = pipe->create_sampler_state(pipe, &sampler);
    if (!filter->sampler)
       goto error_sampler;
 
    filter->quad = vl_vb_upload_quads(pipe);
-   if(!filter->quad.buffer)
+   if(!filter->quad.buffer.resource)
       goto error_quad;
 
    memset(&ve, 0, sizeof(ve));
    ve.src_offset = 0;
    ve.instance_divisor = 0;
    ve.vertex_buffer_index = 0;
    ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
    filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
    if (!filter->ves)
       goto error_ves;
@@ -330,21 +330,21 @@ vl_median_filter_init(struct vl_median_filter *filter, struct pipe_context *pipe
 error_fs:
    pipe->delete_vs_state(pipe, filter->vs);
 
 error_vs:
    FREE(offsets);
 
 error_offsets:
    pipe->delete_vertex_elements_state(pipe, filter->ves);
 
 error_ves:
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
 error_quad:
    pipe->delete_sampler_state(pipe, filter->sampler);
 
 error_sampler:
    pipe->delete_blend_state(pipe, filter->blend);
 
 error_blend:
    pipe->delete_rasterizer_state(pipe, filter->rs_state);
 
@@ -354,21 +354,21 @@ error_rs_state:
 
 void
 vl_median_filter_cleanup(struct vl_median_filter *filter)
 {
    assert(filter);
 
    filter->pipe->delete_sampler_state(filter->pipe, filter->sampler);
    filter->pipe->delete_blend_state(filter->pipe, filter->blend);
    filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
    filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
-   pipe_resource_reference(&filter->quad.buffer, NULL);
+   pipe_resource_reference(&filter->quad.buffer.resource, NULL);
 
    filter->pipe->delete_vs_state(filter->pipe, filter->vs);
    filter->pipe->delete_fs_state(filter->pipe, filter->fs);
 }
 
 void
 vl_median_filter_render(struct vl_median_filter *filter,
                         struct pipe_sampler_view *src,
                         struct pipe_surface *dst)
 {
diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c b/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c
index db62b44..8a2dae3 100644
--- a/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c
+++ b/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c
@@ -502,22 +502,22 @@ vl_mpeg12_destroy(struct pipe_video_codec *decoder)
       vl_idct_cleanup(&dec->idct_c);
       dec->idct_source->destroy(dec->idct_source);
    }
 
    vl_zscan_cleanup(&dec->zscan_y);
    vl_zscan_cleanup(&dec->zscan_c);
 
    dec->context->delete_vertex_elements_state(dec->context, dec->ves_ycbcr);
    dec->context->delete_vertex_elements_state(dec->context, dec->ves_mv);
 
-   pipe_resource_reference(&dec->quads.buffer, NULL);
-   pipe_resource_reference(&dec->pos.buffer, NULL);
+   pipe_resource_reference(&dec->quads.buffer.resource, NULL);
+   pipe_resource_reference(&dec->pos.buffer.resource, NULL);
 
    pipe_sampler_view_reference(&dec->zscan_linear, NULL);
    pipe_sampler_view_reference(&dec->zscan_normal, NULL);
    pipe_sampler_view_reference(&dec->zscan_alternate, NULL);
 
    for (i = 0; i < 4; ++i)
       if (dec->dec_buffers[i])
          vl_mpeg12_destroy_buffer(dec->dec_buffers[i]);
 
    dec->context->destroy(dec->context);
diff --git a/src/gallium/auxiliary/vl/vl_vertex_buffers.c b/src/gallium/auxiliary/vl/vl_vertex_buffers.c
index 1721227..45a9bad 100644
--- a/src/gallium/auxiliary/vl/vl_vertex_buffers.c
+++ b/src/gallium/auxiliary/vl/vl_vertex_buffers.c
@@ -42,37 +42,37 @@ vl_vb_upload_quads(struct pipe_context *pipe)
    struct pipe_transfer *buf_transfer;
    struct vertex2f *v;
 
    unsigned i;
 
    assert(pipe);
 
    /* create buffer */
    quad.stride = sizeof(struct vertex2f);
    quad.buffer_offset = 0;
-   quad.buffer = pipe_buffer_create
+   quad.buffer.resource = pipe_buffer_create
    (
       pipe->screen,
       PIPE_BIND_VERTEX_BUFFER,
       PIPE_USAGE_DEFAULT,
       sizeof(struct vertex2f) * 4
    );
-   quad.user_buffer = NULL;
+   quad.is_user_buffer = false;
 
-   if(!quad.buffer)
+   if(!quad.buffer.resource)
       return quad;
 
    /* and fill it */
    v = pipe_buffer_map
    (
       pipe,
-      quad.buffer,
+      quad.buffer.resource,
       PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
       &buf_transfer
    );
 
    for (i = 0; i < 4; ++i, ++v) {
       v->x = block_quad[i].x;
       v->y = block_quad[i].y;
    }
 
    pipe_buffer_unmap(pipe, buf_transfer);
@@ -87,37 +87,37 @@ vl_vb_upload_pos(struct pipe_context *pipe, unsigned width, unsigned height)
    struct pipe_transfer *buf_transfer;
    struct vertex2s *v;
 
    unsigned x, y;
 
    assert(pipe);
 
    /* create buffer */
    pos.stride = sizeof(struct vertex2s);
    pos.buffer_offset = 0;
-   pos.buffer = pipe_buffer_create
+   pos.buffer.resource = pipe_buffer_create
    (
       pipe->screen,
       PIPE_BIND_VERTEX_BUFFER,
       PIPE_USAGE_DEFAULT,
       sizeof(struct vertex2s) * width * height
    );
-   pos.user_buffer = NULL;
+   pos.is_user_buffer = false;
 
-   if(!pos.buffer)
+   if(!pos.buffer.resource)
       return pos;
 
    /* and fill it */
    v = pipe_buffer_map
    (
       pipe,
-      pos.buffer,
+      pos.buffer.resource,
       PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
       &buf_transfer
    );
 
    for ( y = 0; y < height; ++y) {
       for ( x = 0; x < width; ++x, ++v) {
          v->x = x;
          v->y = y;
       }
    }
@@ -261,37 +261,37 @@ vl_vb_attributes_per_plock(struct vl_vertex_buffer *buffer)
 
 struct pipe_vertex_buffer
 vl_vb_get_ycbcr(struct vl_vertex_buffer *buffer, int component)
 {
    struct pipe_vertex_buffer buf;
 
    assert(buffer);
 
    buf.stride = sizeof(struct vl_ycbcr_block);
    buf.buffer_offset = 0;
-   buf.buffer = buffer->ycbcr[component].resource;
-   buf.user_buffer = NULL;
+   buf.buffer.resource = buffer->ycbcr[component].resource;
+   buf.is_user_buffer = false;
 
    return buf;
 }
 
 struct pipe_vertex_buffer
 vl_vb_get_mv(struct vl_vertex_buffer *buffer, int motionvector)
 {
    struct pipe_vertex_buffer buf;
 
    assert(buffer);
 
    buf.stride = sizeof(struct vl_motionvector);
    buf.buffer_offset = 0;
-   buf.buffer = buffer->mv[motionvector].resource;
-   buf.user_buffer = NULL;
+   buf.buffer.resource = buffer->mv[motionvector].resource;
+   buf.is_user_buffer = false;
 
    return buf;
 }
 
 void
 vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe)
 {
    unsigned i;
 
    assert(buffer && pipe);
diff --git a/src/gallium/drivers/ddebug/dd_draw.c b/src/gallium/drivers/ddebug/dd_draw.c
index 6e96c72..a70187d 100644
--- a/src/gallium/drivers/ddebug/dd_draw.c
+++ b/src/gallium/drivers/ddebug/dd_draw.c
@@ -222,25 +222,24 @@ dd_dump_draw_vbo(struct dd_draw_state *dstate, struct pipe_draw_info *info, FILE
       DUMP_M(resource, info, indirect);
    if (info->indirect_params)
       DUMP_M(resource, info, indirect_params);
    fprintf(f, "\n");
 
    /* TODO: dump active queries */
 
    dd_dump_render_condition(dstate, f);
 
    for (i = 0; i < PIPE_MAX_ATTRIBS; i++)
-      if (dstate->vertex_buffers[i].buffer ||
-          dstate->vertex_buffers[i].user_buffer) {
+      if (dstate->vertex_buffers[i].buffer.resource) {
          DUMP_I(vertex_buffer, &dstate->vertex_buffers[i], i);
-         if (dstate->vertex_buffers[i].buffer)
-            DUMP_M(resource, &dstate->vertex_buffers[i], buffer);
+         if (!dstate->vertex_buffers[i].is_user_buffer)
+            DUMP_M(resource, &dstate->vertex_buffers[i], buffer.resource);
       }
 
    if (dstate->velems) {
       print_named_value(f, "num vertex elements",
                         dstate->velems->state.velems.count);
       for (i = 0; i < dstate->velems->state.velems.count; i++) {
          fprintf(f, "  ");
          DUMP_I(vertex_element, &dstate->velems->state.velems.velems[i], i);
       }
    }
@@ -746,21 +745,21 @@ dd_init_copy_of_draw_state(struct dd_draw_state_copy *state)
 
 static void
 dd_unreference_copy_of_draw_state(struct dd_draw_state_copy *state)
 {
    struct dd_draw_state *dst = &state->base;
    unsigned i,j;
 
    util_set_index_buffer(&dst->index_buffer, NULL);
 
    for (i = 0; i < ARRAY_SIZE(dst->vertex_buffers); i++)
-      pipe_resource_reference(&dst->vertex_buffers[i].buffer, NULL);
+      pipe_vertex_buffer_unreference(&dst->vertex_buffers[i]);
    for (i = 0; i < ARRAY_SIZE(dst->so_targets); i++)
       pipe_so_target_reference(&dst->so_targets[i], NULL);
 
    for (i = 0; i < PIPE_SHADER_TYPES; i++) {
       if (dst->shaders[i])
          tgsi_free_tokens(dst->shaders[i]->state.shader.tokens);
 
       for (j = 0; j < PIPE_MAX_CONSTANT_BUFFERS; j++)
          pipe_resource_reference(&dst->constant_buffers[i][j].buffer, NULL);
       for (j = 0; j < PIPE_MAX_SAMPLERS; j++)
@@ -783,24 +782,22 @@ dd_copy_draw_state(struct dd_draw_state *dst, struct dd_draw_state *src)
       *dst->render_cond.query = *src->render_cond.query;
       dst->render_cond.condition = src->render_cond.condition;
       dst->render_cond.mode = src->render_cond.mode;
    } else {
       dst->render_cond.query = NULL;
    }
 
    util_set_index_buffer(&dst->index_buffer, &src->index_buffer);
 
    for (i = 0; i < ARRAY_SIZE(src->vertex_buffers); i++) {
-      pipe_resource_reference(&dst->vertex_buffers[i].buffer,
-                              src->vertex_buffers[i].buffer);
-      memcpy(&dst->vertex_buffers[i], &src->vertex_buffers[i],
-             sizeof(src->vertex_buffers[i]));
+      pipe_vertex_buffer_reference(&dst->vertex_buffers[i],
+                                   &src->vertex_buffers[i]);
    }
 
    dst->num_so_targets = src->num_so_targets;
    for (i = 0; i < ARRAY_SIZE(src->so_targets); i++)
       pipe_so_target_reference(&dst->so_targets[i], src->so_targets[i]);
    memcpy(dst->so_offsets, src->so_offsets, sizeof(src->so_offsets));
 
    for (i = 0; i < PIPE_SHADER_TYPES; i++) {
       if (!src->shaders[i]) {
          dst->shaders[i] = NULL;
diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c
index e426d4f..2e5e7f6 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_context.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_context.c
@@ -227,22 +227,22 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
       surf = pfb->cbufs[i]->texture;
       resource_written(ctx, surf);
    }
 
    /* Mark constant buffers as being read */
    resource_read(ctx, ctx->constant_buffer[PIPE_SHADER_VERTEX].buffer);
    resource_read(ctx, ctx->constant_buffer[PIPE_SHADER_FRAGMENT].buffer);
 
    /* Mark VBOs as being read */
    for (i = 0; i < ctx->vertex_buffer.count; i++) {
-      assert(!ctx->vertex_buffer.vb[i].user_buffer);
-      resource_read(ctx, ctx->vertex_buffer.vb[i].buffer);
+      assert(!ctx->vertex_buffer.vb[i].is_user_buffer);
+      resource_read(ctx, ctx->vertex_buffer.vb[i].buffer.resource);
    }
 
    /* Mark index buffer as being read */
    resource_read(ctx, ctx->index_buffer.ib.buffer);
 
    /* Mark textures as being read */
    for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
       if (ctx->sampler_view[i])
          resource_read(ctx, ctx->sampler_view[i]->texture);
 
diff --git a/src/gallium/drivers/etnaviv/etnaviv_state.c b/src/gallium/drivers/etnaviv/etnaviv_state.c
index d96b445..dcc587d 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_state.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_state.c
@@ -421,25 +421,25 @@ etna_set_vertex_buffers(struct pipe_context *pctx, unsigned start_slot,
    struct etna_context *ctx = etna_context(pctx);
    struct etna_vertexbuf_state *so = &ctx->vertex_buffer;
 
    util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot, num_buffers);
    so->count = util_last_bit(so->enabled_mask);
 
    for (unsigned idx = start_slot; idx < start_slot + num_buffers; ++idx) {
       struct compiled_set_vertex_buffer *cs = &so->cvb[idx];
       struct pipe_vertex_buffer *vbi = &so->vb[idx];
 
-      assert(!vbi->user_buffer); /* XXX support user_buffer using
-                                    etna_usermem_map */
+      assert(!vbi->is_user_buffer); /* XXX support user_buffer using
+                                       etna_usermem_map */
 
-      if (vbi->buffer) { /* GPU buffer */
-         cs->FE_VERTEX_STREAM_BASE_ADDR.bo = etna_resource(vbi->buffer)->bo;
+      if (vbi->buffer.resource) { /* GPU buffer */
+         cs->FE_VERTEX_STREAM_BASE_ADDR.bo = etna_resource(vbi->buffer.resource)->bo;
          cs->FE_VERTEX_STREAM_BASE_ADDR.offset = vbi->buffer_offset;
          cs->FE_VERTEX_STREAM_BASE_ADDR.flags = ETNA_RELOC_READ;
          cs->FE_VERTEX_STREAM_CONTROL =
             FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(vbi->stride);
       } else {
          cs->FE_VERTEX_STREAM_BASE_ADDR.bo = NULL;
          cs->FE_VERTEX_STREAM_CONTROL = 0;
       }
    }
 
diff --git a/src/gallium/drivers/freedreno/a2xx/fd2_draw.c b/src/gallium/drivers/freedreno/a2xx/fd2_draw.c
index f360ec2..eeae10b 100644
--- a/src/gallium/drivers/freedreno/a2xx/fd2_draw.c
+++ b/src/gallium/drivers/freedreno/a2xx/fd2_draw.c
@@ -62,22 +62,22 @@ emit_vertexbufs(struct fd_context *ctx)
 	unsigned i;
 
 	if (!vtx->num_elements)
 		return;
 
 	for (i = 0; i < vtx->num_elements; i++) {
 		struct pipe_vertex_element *elem = &vtx->pipe[i];
 		struct pipe_vertex_buffer *vb =
 				&vertexbuf->vb[elem->vertex_buffer_index];
 		bufs[i].offset = vb->buffer_offset;
-		bufs[i].size = fd_bo_size(fd_resource(vb->buffer)->bo);
-		bufs[i].prsc = vb->buffer;
+		bufs[i].size = fd_bo_size(fd_resource(vb->buffer.resource)->bo);
+		bufs[i].prsc = vb->buffer.resource;
 	}
 
 	// NOTE I believe the 0x78 (or 0x9c in solid_vp) relates to the
 	// CONST(20,0) (or CONST(26,0) in soliv_vp)
 
 	fd2_emit_vertex_bufs(ctx->batch->draw, 0x78, bufs, vtx->num_elements);
 }
 
 static bool
 fd2_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info)
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_emit.c b/src/gallium/drivers/freedreno/a3xx/fd3_emit.c
index ca97a08..3b61cac 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_emit.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_emit.c
@@ -394,21 +394,21 @@ fd3_emit_vertex_bufs(struct fd_ringbuffer *ring, struct fd3_emit *emit)
 			last = i;
 		}
 	}
 
 	for (i = 0, j = 0; i <= last; i++) {
 		assert(!vp->inputs[i].sysval);
 		if (vp->inputs[i].compmask) {
 			struct pipe_vertex_element *elem = &vtx->vtx->pipe[i];
 			const struct pipe_vertex_buffer *vb =
 					&vtx->vertexbuf.vb[elem->vertex_buffer_index];
-			struct fd_resource *rsc = fd_resource(vb->buffer);
+			struct fd_resource *rsc = fd_resource(vb->buffer.resource);
 			enum pipe_format pfmt = elem->src_format;
 			enum a3xx_vtx_fmt fmt = fd3_pipe2vtx(pfmt);
 			bool switchnext = (i != last) ||
 					(vertex_regid != regid(63, 0)) ||
 					(instance_regid != regid(63, 0)) ||
 					(vtxcnt_regid != regid(63, 0));
 			bool isint = util_format_is_pure_integer(pfmt);
 			uint32_t fs = util_format_get_blocksize(pfmt);
 
 			debug_assert(fmt != ~0);
diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
index f0a1fde..ba024bd 100644
--- a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
+++ b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
@@ -396,21 +396,21 @@ fd4_emit_vertex_bufs(struct fd_ringbuffer *ring, struct fd4_emit *emit)
 			last = i;
 		}
 	}
 
 	for (i = 0, j = 0; i <= last; i++) {
 		assert(!vp->inputs[i].sysval);
 		if (vp->inputs[i].compmask) {
 			struct pipe_vertex_element *elem = &vtx->vtx->pipe[i];
 			const struct pipe_vertex_buffer *vb =
 					&vtx->vertexbuf.vb[elem->vertex_buffer_index];
-			struct fd_resource *rsc = fd_resource(vb->buffer);
+			struct fd_resource *rsc = fd_resource(vb->buffer.resource);
 			enum pipe_format pfmt = elem->src_format;
 			enum a4xx_vtx_fmt fmt = fd4_pipe2vtx(pfmt);
 			bool switchnext = (i != last) ||
 					(vertex_regid != regid(63, 0)) ||
 					(instance_regid != regid(63, 0)) ||
 					(vtxcnt_regid != regid(63, 0));
 			bool isint = util_format_is_pure_integer(pfmt);
 			uint32_t fs = util_format_get_blocksize(pfmt);
 			uint32_t off = vb->buffer_offset + elem->src_offset;
 			uint32_t size = fd_bo_size(rsc->bo) - off;
diff --git a/src/gallium/drivers/freedreno/a5xx/fd5_emit.c b/src/gallium/drivers/freedreno/a5xx/fd5_emit.c
index 5b25257..db8e748 100644
--- a/src/gallium/drivers/freedreno/a5xx/fd5_emit.c
+++ b/src/gallium/drivers/freedreno/a5xx/fd5_emit.c
@@ -352,21 +352,21 @@ fd5_emit_vertex_bufs(struct fd_ringbuffer *ring, struct fd5_emit *emit)
 	const struct fd_vertex_state *vtx = emit->vtx;
 	const struct ir3_shader_variant *vp = fd5_emit_get_vp(emit);
 
 	for (i = 0, j = 0; i <= vp->inputs_count; i++) {
 		if (vp->inputs[i].sysval)
 			continue;
 		if (vp->inputs[i].compmask) {
 			struct pipe_vertex_element *elem = &vtx->vtx->pipe[i];
 			const struct pipe_vertex_buffer *vb =
 					&vtx->vertexbuf.vb[elem->vertex_buffer_index];
-			struct fd_resource *rsc = fd_resource(vb->buffer);
+			struct fd_resource *rsc = fd_resource(vb->buffer.resource);
 			enum pipe_format pfmt = elem->src_format;
 			enum a5xx_vtx_fmt fmt = fd5_pipe2vtx(pfmt);
 			bool isint = util_format_is_pure_integer(pfmt);
 			uint32_t off = vb->buffer_offset + elem->src_offset;
 			uint32_t size = fd_bo_size(rsc->bo) - off;
 			debug_assert(fmt != ~0);
 
 			OUT_PKT4(ring, REG_A5XX_VFD_FETCH(j), 4);
 			OUT_RELOC(ring, rsc->bo, off, 0, 0);
 			OUT_RING(ring, size);           /* VFD_FETCH[j].SIZE */
diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c
index d9d334e..8a86f0b 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.c
+++ b/src/gallium/drivers/freedreno/freedreno_context.c
@@ -203,38 +203,38 @@ fd_context_setup_common_vbos(struct fd_context *ctx)
 
 	/* setup solid_vbuf_state: */
 	ctx->solid_vbuf_state.vtx = pctx->create_vertex_elements_state(
 			pctx, 1, (struct pipe_vertex_element[]){{
 				.vertex_buffer_index = 0,
 				.src_offset = 0,
 				.src_format = PIPE_FORMAT_R32G32B32_FLOAT,
 			}});
 	ctx->solid_vbuf_state.vertexbuf.count = 1;
 	ctx->solid_vbuf_state.vertexbuf.vb[0].stride = 12;
-	ctx->solid_vbuf_state.vertexbuf.vb[0].buffer = ctx->solid_vbuf;
+	ctx->solid_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->solid_vbuf;
 
 	/* setup blit_vbuf_state: */
 	ctx->blit_vbuf_state.vtx = pctx->create_vertex_elements_state(
 			pctx, 2, (struct pipe_vertex_element[]){{
 				.vertex_buffer_index = 0,
 				.src_offset = 0,
 				.src_format = PIPE_FORMAT_R32G32_FLOAT,
 			}, {
 				.vertex_buffer_index = 1,
 				.src_offset = 0,
 				.src_format = PIPE_FORMAT_R32G32B32_FLOAT,
 			}});
 	ctx->blit_vbuf_state.vertexbuf.count = 2;
 	ctx->blit_vbuf_state.vertexbuf.vb[0].stride = 8;
-	ctx->blit_vbuf_state.vertexbuf.vb[0].buffer = ctx->blit_texcoord_vbuf;
+	ctx->blit_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->blit_texcoord_vbuf;
 	ctx->blit_vbuf_state.vertexbuf.vb[1].stride = 12;
-	ctx->blit_vbuf_state.vertexbuf.vb[1].buffer = ctx->solid_vbuf;
+	ctx->blit_vbuf_state.vertexbuf.vb[1].buffer.resource = ctx->solid_vbuf;
 }
 
 void
 fd_context_cleanup_common_vbos(struct fd_context *ctx)
 {
 	struct pipe_context *pctx = &ctx->base;
 
 	pctx->delete_vertex_elements_state(pctx, ctx->solid_vbuf_state.vtx);
 	pctx->delete_vertex_elements_state(pctx, ctx->blit_vbuf_state.vtx);
 
diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c
index d5b9a7b..61e0bfb 100644
--- a/src/gallium/drivers/freedreno/freedreno_draw.c
+++ b/src/gallium/drivers/freedreno/freedreno_draw.c
@@ -151,22 +151,22 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 			batch->gmem_reason |= FD_GMEM_BLEND_ENABLED;
 	}
 
 	foreach_bit(i, ctx->constbuf[PIPE_SHADER_VERTEX].enabled_mask)
 		resource_read(batch, ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer);
 	foreach_bit(i, ctx->constbuf[PIPE_SHADER_FRAGMENT].enabled_mask)
 		resource_read(batch, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer);
 
 	/* Mark VBOs as being read */
 	foreach_bit(i, ctx->vtx.vertexbuf.enabled_mask) {
-		assert(!ctx->vtx.vertexbuf.vb[i].user_buffer);
-		resource_read(batch, ctx->vtx.vertexbuf.vb[i].buffer);
+		assert(!ctx->vtx.vertexbuf.vb[i].is_user_buffer);
+		resource_read(batch, ctx->vtx.vertexbuf.vb[i].buffer.resource);
 	}
 
 	/* Mark index buffer as being read */
 	resource_read(batch, ctx->indexbuf.buffer);
 
 	/* Mark textures as being read */
 	foreach_bit(i, ctx->tex[PIPE_SHADER_VERTEX].valid_textures)
 		resource_read(batch, ctx->tex[PIPE_SHADER_VERTEX].textures[i]->texture);
 	foreach_bit(i, ctx->tex[PIPE_SHADER_FRAGMENT].valid_textures)
 		resource_read(batch, ctx->tex[PIPE_SHADER_FRAGMENT].textures[i]->texture);
diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c
index e47ac32..eeeae07 100644
--- a/src/gallium/drivers/freedreno/freedreno_resource.c
+++ b/src/gallium/drivers/freedreno/freedreno_resource.c
@@ -51,21 +51,21 @@
 static void
 fd_invalidate_resource(struct fd_context *ctx, struct pipe_resource *prsc)
 {
 	/* Go through the entire state and see if the resource is bound
 	 * anywhere. If it is, mark the relevant state as dirty. This is called on
 	 * realloc_bo.
 	 */
 
 	/* VBOs */
 	for (unsigned i = 0; i < ctx->vtx.vertexbuf.count && !(ctx->dirty & FD_DIRTY_VTXBUF); i++) {
-		if (ctx->vtx.vertexbuf.vb[i].buffer == prsc)
+		if (ctx->vtx.vertexbuf.vb[i].buffer.resource == prsc)
 			ctx->dirty |= FD_DIRTY_VTXBUF;
 	}
 
 	/* Index buffer */
 	if (ctx->indexbuf.buffer == prsc)
 		ctx->dirty |= FD_DIRTY_INDEXBUF;
 
 	/* per-shader-stage resources: */
 	for (unsigned stage = 0; stage < PIPE_SHADER_TYPES; stage++) {
 		/* Constbufs.. note that constbuf[0] is normal uniforms emitted in
diff --git a/src/gallium/drivers/freedreno/freedreno_state.c b/src/gallium/drivers/freedreno/freedreno_state.c
index 8f46633..18f012d 100644
--- a/src/gallium/drivers/freedreno/freedreno_state.c
+++ b/src/gallium/drivers/freedreno/freedreno_state.c
@@ -204,22 +204,22 @@ fd_set_vertex_buffers(struct pipe_context *pctx,
 	struct fd_context *ctx = fd_context(pctx);
 	struct fd_vertexbuf_stateobj *so = &ctx->vtx.vertexbuf;
 	int i;
 
 	/* on a2xx, pitch is encoded in the vtx fetch instruction, so
 	 * we need to mark VTXSTATE as dirty as well to trigger patching
 	 * and re-emitting the vtx shader:
 	 */
 	if (ctx->screen->gpu_id < 300) {
 		for (i = 0; i < count; i++) {
-			bool new_enabled = vb && (vb[i].buffer || vb[i].user_buffer);
-			bool old_enabled = so->vb[i].buffer || so->vb[i].user_buffer;
+			bool new_enabled = vb && vb[i].buffer.resource;
+			bool old_enabled = so->vb[i].buffer.resource != NULL;
 			uint32_t new_stride = vb ? vb[i].stride : 0;
 			uint32_t old_stride = so->vb[i].stride;
 			if ((new_enabled != old_enabled) || (new_stride != old_stride)) {
 				ctx->dirty |= FD_DIRTY_VTXSTATE;
 				break;
 			}
 		}
 	}
 
 	util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot, count);
diff --git a/src/gallium/drivers/i915/i915_context.c b/src/gallium/drivers/i915/i915_context.c
index c22e405..d229700 100644
--- a/src/gallium/drivers/i915/i915_context.c
+++ b/src/gallium/drivers/i915/i915_context.c
@@ -66,23 +66,24 @@ i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
     */
    i915->dirty &= ~I915_NEW_VS_CONSTANTS;
 
    if (i915->dirty)
       i915_update_derived(i915);
 
    /*
     * Map vertex buffers
     */
    for (i = 0; i < i915->nr_vertex_buffers; i++) {
-      const void *buf = i915->vertex_buffers[i].user_buffer;
+      const void *buf = i915->vertex_buffers[i].is_user_buffer ?
+                           i915->vertex_buffers[i].buffer.user : NULL;
       if (!buf)
-            buf = i915_buffer(i915->vertex_buffers[i].buffer)->data;
+            buf = i915_buffer(i915->vertex_buffers[i].buffer.resource)->data;
       draw_set_mapped_vertex_buffer(draw, i, buf, ~0);
    }
 
    /*
     * Map index buffer, if present
     */
    if (info->indexed) {
       mapped_indices = i915->index_buffer.user_buffer;
       if (!mapped_indices)
          mapped_indices = i915_buffer(i915->index_buffer.buffer)->data;
diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
index 9a1a7b9..c18e72c 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.c
+++ b/src/gallium/drivers/llvmpipe/lp_context.c
@@ -89,21 +89,21 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
       pipe_sampler_view_reference(&llvmpipe->sampler_views[PIPE_SHADER_GEOMETRY][i], NULL);
    }
 
    for (i = 0; i < ARRAY_SIZE(llvmpipe->constants); i++) {
       for (j = 0; j < ARRAY_SIZE(llvmpipe->constants[i]); j++) {
          pipe_resource_reference(&llvmpipe->constants[i][j].buffer, NULL);
       }
    }
 
    for (i = 0; i < llvmpipe->num_vertex_buffers; i++) {
-      pipe_resource_reference(&llvmpipe->vertex_buffer[i].buffer, NULL);
+      pipe_vertex_buffer_unreference(&llvmpipe->vertex_buffer[i]);
    }
 
    lp_delete_setup_variants(llvmpipe);
 
 #ifndef USE_GLOBAL_LLVM_CONTEXT
    LLVMContextDispose(llvmpipe->context);
 #endif
    llvmpipe->context = NULL;
 
    align_free( llvmpipe );
diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
index 22ef5fc..9a9c2f7 100644
--- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
+++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
@@ -66,28 +66,29 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
       return;
    }
 
    if (lp->dirty)
       llvmpipe_update_derived( lp );
 
    /*
     * Map vertex buffers
     */
    for (i = 0; i < lp->num_vertex_buffers; i++) {
-      const void *buf = lp->vertex_buffer[i].user_buffer;
+      const void *buf = lp->vertex_buffer[i].is_user_buffer ?
+                           lp->vertex_buffer[i].buffer.user : NULL;
       size_t size = ~0;
       if (!buf) {
-         if (!lp->vertex_buffer[i].buffer) {
+         if (!lp->vertex_buffer[i].buffer.resource) {
             continue;
          }
-         buf = llvmpipe_resource_data(lp->vertex_buffer[i].buffer);
-         size = lp->vertex_buffer[i].buffer->width0;
+         buf = llvmpipe_resource_data(lp->vertex_buffer[i].buffer.resource);
+         size = lp->vertex_buffer[i].buffer.resource->width0;
       }
       draw_set_mapped_vertex_buffer(draw, i, buf, size);
    }
 
    /* Map index buffer, if present */
    if (info->indexed) {
       unsigned available_space = ~0;
       mapped_indices = lp->index_buffer.user_buffer;
       if (!mapped_indices) {
          mapped_indices = llvmpipe_resource_data(lp->index_buffer.buffer);
diff --git a/src/gallium/drivers/nouveau/nv30/nv30_context.c b/src/gallium/drivers/nouveau/nv30/nv30_context.c
index 4c16e0c..cec3cd0 100644
--- a/src/gallium/drivers/nouveau/nv30/nv30_context.c
+++ b/src/gallium/drivers/nouveau/nv30/nv30_context.c
@@ -108,21 +108,21 @@ nv30_invalidate_resource_storage(struct nouveau_context *nv,
           nv30->framebuffer.zsbuf->texture == res) {
             nv30->dirty |= NV30_NEW_FRAMEBUFFER;
             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB);
             if (!--ref)
                return ref;
       }
    }
 
    if (res->bind & PIPE_BIND_VERTEX_BUFFER) {
       for (i = 0; i < nv30->num_vtxbufs; ++i) {
-         if (nv30->vtxbuf[i].buffer == res) {
+         if (nv30->vtxbuf[i].buffer.resource == res) {
             nv30->dirty |= NV30_NEW_ARRAYS;
             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXBUF);
             if (!--ref)
                return ref;
          }
       }
    }
    if (res->bind & PIPE_BIND_INDEX_BUFFER) {
       if (nv30->idxbuf.buffer == res) {
          nouveau_bufctx_reset(nv30->bufctx, BUFCTX_IDXBUF);
diff --git a/src/gallium/drivers/nouveau/nv30/nv30_draw.c b/src/gallium/drivers/nouveau/nv30/nv30_draw.c
index 10c9f56..28d3de9 100644
--- a/src/gallium/drivers/nouveau/nv30/nv30_draw.c
+++ b/src/gallium/drivers/nouveau/nv30/nv30_draw.c
@@ -412,24 +412,25 @@ nv30_render_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
       if (nv30->vertprog.constbuf) {
          void *map = nv04_resource(nv30->vertprog.constbuf)->data;
          draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0,
                                          map, nv30->vertprog.constbuf_nr * 16);
       } else {
          draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0);
       }
    }
 
    for (i = 0; i < nv30->num_vtxbufs; i++) {
-      const void *map = nv30->vtxbuf[i].user_buffer;
+      const void *map = nv30->vtxbuf[i].is_user_buffer ?
+                           nv30->vtxbuf[i].buffer.user : NULL;
       if (!map) {
-         if (nv30->vtxbuf[i].buffer)
-            map = pipe_buffer_map(pipe, nv30->vtxbuf[i].buffer,
+         if (nv30->vtxbuf[i].buffer.resource)
+            map = pipe_buffer_map(pipe, nv30->vtxbuf[i].buffer.resource,
                                   PIPE_TRANSFER_UNSYNCHRONIZED |
                                   PIPE_TRANSFER_READ, &transfer[i]);
       }
       draw_set_mapped_vertex_buffer(draw, i, map, ~0);
    }
 
    if (info->indexed) {
       const void *map = nv30->idxbuf.user_buffer;
       if (!map)
          map = pipe_buffer_map(pipe, nv30->idxbuf.buffer,
diff --git a/src/gallium/drivers/nouveau/nv30/nv30_push.c b/src/gallium/drivers/nouveau/nv30/nv30_push.c
index 67ab050..90adfa0 100644
--- a/src/gallium/drivers/nouveau/nv30/nv30_push.c
+++ b/src/gallium/drivers/nouveau/nv30/nv30_push.c
@@ -202,23 +202,23 @@ nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info)
    bool apply_bias = info->indexed && info->index_bias;
 
    ctx.push = nv30->base.pushbuf;
    ctx.translate = nv30->vertex->translate;
    ctx.packet_vertex_limit = nv30->vertex->vtx_per_packet_max;
    ctx.vertex_words = nv30->vertex->vtx_size;
 
    for (i = 0; i < nv30->num_vtxbufs; ++i) {
       uint8_t *data;
       struct pipe_vertex_buffer *vb = &nv30->vtxbuf[i];
-      struct nv04_resource *res = nv04_resource(vb->buffer);
+      struct nv04_resource *res = nv04_resource(vb->buffer.resource);
 
-      if (!vb->buffer && !vb->user_buffer) {
+      if (!vb->buffer.resource) {
          continue;
       }
 
       data = nouveau_resource_map_offset(&nv30->base, res,
                                          vb->buffer_offset, NOUVEAU_BO_RD);
 
       if (apply_bias)
          data += info->index_bias * vb->stride;
 
       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
@@ -274,17 +274,17 @@ nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info)
       assert(0);
       break;
    }
    BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
    PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP);
 
    if (info->indexed)
       nouveau_resource_unmap(nv04_resource(nv30->idxbuf.buffer));
 
    for (i = 0; i < nv30->num_vtxbufs; ++i) {
-      if (nv30->vtxbuf[i].buffer) {
-         nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer));
+      if (nv30->vtxbuf[i].buffer.resource) {
+         nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer.resource));
       }
    }
 
    nv30_state_release(nv30);
 }
diff --git a/src/gallium/drivers/nouveau/nv30/nv30_resource.c b/src/gallium/drivers/nouveau/nv30/nv30_resource.c
index 6238a23..d5842dd 100644
--- a/src/gallium/drivers/nouveau/nv30/nv30_resource.c
+++ b/src/gallium/drivers/nouveau/nv30/nv30_resource.c
@@ -32,23 +32,23 @@
 #include "nv30/nv30_transfer.h"
 
 static void
 nv30_memory_barrier(struct pipe_context *pipe, unsigned flags)
 {
    struct nv30_context *nv30 = nv30_context(pipe);
    int i;
 
    if (flags & PIPE_BARRIER_MAPPED_BUFFER) {
       for (i = 0; i < nv30->num_vtxbufs; ++i) {
-         if (!nv30->vtxbuf[i].buffer)
+         if (!nv30->vtxbuf[i].buffer.resource)
             continue;
-         if (nv30->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
+         if (nv30->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
             nv30->base.vbo_dirty = true;
       }
 
       if (nv30->idxbuf.buffer &&
           nv30->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
          nv30->base.vbo_dirty = true;
    }
 }
 
 static struct pipe_resource *
diff --git a/src/gallium/drivers/nouveau/nv30/nv30_vbo.c b/src/gallium/drivers/nouveau/nv30/nv30_vbo.c
index 9338f2e..d049b55 100644
--- a/src/gallium/drivers/nouveau/nv30/nv30_vbo.c
+++ b/src/gallium/drivers/nouveau/nv30/nv30_vbo.c
@@ -33,21 +33,21 @@
 #include "nv30/nv30-40_3d.xml.h"
 #include "nv30/nv30_context.h"
 #include "nv30/nv30_format.h"
 
 static void
 nv30_emit_vtxattr(struct nv30_context *nv30, struct pipe_vertex_buffer *vb,
                   struct pipe_vertex_element *ve, unsigned attr)
 {
    const unsigned nc = util_format_get_nr_components(ve->src_format);
    struct nouveau_pushbuf *push = nv30->base.pushbuf;
-   struct nv04_resource *res = nv04_resource(vb->buffer);
+   struct nv04_resource *res = nv04_resource(vb->buffer.resource);
    const struct util_format_description *desc =
       util_format_description(ve->src_format);
    const void *data;
    float v[4];
 
    data = nouveau_resource_map_offset(&nv30->base, res, vb->buffer_offset +
                                       ve->src_offset, NOUVEAU_BO_RD);
 
    desc->unpack_rgba_float(v, 0, data, 0, 1, 1);
 
@@ -95,26 +95,26 @@ nv30_prevalidate_vbufs(struct nv30_context *nv30)
 {
    struct pipe_vertex_buffer *vb;
    struct nv04_resource *buf;
    int i;
    uint32_t base, size;
 
    nv30->vbo_fifo = nv30->vbo_user = 0;
 
    for (i = 0; i < nv30->num_vtxbufs; i++) {
       vb = &nv30->vtxbuf[i];
-      if (!vb->stride || !vb->buffer) /* NOTE: user_buffer not implemented */
+      if (!vb->stride || !vb->buffer.resource) /* NOTE: user_buffer not implemented */
          continue;
-      buf = nv04_resource(vb->buffer);
+      buf = nv04_resource(vb->buffer.resource);
 
       /* NOTE: user buffers with temporary storage count as mapped by GPU */
-      if (!nouveau_resource_mapped_by_gpu(vb->buffer)) {
+      if (!nouveau_resource_mapped_by_gpu(vb->buffer.resource)) {
          if (nv30->vbo_push_hint) {
             nv30->vbo_fifo = ~0;
             continue;
          } else {
             if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) {
                nv30->vbo_user |= 1 << i;
                assert(vb->stride > vb->buffer_offset);
                nv30_vbuf_range(nv30, i, &base, &size);
                nouveau_user_buffer_upload(&nv30->base, buf, base, size);
             } else {
@@ -131,21 +131,21 @@ nv30_update_user_vbufs(struct nv30_context *nv30)
 {
    struct nouveau_pushbuf *push = nv30->base.pushbuf;
    uint32_t base, offset, size;
    int i;
    uint32_t written = 0;
 
    for (i = 0; i < nv30->vertex->num_elements; i++) {
       struct pipe_vertex_element *ve = &nv30->vertex->pipe[i];
       const int b = ve->vertex_buffer_index;
       struct pipe_vertex_buffer *vb = &nv30->vtxbuf[b];
-      struct nv04_resource *buf = nv04_resource(vb->buffer);
+      struct nv04_resource *buf = nv04_resource(vb->buffer.resource);
 
       if (!(nv30->vbo_user & (1 << b)))
          continue;
 
       if (!vb->stride) {
          nv30_emit_vtxattr(nv30, vb, ve, i);
          continue;
       }
       nv30_vbuf_range(nv30, b, &base, &size);
 
@@ -166,21 +166,21 @@ nv30_update_user_vbufs(struct nv30_context *nv30)
 
 static inline void
 nv30_release_user_vbufs(struct nv30_context *nv30)
 {
    uint32_t vbo_user = nv30->vbo_user;
 
    while (vbo_user) {
       int i = ffs(vbo_user) - 1;
       vbo_user &= ~(1 << i);
 
-      nouveau_buffer_release_gpu_storage(nv04_resource(nv30->vtxbuf[i].buffer));
+      nouveau_buffer_release_gpu_storage(nv04_resource(nv30->vtxbuf[i].buffer.resource));
    }
 
    nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXTMP);
 }
 
 void
 nv30_vbo_validate(struct nv30_context *nv30)
 {
    struct nouveau_pushbuf *push = nv30->base.pushbuf;
    struct nv30_vertex_stateobj *vertex = nv30->vertex;
@@ -228,21 +228,21 @@ nv30_vbo_validate(struct nv30_context *nv30)
 
    for (i = 0; i < vertex->num_elements; i++) {
       struct nv04_resource *res;
       unsigned offset;
       bool user;
 
       ve = &vertex->pipe[i];
       vb = &nv30->vtxbuf[ve->vertex_buffer_index];
       user = (nv30->vbo_user & (1 << ve->vertex_buffer_index));
 
-      res = nv04_resource(vb->buffer);
+      res = nv04_resource(vb->buffer.resource);
 
       if (nv30->vbo_fifo || unlikely(vb->stride == 0)) {
          if (!nv30->vbo_fifo)
             nv30_emit_vtxattr(nv30, vb, ve, i);
          continue;
       }
 
       offset = ve->src_offset + vb->buffer_offset;
 
       BEGIN_NV04(push, NV30_3D(VTXBUF(i)), 1);
@@ -576,23 +576,23 @@ nv30_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    if (nv30->draw_flags) {
       nv30_render_vbo(pipe, info);
       return;
    } else
    if (nv30->vbo_fifo) {
       nv30_push_vbo(nv30, info);
       return;
    }
 
    for (i = 0; i < nv30->num_vtxbufs && !nv30->base.vbo_dirty; ++i) {
-      if (!nv30->vtxbuf[i].buffer)
+      if (!nv30->vtxbuf[i].buffer.resource)
          continue;
-      if (nv30->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
+      if (nv30->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
          nv30->base.vbo_dirty = true;
    }
 
    if (!nv30->base.vbo_dirty && nv30->idxbuf.buffer &&
        nv30->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
       nv30->base.vbo_dirty = true;
 
    if (nv30->base.vbo_dirty) {
       BEGIN_NV04(push, NV30_3D(VTX_CACHE_INVALIDATE_1710), 1);
       PUSH_DATA (push, 0);
diff --git a/src/gallium/drivers/nouveau/nv50/nv50_context.c b/src/gallium/drivers/nouveau/nv50/nv50_context.c
index bf768bc..d072927 100644
--- a/src/gallium/drivers/nouveau/nv50/nv50_context.c
+++ b/src/gallium/drivers/nouveau/nv50/nv50_context.c
@@ -55,23 +55,23 @@ nv50_texture_barrier(struct pipe_context *pipe, unsigned flags)
 }
 
 static void
 nv50_memory_barrier(struct pipe_context *pipe, unsigned flags)
 {
    struct nv50_context *nv50 = nv50_context(pipe);
    int i, s;
 
    if (flags & PIPE_BARRIER_MAPPED_BUFFER) {
       for (i = 0; i < nv50->num_vtxbufs; ++i) {
-         if (!nv50->vtxbuf[i].buffer)
+         if (!nv50->vtxbuf[i].buffer.resource && !nv50->vtxbuf[i].is_user_buffer)
             continue;
-         if (nv50->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
+         if (nv50->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
             nv50->base.vbo_dirty = true;
       }
 
       if (nv50->idxbuf.buffer &&
           nv50->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
          nv50->base.vbo_dirty = true;
 
       for (s = 0; s < 3 && !nv50->cb_dirty; ++s) {
          uint32_t valid = nv50->constbuf_valid[s];
 
@@ -137,21 +137,21 @@ nv50_context_unreference_resources(struct nv50_context *nv50)
    unsigned s, i;
 
    nouveau_bufctx_del(&nv50->bufctx_3d);
    nouveau_bufctx_del(&nv50->bufctx);
    nouveau_bufctx_del(&nv50->bufctx_cp);
 
    util_unreference_framebuffer_state(&nv50->framebuffer);
 
    assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
    for (i = 0; i < nv50->num_vtxbufs; ++i)
-      pipe_resource_reference(&nv50->vtxbuf[i].buffer, NULL);
+      pipe_resource_reference(&nv50->vtxbuf[i].buffer.resource, NULL);
 
    pipe_resource_reference(&nv50->idxbuf.buffer, NULL);
 
    for (s = 0; s < 3; ++s) {
       assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);
       for (i = 0; i < nv50->num_textures[s]; ++i)
          pipe_sampler_view_reference(&nv50->textures[s][i], NULL);
 
       for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i)
          if (!nv50->constbuf[s][i].user)
@@ -223,21 +223,21 @@ nv50_invalidate_resource_storage(struct nouveau_context *ctx,
    }
 
    if (bind & (PIPE_BIND_VERTEX_BUFFER |
                PIPE_BIND_INDEX_BUFFER |
                PIPE_BIND_CONSTANT_BUFFER |
                PIPE_BIND_STREAM_OUTPUT |
                PIPE_BIND_SAMPLER_VIEW)) {
 
       assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
       for (i = 0; i < nv50->num_vtxbufs; ++i) {
-         if (nv50->vtxbuf[i].buffer == res) {
+         if (nv50->vtxbuf[i].buffer.resource == res) {
             nv50->dirty_3d |= NV50_NEW_3D_ARRAYS;
             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_VERTEX);
             if (!--ref)
                return ref;
          }
       }
 
       if (nv50->idxbuf.buffer == res) {
          /* Just rebind to the bufctx as there is no separate dirty bit */
          nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_INDEX);
diff --git a/src/gallium/drivers/nouveau/nv50/nv50_push.c b/src/gallium/drivers/nouveau/nv50/nv50_push.c
index 6a53ad0..d341901 100644
--- a/src/gallium/drivers/nouveau/nv50/nv50_push.c
+++ b/src/gallium/drivers/nouveau/nv50/nv50_push.c
@@ -257,25 +257,25 @@ nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info)
    /* For indexed draws, gl_VertexID must be emitted for every vertex. */
    ctx.packet_vertex_limit =
       ctx.need_vertex_id ? 1 : nv50->vertex->packet_vertex_limit;
    ctx.vertex_words = nv50->vertex->vertex_size;
 
    assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
    for (i = 0; i < nv50->num_vtxbufs; ++i) {
       const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i];
       const uint8_t *data;
 
-      if (unlikely(vb->buffer))
+      if (unlikely(!vb->is_user_buffer))
          data = nouveau_resource_map_offset(&nv50->base,
-            nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD);
+            nv04_resource(vb->buffer.resource), vb->buffer_offset, NOUVEAU_BO_RD);
       else
-         data = vb->user_buffer;
+         data = vb->buffer.user;
 
       if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i))))
          data += (ptrdiff_t)info->index_bias * vb->stride;
 
       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
    }
 
    if (info->indexed) {
       if (nv50->idxbuf.buffer) {
          ctx.idxbuf = nouveau_resource_map_offset(&nv50->base,
diff --git a/src/gallium/drivers/nouveau/nv50/nv50_state.c b/src/gallium/drivers/nouveau/nv50/nv50_state.c
index 6fa3d2c..d5af6c9 100644
--- a/src/gallium/drivers/nouveau/nv50/nv50_state.c
+++ b/src/gallium/drivers/nouveau/nv50/nv50_state.c
@@ -1053,33 +1053,33 @@ nv50_set_vertex_buffers(struct pipe_context *pipe,
    if (!vb) {
       nv50->vbo_user &= ~(((1ull << count) - 1) << start_slot);
       nv50->vbo_constant &= ~(((1ull << count) - 1) << start_slot);
       nv50->vtxbufs_coherent &= ~(((1ull << count) - 1) << start_slot);
       return;
    }
 
    for (i = 0; i < count; ++i) {
       unsigned dst_index = start_slot + i;
 
-      if (!vb[i].buffer && vb[i].user_buffer) {
+      if (vb[i].is_user_buffer) {
          nv50->vbo_user |= 1 << dst_index;
          if (!vb[i].stride)
             nv50->vbo_constant |= 1 << dst_index;
          else
             nv50->vbo_constant &= ~(1 << dst_index);
          nv50->vtxbufs_coherent &= ~(1 << dst_index);
       } else {
          nv50->vbo_user &= ~(1 << dst_index);
          nv50->vbo_constant &= ~(1 << dst_index);
 
-         if (vb[i].buffer &&
-             vb[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
+         if (vb[i].buffer.resource &&
+             vb[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
             nv50->vtxbufs_coherent |= (1 << dst_index);
          else
             nv50->vtxbufs_coherent &= ~(1 << dst_index);
       }
    }
 }
 
 static void
 nv50_set_index_buffer(struct pipe_context *pipe,
                       const struct pipe_index_buffer *ib)
diff --git a/src/gallium/drivers/nouveau/nv50/nv50_vbo.c b/src/gallium/drivers/nouveau/nv50/nv50_vbo.c
index 227038e..60970d7 100644
--- a/src/gallium/drivers/nouveau/nv50/nv50_vbo.c
+++ b/src/gallium/drivers/nouveau/nv50/nv50_vbo.c
@@ -134,27 +134,27 @@ nv50_vertex_state_create(struct pipe_context *pipe,
 #define NV50_3D_VERTEX_ATTRIB_INACTIVE              \
    NV50_3D_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT |         \
    NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32_32 | \
    NV50_3D_VERTEX_ARRAY_ATTRIB_CONST
 
 static void
 nv50_emit_vtxattr(struct nv50_context *nv50, struct pipe_vertex_buffer *vb,
                   struct pipe_vertex_element *ve, unsigned attr)
 {
    struct nouveau_pushbuf *push = nv50->base.pushbuf;
-   const void *data = (const uint8_t *)vb->user_buffer + ve->src_offset;
+   const void *data = (const uint8_t *)vb->buffer.user + ve->src_offset;
    float v[4];
    const unsigned nc = util_format_get_nr_components(ve->src_format);
    const struct util_format_description *desc =
       util_format_description(ve->src_format);
 
-   assert(vb->user_buffer);
+   assert(vb->is_user_buffer);
 
    if (desc->channel[0].pure_integer) {
       if (desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {
          desc->unpack_rgba_sint((int32_t *)v, 0, data, 0, 1, 1);
       } else {
          desc->unpack_rgba_uint((uint32_t *)v, 0, data, 0, 1, 1);
       }
    } else {
       desc->unpack_rgba_float(v, 0, data, 0, 1, 1);
    }
@@ -193,21 +193,21 @@ nv50_emit_vtxattr(struct nv50_context *nv50, struct pipe_vertex_buffer *vb,
 }
 
 static inline void
 nv50_user_vbuf_range(struct nv50_context *nv50, unsigned vbi,
                      uint32_t *base, uint32_t *size)
 {
    assert(vbi < PIPE_MAX_ATTRIBS);
    if (unlikely(nv50->vertex->instance_bufs & (1 << vbi))) {
       /* TODO: use min and max instance divisor to get a proper range */
       *base = 0;
-      *size = nv50->vtxbuf[vbi].buffer->width0;
+      *size = nv50->vtxbuf[vbi].buffer.resource->width0;
    } else {
       /* NOTE: if there are user buffers, we *must* have index bounds */
       assert(nv50->vb_elt_limit != ~0);
       *base = nv50->vb_elt_first * nv50->vtxbuf[vbi].stride;
       *size = nv50->vb_elt_limit * nv50->vtxbuf[vbi].stride +
          nv50->vertex->vb_access_size[vbi];
    }
 }
 
 static void
@@ -220,21 +220,21 @@ nv50_upload_user_buffers(struct nv50_context *nv50,
    for (b = 0; b < nv50->num_vtxbufs; ++b) {
       struct nouveau_bo *bo;
       const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[b];
       uint32_t base, size;
 
       if (!(nv50->vbo_user & (1 << b)) || !vb->stride)
          continue;
       nv50_user_vbuf_range(nv50, b, &base, &size);
 
       limits[b] = base + size - 1;
-      addrs[b] = nouveau_scratch_data(&nv50->base, vb->user_buffer, base, size,
+      addrs[b] = nouveau_scratch_data(&nv50->base, vb->buffer.user, base, size,
                                       &bo);
       if (addrs[b])
          BCTX_REFN_bo(nv50->bufctx_3d, 3D_VERTEX_TMP, NOUVEAU_BO_GART |
                       NOUVEAU_BO_RD, bo);
    }
    nv50->base.vbo_dirty = true;
 }
 
 static void
 nv50_update_user_vbufs(struct nv50_context *nv50)
@@ -259,21 +259,21 @@ nv50_update_user_vbufs(struct nv50_context *nv50)
       if (!vb->stride) {
          nv50_emit_vtxattr(nv50, vb, ve, i);
          continue;
       }
       nv50_user_vbuf_range(nv50, b, &base, &size);
 
       if (!(written & (1 << b))) {
          struct nouveau_bo *bo;
          const uint32_t bo_flags = NOUVEAU_BO_GART | NOUVEAU_BO_RD;
          written |= 1 << b;
-         address[b] = nouveau_scratch_data(&nv50->base, vb->user_buffer,
+         address[b] = nouveau_scratch_data(&nv50->base, vb->buffer.user,
                                            base, size, &bo);
          if (address[b])
             BCTX_REFN_bo(nv50->bufctx_3d, 3D_VERTEX_TMP, bo_flags, bo);
       }
 
       BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2);
       PUSH_DATAh(push, address[b] + base + size - 1);
       PUSH_DATA (push, address[b] + base + size - 1);
       BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_START_HIGH(i)), 2);
       PUSH_DATAh(push, address[b] + ve->src_offset);
@@ -310,22 +310,23 @@ nv50_vertex_arrays_validate(struct nv50_context *nv50)
    else
    if (nv50->vbo_user & ~nv50->vbo_constant)
       nv50->vbo_fifo = nv50->vbo_push_hint ? ~0 : 0;
    else
       nv50->vbo_fifo = 0;
 
    if (!nv50->vbo_fifo) {
       /* if vertex buffer was written by GPU - flush VBO cache */
       assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
       for (i = 0; i < nv50->num_vtxbufs; ++i) {
-         struct nv04_resource *buf = nv04_resource(nv50->vtxbuf[i].buffer);
-         if (buf && buf->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
+         struct nv04_resource *buf = nv04_resource(nv50->vtxbuf[i].buffer.resource);
+         if (!nv50->vtxbuf[i].is_user_buffer &&
+             buf && buf->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
             buf->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;
             nv50->base.vbo_dirty = true;
          }
       }
    }
 
    /* update vertex format state */
    BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_ATTRIB(0)), n);
    if (nv50->vbo_fifo) {
       nv50->state.num_vtxelts = vertex->num_elements;
@@ -379,26 +380,26 @@ nv50_vertex_arrays_validate(struct nv50_context *nv50)
       if (unlikely(nv50->vbo_constant & (1 << b))) {
          BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FETCH(i)), 1);
          PUSH_DATA (push, 0);
          nv50_emit_vtxattr(nv50, vb, &ve->pipe, i);
          continue;
       } else
       if (nv50->vbo_user & (1 << b)) {
          address = addrs[b] + ve->pipe.src_offset;
          limit = addrs[b] + limits[b];
       } else
-      if (!vb->buffer) {
+      if (!vb->buffer.resource) {
          BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FETCH(i)), 1);
          PUSH_DATA (push, 0);
          continue;
       } else {
-         struct nv04_resource *buf = nv04_resource(vb->buffer);
+         struct nv04_resource *buf = nv04_resource(vb->buffer.resource);
          if (!(refd & (1 << b))) {
             refd |= 1 << b;
             BCTX_REFN(nv50->bufctx_3d, 3D_VERTEX, buf, RD);
          }
          address = buf->address + vb->buffer_offset + ve->pipe.src_offset;
          limit = buf->address + buf->base.width0 - 1;
       }
 
       if (unlikely(ve->pipe.instance_divisor)) {
          BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FETCH(i)), 4);
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_context.c b/src/gallium/drivers/nouveau/nvc0/nvc0_context.c
index d0f4da3..ef61256 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_context.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_context.c
@@ -55,23 +55,23 @@ nvc0_texture_barrier(struct pipe_context *pipe, unsigned flags)
 
 static void
 nvc0_memory_barrier(struct pipe_context *pipe, unsigned flags)
 {
    struct nvc0_context *nvc0 = nvc0_context(pipe);
    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    int i, s;
 
    if (flags & PIPE_BARRIER_MAPPED_BUFFER) {
       for (i = 0; i < nvc0->num_vtxbufs; ++i) {
-         if (!nvc0->vtxbuf[i].buffer)
+         if (!nvc0->vtxbuf[i].buffer.resource && !nvc0->vtxbuf[i].is_user_buffer)
             continue;
-         if (nvc0->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
+         if (nvc0->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
             nvc0->base.vbo_dirty = true;
       }
 
       if (nvc0->idxbuf.buffer &&
           nvc0->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
          nvc0->base.vbo_dirty = true;
 
       for (s = 0; s < 5 && !nvc0->cb_dirty; ++s) {
          uint32_t valid = nvc0->constbuf_valid[s];
 
@@ -140,21 +140,21 @@ nvc0_context_unreference_resources(struct nvc0_context *nvc0)
 {
    unsigned s, i;
 
    nouveau_bufctx_del(&nvc0->bufctx_3d);
    nouveau_bufctx_del(&nvc0->bufctx);
    nouveau_bufctx_del(&nvc0->bufctx_cp);
 
    util_unreference_framebuffer_state(&nvc0->framebuffer);
 
    for (i = 0; i < nvc0->num_vtxbufs; ++i)
-      pipe_resource_reference(&nvc0->vtxbuf[i].buffer, NULL);
+      pipe_vertex_buffer_unreference(&nvc0->vtxbuf[i]);
 
    pipe_resource_reference(&nvc0->idxbuf.buffer, NULL);
 
    for (s = 0; s < 6; ++s) {
       for (i = 0; i < nvc0->num_textures[s]; ++i)
          pipe_sampler_view_reference(&nvc0->textures[s][i], NULL);
 
       for (i = 0; i < NVC0_MAX_PIPE_CONSTBUFS; ++i)
          if (!nvc0->constbuf[s][i].user)
             pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, NULL);
@@ -253,21 +253,21 @@ nvc0_invalidate_resource_storage(struct nouveau_context *ctx,
           nvc0->framebuffer.zsbuf->texture == res) {
          nvc0->dirty_3d |= NVC0_NEW_3D_FRAMEBUFFER;
          nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_FB);
          if (!--ref)
             return ref;
       }
    }
 
    if (res->target == PIPE_BUFFER) {
       for (i = 0; i < nvc0->num_vtxbufs; ++i) {
-         if (nvc0->vtxbuf[i].buffer == res) {
+         if (nvc0->vtxbuf[i].buffer.resource == res) {
             nvc0->dirty_3d |= NVC0_NEW_3D_ARRAYS;
             nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_VTX);
             if (!--ref)
                return ref;
          }
       }
 
       if (nvc0->idxbuf.buffer == res) {
          nvc0->dirty_3d |= NVC0_NEW_3D_IDXBUF;
          nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_IDX);
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c
index c51c9a7..bf33746 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c
@@ -934,33 +934,33 @@ nvc0_set_vertex_buffers(struct pipe_context *pipe,
     if (!vb) {
        nvc0->vbo_user &= ~(((1ull << count) - 1) << start_slot);
        nvc0->constant_vbos &= ~(((1ull << count) - 1) << start_slot);
        nvc0->vtxbufs_coherent &= ~(((1ull << count) - 1) << start_slot);
        return;
     }
 
     for (i = 0; i < count; ++i) {
        unsigned dst_index = start_slot + i;
 
-       if (vb[i].user_buffer) {
+       if (vb[i].is_user_buffer) {
           nvc0->vbo_user |= 1 << dst_index;
           if (!vb[i].stride && nvc0->screen->eng3d->oclass < GM107_3D_CLASS)
              nvc0->constant_vbos |= 1 << dst_index;
           else
              nvc0->constant_vbos &= ~(1 << dst_index);
           nvc0->vtxbufs_coherent &= ~(1 << dst_index);
        } else {
           nvc0->vbo_user &= ~(1 << dst_index);
           nvc0->constant_vbos &= ~(1 << dst_index);
 
-          if (vb[i].buffer &&
-              vb[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
+          if (vb[i].buffer.resource &&
+              vb[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)
              nvc0->vtxbufs_coherent |= (1 << dst_index);
           else
              nvc0->vtxbufs_coherent &= ~(1 << dst_index);
        }
     }
 }
 
 static void
 nvc0_set_index_buffer(struct pipe_context *pipe,
                       const struct pipe_index_buffer *ib)
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c
index 9a3eb06..b42b468 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c
@@ -169,22 +169,22 @@ nvc0_vertex_state_create(struct pipe_context *pipe,
 
 static void
 nvc0_set_constant_vertex_attrib(struct nvc0_context *nvc0, const unsigned a)
 {
    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    struct pipe_vertex_element *ve = &nvc0->vertex->element[a].pipe;
    struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index];
    uint32_t mode;
    const struct util_format_description *desc;
    void *dst;
-   const void *src = (const uint8_t *)vb->user_buffer + ve->src_offset;
-   assert(!vb->buffer);
+   const void *src = (const uint8_t *)vb->buffer.user + ve->src_offset;
+   assert(vb->is_user_buffer);
 
    desc = util_format_description(ve->src_format);
 
    PUSH_SPACE(push, 6);
    BEGIN_NVC0(push, NVC0_3D(VTX_ATTR_DEFINE), 5);
    dst = &push->cur[1];
    if (desc->channel[0].pure_integer) {
       if (desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {
          mode = VTX_ATTR(a, 4, SINT, 32);
          desc->unpack_rgba_sint(dst, 0, src, 0, 1, 1);
@@ -247,21 +247,21 @@ nvc0_update_user_vbufs(struct nvc0_context *nvc0)
       if (nvc0->constant_vbos & (1 << b)) {
          nvc0_set_constant_vertex_attrib(nvc0, i);
          continue;
       }
       nvc0_user_vbuf_range(nvc0, b, &base, &size);
 
       if (!(written & (1 << b))) {
          struct nouveau_bo *bo;
          const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART;
          written |= 1 << b;
-         address[b] = nouveau_scratch_data(&nvc0->base, vb->user_buffer,
+         address[b] = nouveau_scratch_data(&nvc0->base, vb->buffer.user,
                                            base, size, &bo);
          if (bo)
             BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, bo_flags, bo);
 
          NOUVEAU_DRV_STAT(&nvc0->screen->base, user_buffer_upload_bytes, size);
       }
 
       BEGIN_1IC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_SELECT), 5);
       PUSH_DATA (push, i);
       PUSH_DATAh(push, address[b] + base + size - 1);
@@ -282,21 +282,21 @@ nvc0_update_user_vbufs_shared(struct nvc0_context *nvc0)
    while (mask) {
       struct nouveau_bo *bo;
       const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART;
       uint64_t address;
       uint32_t base, size;
       const int b = ffs(mask) - 1;
       mask &= ~(1 << b);
 
       nvc0_user_vbuf_range(nvc0, b, &base, &size);
 
-      address = nouveau_scratch_data(&nvc0->base, nvc0->vtxbuf[b].user_buffer,
+      address = nouveau_scratch_data(&nvc0->base, nvc0->vtxbuf[b].buffer.user,
                                      base, size, &bo);
       if (bo)
          BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, bo_flags, bo);
 
       BEGIN_1IC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_SELECT), 5);
       PUSH_DATA (push, b);
       PUSH_DATAh(push, address + base + size - 1);
       PUSH_DATA (push, address + base + size - 1);
       PUSH_DATAh(push, address);
       PUSH_DATA (push, address);
@@ -339,23 +339,23 @@ nvc0_validate_vertex_buffers(struct nvc0_context *nvc0)
             if (ve->pipe.instance_divisor) {
                BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_DIVISOR(i)), 1);
                PUSH_DATA (push, ve->pipe.instance_divisor);
             }
             BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 1);
             PUSH_DATA (push, (1 << 12) | vb->stride);
          }
          /* address/value set in nvc0_update_user_vbufs */
          continue;
       }
-      res = nv04_resource(vb->buffer);
+      res = nv04_resource(vb->buffer.resource);
       offset = ve->pipe.src_offset + vb->buffer_offset;
-      limit = vb->buffer->width0 - 1;
+      limit = vb->buffer.resource->width0 - 1;
 
       if (unlikely(ve->pipe.instance_divisor)) {
          BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 4);
          PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
          PUSH_DATAh(push, res->address + offset);
          PUSH_DATA (push, res->address + offset);
          PUSH_DATA (push, ve->pipe.instance_divisor);
       } else {
          BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 3);
          PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
@@ -388,26 +388,26 @@ nvc0_validate_vertex_buffers_shared(struct nvc0_context *nvc0)
       struct nv04_resource *buf;
       uint32_t offset, limit;
 
       if (mask & (1 << b)) {
          if (!(nvc0->constant_vbos & (1 << b))) {
             BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 1);
             PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
          }
          /* address/value set in nvc0_update_user_vbufs_shared */
          continue;
-      } else if (!vb->buffer) {
+      } else if (!vb->buffer.resource) {
          /* there can be holes in the vertex buffer lists */
          IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 0);
          continue;
       }
-      buf = nv04_resource(vb->buffer);
+      buf = nv04_resource(vb->buffer.resource);
       offset = vb->buffer_offset;
       limit = buf->base.width0 - 1;
 
       BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 3);
       PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
       PUSH_DATAh(push, buf->address + offset);
       PUSH_DATA (push, buf->address + offset);
       BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(b)), 2);
       PUSH_DATAh(push, buf->address + limit);
       PUSH_DATA (push, buf->address + limit);
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c
index fd2bcbb..e4ccac8 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c
@@ -62,25 +62,25 @@ nvc0_push_context_init(struct nvc0_context *nvc0, struct push_context *ctx)
 static inline void
 nvc0_vertex_configure_translate(struct nvc0_context *nvc0, int32_t index_bias)
 {
    struct translate *translate = nvc0->vertex->translate;
    unsigned i;
 
    for (i = 0; i < nvc0->num_vtxbufs; ++i) {
       const uint8_t *map;
       const struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
 
-      if (likely(!vb->buffer))
-         map = (const uint8_t *)vb->user_buffer;
+      if (likely(vb->is_user_buffer))
+         map = (const uint8_t *)vb->buffer.user;
       else
          map = nouveau_resource_map_offset(&nvc0->base,
-            nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD);
+            nv04_resource(vb->buffer.resource), vb->buffer_offset, NOUVEAU_BO_RD);
 
       if (index_bias && !unlikely(nvc0->vertex->instance_bufs & (1 << i)))
          map += (intptr_t)index_bias * vb->stride;
 
       translate->set_buffer(translate, i, map, vb->stride, ~0);
    }
 }
 
 static inline void
 nvc0_push_map_idxbuf(struct push_context *ctx, struct nvc0_context *nvc0)
@@ -94,30 +94,30 @@ nvc0_push_map_idxbuf(struct push_context *ctx, struct nvc0_context *nvc0)
    }
 }
 
 static inline void
 nvc0_push_map_edgeflag(struct push_context *ctx, struct nvc0_context *nvc0,
                        int32_t index_bias)
 {
    unsigned attr = nvc0->vertprog->vp.edgeflag;
    struct pipe_vertex_element *ve = &nvc0->vertex->element[attr].pipe;
    struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index];
-   struct nv04_resource *buf = nv04_resource(vb->buffer);
+   struct nv04_resource *buf = nv04_resource(vb->buffer.resource);
 
    ctx->edgeflag.stride = vb->stride;
    ctx->edgeflag.width = util_format_get_blocksize(ve->src_format);
-   if (buf) {
+   if (!vb->is_user_buffer) {
       unsigned offset = vb->buffer_offset + ve->src_offset;
       ctx->edgeflag.data = nouveau_resource_map_offset(&nvc0->base,
                            buf, offset, NOUVEAU_BO_RD);
    } else {
-      ctx->edgeflag.data = (const uint8_t *)vb->user_buffer + ve->src_offset;
+      ctx->edgeflag.data = (const uint8_t *)vb->buffer.user + ve->src_offset;
    }
 
    if (index_bias)
       ctx->edgeflag.data += (intptr_t)index_bias * vb->stride;
 }
 
 static inline unsigned
 prim_restart_search_i08(const uint8_t *elts, unsigned push, uint8_t index)
 {
    unsigned i;
@@ -579,21 +579,21 @@ nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
       PUSH_DATA (ctx.push,
                  NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST |
                  NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |
                  NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32);
       IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FETCH(1)), 0);
    }
 
    if (info->indexed)
       nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer));
    for (i = 0; i < nvc0->num_vtxbufs; ++i)
-      nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer));
+      nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer.resource));
 
    NOUVEAU_DRV_STAT(&nvc0->screen->base, draw_calls_fallback_count, 1);
 }
 
 static inline void
 copy_indices_u8(uint32_t *dst, const uint8_t *elts, uint32_t bias, unsigned n)
 {
    unsigned i;
    for (i = 0; i < n; ++i)
       dst[i] = elts[i] + bias;
diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c
index 02af5d7..6f4231d 100644
--- a/src/gallium/drivers/r300/r300_context.c
+++ b/src/gallium/drivers/r300/r300_context.c
@@ -56,21 +56,21 @@ static void r300_release_referenced_objects(struct r300_context *r300)
                 (struct pipe_sampler_view**)&textures->sampler_views[i], NULL);
 
     /* The special dummy texture for texkill. */
     if (r300->texkill_sampler) {
         pipe_sampler_view_reference(
                 (struct pipe_sampler_view**)&r300->texkill_sampler,
                 NULL);
     }
 
     /* Manually-created vertex buffers. */
-    pipe_resource_reference(&r300->dummy_vb.buffer, NULL);
+    pipe_vertex_buffer_unreference(&r300->dummy_vb);
     pb_reference(&r300->vbo, NULL);
 
     r300->context.delete_depth_stencil_alpha_state(&r300->context,
                                                    r300->dsa_decompress_zmask);
 }
 
 static void r300_destroy_context(struct pipe_context* context)
 {
     struct r300_context* r300 = r300_context(context);
 
@@ -461,21 +461,21 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,
     if (r300screen->caps.has_tcl) {
         struct pipe_resource vb;
         memset(&vb, 0, sizeof(vb));
         vb.target = PIPE_BUFFER;
         vb.format = PIPE_FORMAT_R8_UNORM;
         vb.usage = PIPE_USAGE_DEFAULT;
         vb.width0 = sizeof(float) * 16;
         vb.height0 = 1;
         vb.depth0 = 1;
 
-        r300->dummy_vb.buffer = screen->resource_create(screen, &vb);
+        r300->dummy_vb.buffer.resource = screen->resource_create(screen, &vb);
         r300->context.set_vertex_buffers(&r300->context, 0, 1, &r300->dummy_vb);
     }
 
     {
         struct pipe_depth_stencil_alpha_state dsa;
         memset(&dsa, 0, sizeof(dsa));
         dsa.depth.writemask = 1;
 
         r300->dsa_decompress_zmask =
             r300->context.create_depth_stencil_alpha_state(&r300->context,
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c
index 671aa62..63f12de 100644
--- a/src/gallium/drivers/r300/r300_emit.c
+++ b/src/gallium/drivers/r300/r300_emit.c
@@ -959,21 +959,21 @@ void r300_emit_vertex_arrays(struct r300_context* r300, int offset,
 
         if (vertex_array_count & 1) {
             vb1 = &vbuf[velem[i].vertex_buffer_index];
             size1 = hw_format_size[i];
 
             OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(vb1->stride));
             OUT_CS(vb1->buffer_offset + velem[i].src_offset + offset * vb1->stride);
         }
 
         for (i = 0; i < vertex_array_count; i++) {
-            buf = r300_resource(vbuf[velem[i].vertex_buffer_index].buffer);
+            buf = r300_resource(vbuf[velem[i].vertex_buffer_index].buffer.resource);
             OUT_CS_RELOC(buf);
         }
     } else {
         /* Instanced arrays. */
         for (i = 0; i < vertex_array_count - 1; i += 2) {
             vb1 = &vbuf[velem[i].vertex_buffer_index];
             vb2 = &vbuf[velem[i+1].vertex_buffer_index];
             size1 = hw_format_size[i];
             size2 = hw_format_size[i+1];
 
@@ -1011,21 +1011,21 @@ void r300_emit_vertex_arrays(struct r300_context* r300, int offset,
             } else {
                 stride1 = vb1->stride;
                 offset1 = vb1->buffer_offset + velem[i].src_offset + offset * vb1->stride;
             }
 
             OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(stride1));
             OUT_CS(offset1);
         }
 
         for (i = 0; i < vertex_array_count; i++) {
-            buf = r300_resource(vbuf[velem[i].vertex_buffer_index].buffer);
+            buf = r300_resource(vbuf[velem[i].vertex_buffer_index].buffer.resource);
             OUT_CS_RELOC(buf);
         }
     }
     END_CS;
 }
 
 void r300_emit_vertex_arrays_swtcl(struct r300_context *r300, boolean indexed)
 {
     CS_LOCALS(r300);
 
@@ -1374,21 +1374,21 @@ validate:
                                  RADEON_DOMAIN_GTT,
                                 RADEON_PRIO_VERTEX_BUFFER);
     /* ...vertex buffers for HWTCL path... */
     if (do_validate_vertex_buffers && r300->vertex_arrays_dirty) {
         struct pipe_vertex_buffer *vbuf = r300->vertex_buffer;
         struct pipe_vertex_buffer *last = r300->vertex_buffer +
                                       r300->nr_vertex_buffers;
         struct pipe_resource *buf;
 
         for (; vbuf != last; vbuf++) {
-            buf = vbuf->buffer;
+            buf = vbuf->buffer.resource;
             if (!buf)
                 continue;
 
             r300->rws->cs_add_buffer(r300->cs, r300_resource(buf)->buf,
                                     RADEON_USAGE_READ | RADEON_USAGE_SYNCHRONIZED,
                                     r300_resource(buf)->domain,
                                     RADEON_PRIO_SAMPLER_BUFFER);
         }
     }
     /* ...and index buffer for HWTCL path. */
diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c
index 9702a2e..1d3e676 100644
--- a/src/gallium/drivers/r300/r300_render.c
+++ b/src/gallium/drivers/r300/r300_render.c
@@ -366,21 +366,21 @@ static void r300_draw_arrays_immediate(struct r300_context *r300,
     for (i = 0; i < vertex_element_count; i++) {
         velem = &r300->velems->velem[i];
         size[i] = r300->velems->format_size[i] / 4;
         vbi = velem->vertex_buffer_index;
         vbuf = &r300->vertex_buffer[vbi];
         stride[i] = vbuf->stride / 4;
 
         /* Map the buffer. */
         if (!map[vbi]) {
             map[vbi] = (uint32_t*)r300->rws->buffer_map(
-                r300_resource(vbuf->buffer)->buf,
+                r300_resource(vbuf->buffer.resource)->buf,
                 r300->cs, PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED);
             map[vbi] += (vbuf->buffer_offset / 4) + stride[i] * info->start;
         }
         mapelem[i] = map[vbi] + (velem->src_offset / 4);
     }
 
     r300_emit_draw_init(r300, info->mode, info->count-1);
 
     BEGIN_CS(dwords);
     OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size);
@@ -734,27 +734,27 @@ static unsigned r300_max_vertex_count(struct r300_context *r300)
    unsigned i, nr = r300->velems->count;
    struct pipe_vertex_element *velems = r300->velems->velem;
    unsigned result = ~0;
 
    for (i = 0; i < nr; i++) {
       struct pipe_vertex_buffer *vb =
             &r300->vertex_buffer[velems[i].vertex_buffer_index];
       unsigned size, max_count, value;
 
       /* We're not interested in constant and per-instance attribs. */
-      if (!vb->buffer ||
+      if (!vb->buffer.resource ||
           !vb->stride ||
           velems[i].instance_divisor) {
          continue;
       }
 
-      size = vb->buffer->width0;
+      size = vb->buffer.resource->width0;
 
       /* Subtract buffer_offset. */
       value = vb->buffer_offset;
       if (value >= size) {
          return 0;
       }
       size -= value;
 
       /* Subtract src_offset. */
       value = velems[i].src_offset;
diff --git a/src/gallium/drivers/r300/r300_screen_buffer.c b/src/gallium/drivers/r300/r300_screen_buffer.c
index 95ada57..4af1c46 100644
--- a/src/gallium/drivers/r300/r300_screen_buffer.c
+++ b/src/gallium/drivers/r300/r300_screen_buffer.c
@@ -104,21 +104,21 @@ r300_buffer_transfer_map( struct pipe_context *context,
             new_buf = r300->rws->buffer_create(r300->rws, rbuf->b.b.width0,
                                                R300_BUFFER_ALIGNMENT,
                                                rbuf->domain, 0);
             if (new_buf) {
                 /* Discard the old buffer. */
                 pb_reference(&rbuf->buf, NULL);
                 rbuf->buf = new_buf;
 
                 /* We changed the buffer, now we need to bind it where the old one was bound. */
                 for (i = 0; i < r300->nr_vertex_buffers; i++) {
-                    if (r300->vertex_buffer[i].buffer == &rbuf->b.b) {
+                    if (r300->vertex_buffer[i].buffer.resource == &rbuf->b.b) {
                         r300->vertex_arrays_dirty = TRUE;
                         break;
                     }
                 }
             }
         }
     }
 
     /* Buffers are never used for write, therefore mapping for read can be
      * unsynchronized. */
diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c
index 709cbd1..b3bfafd 100644
--- a/src/gallium/drivers/r300/r300_state.c
+++ b/src/gallium/drivers/r300/r300_state.c
@@ -1766,26 +1766,26 @@ static void r300_set_vertex_buffers_swtcl(struct pipe_context* pipe,
 
     util_set_vertex_buffers_count(r300->vertex_buffer,
                                   &r300->nr_vertex_buffers,
                                   buffers, start_slot, count);
     draw_set_vertex_buffers(r300->draw, start_slot, count, buffers);
 
     if (!buffers)
         return;
 
     for (i = 0; i < count; i++) {
-        if (buffers[i].user_buffer) {
+        if (buffers[i].is_user_buffer) {
             draw_set_mapped_vertex_buffer(r300->draw, start_slot + i,
-                                          buffers[i].user_buffer, ~0);
-        } else if (buffers[i].buffer) {
+                                          buffers[i].buffer.user, ~0);
+        } else if (buffers[i].buffer.resource) {
             draw_set_mapped_vertex_buffer(r300->draw, start_slot + i,
-                                          r300_resource(buffers[i].buffer)->malloced_buffer, ~0);
+                                          r300_resource(buffers[i].buffer.resource)->malloced_buffer, ~0);
         }
     }
 }
 
 static void r300_set_index_buffer_hwtcl(struct pipe_context* pipe,
                                         const struct pipe_index_buffer *ib)
 {
     struct r300_context* r300 = r300_context(pipe);
 
     if (ib) {
diff --git a/src/gallium/drivers/r600/evergreen_compute.c b/src/gallium/drivers/r600/evergreen_compute.c
index ca2081a..37ef105 100644
--- a/src/gallium/drivers/r600/evergreen_compute.c
+++ b/src/gallium/drivers/r600/evergreen_compute.c
@@ -139,22 +139,22 @@ static void evergreen_set_rat(struct r600_pipe_compute *pipe,
 
 static void evergreen_cs_set_vertex_buffer(struct r600_context *rctx,
 					   unsigned vb_index,
 					   unsigned offset,
 					   struct pipe_resource *buffer)
 {
 	struct r600_vertexbuf_state *state = &rctx->cs_vertex_buffer_state;
 	struct pipe_vertex_buffer *vb = &state->vb[vb_index];
 	vb->stride = 1;
 	vb->buffer_offset = offset;
-	vb->buffer = buffer;
-	vb->user_buffer = NULL;
+	vb->buffer.resource = buffer;
+	vb->is_user_buffer = false;
 
 	/* The vertex instructions in the compute shaders use the texture cache,
 	 * so we need to invalidate it. */
 	rctx->b.flags |= R600_CONTEXT_INV_VERTEX_CACHE;
 	state->enabled_mask |= 1 << vb_index;
 	state->dirty_mask |= 1 << vb_index;
 	r600_mark_atom_dirty(rctx, &state->atom);
 }
 
 static void evergreen_cs_set_constant_buffer(struct r600_context *rctx,
diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c
index 19ad504..6493501 100644
--- a/src/gallium/drivers/r600/evergreen_state.c
+++ b/src/gallium/drivers/r600/evergreen_state.c
@@ -1946,21 +1946,21 @@ static void evergreen_emit_vertex_buffers(struct r600_context *rctx,
 	struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
 	uint32_t dirty_mask = state->dirty_mask;
 
 	while (dirty_mask) {
 		struct pipe_vertex_buffer *vb;
 		struct r600_resource *rbuffer;
 		uint64_t va;
 		unsigned buffer_index = u_bit_scan(&dirty_mask);
 
 		vb = &state->vb[buffer_index];
-		rbuffer = (struct r600_resource*)vb->buffer;
+		rbuffer = (struct r600_resource*)vb->buffer.resource;
 		assert(rbuffer);
 
 		va = rbuffer->gpu_address + vb->buffer_offset;
 
 		/* fetch resources start at index 992 */
 		radeon_emit(cs, PKT3(PKT3_SET_RESOURCE, 8, 0) | pkt_flags);
 		radeon_emit(cs, (resource_offset + buffer_index) * 8);
 		radeon_emit(cs, va); /* RESOURCEi_WORD0 */
 		radeon_emit(cs, rbuffer->b.b.width0 - vb->buffer_offset - 1); /* RESOURCEi_WORD1 */
 		radeon_emit(cs, /* RESOURCEi_WORD2 */
diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c
index fc93eb0..2001cfd 100644
--- a/src/gallium/drivers/r600/r600_state.c
+++ b/src/gallium/drivers/r600/r600_state.c
@@ -1651,21 +1651,21 @@ static void r600_emit_vertex_buffers(struct r600_context *rctx, struct r600_atom
 	struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
 	uint32_t dirty_mask = rctx->vertex_buffer_state.dirty_mask;
 
 	while (dirty_mask) {
 		struct pipe_vertex_buffer *vb;
 		struct r600_resource *rbuffer;
 		unsigned offset;
 		unsigned buffer_index = u_bit_scan(&dirty_mask);
 
 		vb = &rctx->vertex_buffer_state.vb[buffer_index];
-		rbuffer = (struct r600_resource*)vb->buffer;
+		rbuffer = (struct r600_resource*)vb->buffer.resource;
 		assert(rbuffer);
 
 		offset = vb->buffer_offset;
 
 		/* fetch resources start at index 320 (OFFSET_FS) */
 		radeon_emit(cs, PKT3(PKT3_SET_RESOURCE, 7, 0));
 		radeon_emit(cs, (R600_FETCH_CONSTANTS_OFFSET_FS + buffer_index) * 7);
 		radeon_emit(cs, offset); /* RESOURCEi_WORD0 */
 		radeon_emit(cs, rbuffer->b.b.width0 - offset - 1); /* RESOURCEi_WORD1 */
 		radeon_emit(cs, /* RESOURCEi_WORD2 */
diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c
index 7b52be3..f3011c8 100644
--- a/src/gallium/drivers/r600/r600_state_common.c
+++ b/src/gallium/drivers/r600/r600_state_common.c
@@ -555,35 +555,35 @@ static void r600_set_vertex_buffers(struct pipe_context *ctx,
 	struct pipe_vertex_buffer *vb = state->vb + start_slot;
 	unsigned i;
 	uint32_t disable_mask = 0;
 	/* These are the new buffers set by this function. */
 	uint32_t new_buffer_mask = 0;
 
 	/* Set vertex buffers. */
 	if (input) {
 		for (i = 0; i < count; i++) {
 			if (memcmp(&input[i], &vb[i], sizeof(struct pipe_vertex_buffer))) {
-				if (input[i].buffer) {
+				if (input[i].buffer.resource) {
 					vb[i].stride = input[i].stride;
 					vb[i].buffer_offset = input[i].buffer_offset;
-					pipe_resource_reference(&vb[i].buffer, input[i].buffer);
+					pipe_resource_reference(&vb[i].buffer.resource, input[i].buffer.resource);
 					new_buffer_mask |= 1 << i;
-					r600_context_add_resource_size(ctx, input[i].buffer);
+					r600_context_add_resource_size(ctx, input[i].buffer.resource);
 				} else {
-					pipe_resource_reference(&vb[i].buffer, NULL);
+					pipe_resource_reference(&vb[i].buffer.resource, NULL);
 					disable_mask |= 1 << i;
 				}
 			}
 		}
 	} else {
 		for (i = 0; i < count; i++) {
-			pipe_resource_reference(&vb[i].buffer, NULL);
+			pipe_resource_reference(&vb[i].buffer.resource, NULL);
 		}
 		disable_mask = ((1ull << count) - 1);
 	}
 
 	disable_mask <<= start_slot;
 	new_buffer_mask <<= start_slot;
 
 	rctx->vertex_buffer_state.enabled_mask &= ~disable_mask;
 	rctx->vertex_buffer_state.dirty_mask &= rctx->vertex_buffer_state.enabled_mask;
 	rctx->vertex_buffer_state.enabled_mask |= new_buffer_mask;
@@ -2831,21 +2831,21 @@ static void r600_invalidate_buffer(struct pipe_context *ctx, struct pipe_resourc
 	struct r600_pipe_sampler_view *view;
 
 	/* Reallocate the buffer in the same pipe_resource. */
 	r600_alloc_resource(&rctx->screen->b, rbuffer);
 
 	/* We changed the buffer, now we need to bind it where the old one was bound. */
 	/* Vertex buffers. */
 	mask = rctx->vertex_buffer_state.enabled_mask;
 	while (mask) {
 		i = u_bit_scan(&mask);
-		if (rctx->vertex_buffer_state.vb[i].buffer == &rbuffer->b.b) {
+		if (rctx->vertex_buffer_state.vb[i].buffer.resource == &rbuffer->b.b) {
 			rctx->vertex_buffer_state.dirty_mask |= 1 << i;
 			r600_vertex_buffers_dirty(rctx);
 		}
 	}
 	/* Streamout buffers. */
 	for (i = 0; i < rctx->b.streamout.num_targets; i++) {
 		if (rctx->b.streamout.targets[i] &&
 		    rctx->b.streamout.targets[i]->b.buffer == &rbuffer->b.b) {
 			if (rctx->b.streamout.begin_emitted) {
 				r600_emit_streamout_end(&rctx->b);
diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
index fc94e43..8d34541 100644
--- a/src/gallium/drivers/radeonsi/si_descriptors.c
+++ b/src/gallium/drivers/radeonsi/si_descriptors.c
@@ -1001,25 +1001,25 @@ static void si_vertex_buffers_begin_new_cs(struct si_context *sctx)
 {
 	struct si_descriptors *desc = &sctx->vertex_buffers;
 	int count = sctx->vertex_elements ? sctx->vertex_elements->count : 0;
 	int i;
 
 	for (i = 0; i < count; i++) {
 		int vb = sctx->vertex_elements->elements[i].vertex_buffer_index;
 
 		if (vb >= ARRAY_SIZE(sctx->vertex_buffer))
 			continue;
-		if (!sctx->vertex_buffer[vb].buffer)
+		if (!sctx->vertex_buffer[vb].buffer.resource)
 			continue;
 
 		radeon_add_to_buffer_list(&sctx->b, &sctx->b.gfx,
-				      (struct r600_resource*)sctx->vertex_buffer[vb].buffer,
+				      (struct r600_resource*)sctx->vertex_buffer[vb].buffer.resource,
 				      RADEON_USAGE_READ, RADEON_PRIO_VERTEX_BUFFER);
 	}
 
 	if (!desc->buffer)
 		return;
 	radeon_add_to_buffer_list(&sctx->b, &sctx->b.gfx,
 			      desc->buffer, RADEON_USAGE_READ,
 			      RADEON_PRIO_DESCRIPTORS);
 }
 
@@ -1064,48 +1064,48 @@ bool si_upload_vertex_buffer_descriptors(struct si_context *sctx)
 
 	for (i = 0; i < count; i++) {
 		struct pipe_vertex_element *ve = &velems->elements[i];
 		struct pipe_vertex_buffer *vb;
 		struct r600_resource *rbuffer;
 		unsigned offset;
 		unsigned vbo_index = ve->vertex_buffer_index;
 		uint32_t *desc = &ptr[i*4];
 
 		vb = &sctx->vertex_buffer[vbo_index];
-		rbuffer = (struct r600_resource*)vb->buffer;
+		rbuffer = (struct r600_resource*)vb->buffer.resource;
 		if (!rbuffer) {
 			memset(desc, 0, 16);
 			continue;
 		}
 
 		offset = vb->buffer_offset + ve->src_offset;
 		va = rbuffer->gpu_address + offset;
 
 		/* Fill in T# buffer resource description */
 		desc[0] = va;
 		desc[1] = S_008F04_BASE_ADDRESS_HI(va >> 32) |
 			  S_008F04_STRIDE(vb->stride);
 
 		if (sctx->b.chip_class != VI && vb->stride) {
 			/* Round up by rounding down and adding 1 */
-			desc[2] = (vb->buffer->width0 - offset -
+			desc[2] = (vb->buffer.resource->width0 - offset -
 				   velems->format_size[i]) /
 				  vb->stride + 1;
 		} else {
-			desc[2] = vb->buffer->width0 - offset;
+			desc[2] = vb->buffer.resource->width0 - offset;
 		}
 
 		desc[3] = velems->rsrc_word3[i];
 
 		if (first_vb_use_mask & (1 << i)) {
 			radeon_add_to_buffer_list(&sctx->b, &sctx->b.gfx,
-					      (struct r600_resource*)vb->buffer,
+					      (struct r600_resource*)vb->buffer.resource,
 					      RADEON_USAGE_READ, RADEON_PRIO_VERTEX_BUFFER);
 		}
 	}
 
 	/* Don't flush the const cache. It would have a very negative effect
 	 * on performance (confirmed by testing). New descriptors are always
 	 * uploaded to a fresh new buffer, so I don't think flushing the const
 	 * cache is needed. */
 	si_mark_atom_dirty(sctx, &sctx->shader_userdata.atom);
 	if (sctx->b.chip_class >= CIK)
@@ -1651,24 +1651,24 @@ static void si_invalidate_buffer(struct pipe_context *ctx, struct pipe_resource
 	 *   2) Adding a relocation to the CS, so that it's usable.
 	 */
 
 	/* Vertex buffers. */
 	if (rbuffer->bind_history & PIPE_BIND_VERTEX_BUFFER) {
 		for (i = 0; i < num_elems; i++) {
 			int vb = sctx->vertex_elements->elements[i].vertex_buffer_index;
 
 			if (vb >= ARRAY_SIZE(sctx->vertex_buffer))
 				continue;
-			if (!sctx->vertex_buffer[vb].buffer)
+			if (!sctx->vertex_buffer[vb].buffer.resource)
 				continue;
 
-			if (sctx->vertex_buffer[vb].buffer == buf) {
+			if (sctx->vertex_buffer[vb].buffer.resource == buf) {
 				sctx->vertex_buffers_dirty = true;
 				break;
 			}
 		}
 	}
 
 	/* Streamout buffers. (other internal buffers can't be invalidated) */
 	if (rbuffer->bind_history & PIPE_BIND_STREAM_OUTPUT) {
 		for (i = SI_VS_STREAMOUT_BUF0; i <= SI_VS_STREAMOUT_BUF3; i++) {
 			struct si_buffer_resources *buffers = &sctx->rw_buffers;
diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
index 938e7fb..79c7f25 100644
--- a/src/gallium/drivers/radeonsi/si_state.c
+++ b/src/gallium/drivers/radeonsi/si_state.c
@@ -3836,49 +3836,49 @@ static void si_set_vertex_buffers(struct pipe_context *ctx,
 	struct pipe_vertex_buffer *dst = sctx->vertex_buffer + start_slot;
 	int i;
 
 	assert(start_slot + count <= ARRAY_SIZE(sctx->vertex_buffer));
 
 	if (buffers) {
 		for (i = 0; i < count; i++) {
 			const struct pipe_vertex_buffer *src = buffers + i;
 			struct pipe_vertex_buffer *dsti = dst + i;
 
-			if (unlikely(src->user_buffer)) {
+			if (unlikely(src->is_user_buffer)) {
 				/* Zero-stride attribs only. */
 				assert(src->stride == 0);
 
 				/* Assume that the user_buffer comes from
 				 * gl_current_attrib, which implies it has
 				 * 4 * 8 bytes (for dvec4 attributes).
 				 *
 				 * Use const_uploader to upload into VRAM directly.
 				 */
 				u_upload_data(sctx->b.b.const_uploader, 0, 32, 32,
-					      src->user_buffer,
+					      src->buffer.user,
 					      &dsti->buffer_offset,
-					      &dsti->buffer);
+					      &dsti->buffer.resource);
 				dsti->stride = 0;
 			} else {
-				struct pipe_resource *buf = src->buffer;
+				struct pipe_resource *buf = src->buffer.resource;
 
-				pipe_resource_reference(&dsti->buffer, buf);
+				pipe_resource_reference(&dsti->buffer.resource, buf);
 				dsti->buffer_offset = src->buffer_offset;
 				dsti->stride = src->stride;
 				r600_context_add_resource_size(ctx, buf);
 				if (buf)
 					r600_resource(buf)->bind_history |= PIPE_BIND_VERTEX_BUFFER;
 			}
 		}
 	} else {
 		for (i = 0; i < count; i++) {
-			pipe_resource_reference(&dst[i].buffer, NULL);
+			pipe_resource_reference(&dst[i].buffer.resource, NULL);
 		}
 	}
 	sctx->vertex_buffers_dirty = true;
 }
 
 static void si_set_index_buffer(struct pipe_context *ctx,
 				const struct pipe_index_buffer *ib)
 {
 	struct si_context *sctx = (struct si_context *)ctx;
 
diff --git a/src/gallium/drivers/rbug/rbug_context.c b/src/gallium/drivers/rbug/rbug_context.c
index 5d00207..91b1ac6 100644
--- a/src/gallium/drivers/rbug/rbug_context.c
+++ b/src/gallium/drivers/rbug/rbug_context.c
@@ -771,22 +771,25 @@ rbug_set_vertex_buffers(struct pipe_context *_pipe,
    struct rbug_context *rb_pipe = rbug_context(_pipe);
    struct pipe_context *pipe = rb_pipe->pipe;
    struct pipe_vertex_buffer unwrapped_buffers[PIPE_MAX_SHADER_INPUTS];
    struct pipe_vertex_buffer *buffers = NULL;
    unsigned i;
 
    mtx_lock(&rb_pipe->call_mutex);
 
    if (num_buffers && _buffers) {
       memcpy(unwrapped_buffers, _buffers, num_buffers * sizeof(*_buffers));
-      for (i = 0; i < num_buffers; i++)
-         unwrapped_buffers[i].buffer = rbug_resource_unwrap(_buffers[i].buffer);
+      for (i = 0; i < num_buffers; i++) {
+         if (!_buffers[i].is_user_buffer)
+            unwrapped_buffers[i].buffer.resource =
+               rbug_resource_unwrap(_buffers[i].buffer.resource);
+      }
       buffers = unwrapped_buffers;
    }
 
    pipe->set_vertex_buffers(pipe, start_slot,
                             num_buffers,
                             buffers);
 
    mtx_unlock(&rb_pipe->call_mutex);
 }
 
diff --git a/src/gallium/drivers/softpipe/sp_context.c b/src/gallium/drivers/softpipe/sp_context.c
index 0597301..a3ebc00 100644
--- a/src/gallium/drivers/softpipe/sp_context.c
+++ b/src/gallium/drivers/softpipe/sp_context.c
@@ -107,21 +107,21 @@ softpipe_destroy( struct pipe_context *pipe )
 
    for (sh = 0; sh < ARRAY_SIZE(softpipe->constants); sh++) {
       for (i = 0; i < ARRAY_SIZE(softpipe->constants[0]); i++) {
          if (softpipe->constants[sh][i]) {
             pipe_resource_reference(&softpipe->constants[sh][i], NULL);
          }
       }
    }
 
    for (i = 0; i < softpipe->num_vertex_buffers; i++) {
-      pipe_resource_reference(&softpipe->vertex_buffer[i].buffer, NULL);
+      pipe_vertex_buffer_unreference(&softpipe->vertex_buffer[i]);
    }
 
    tgsi_exec_machine_destroy(softpipe->fs_machine);
 
    for (i = 0; i < PIPE_SHADER_TYPES; i++) {
       FREE(softpipe->tgsi.sampler[i]);
       FREE(softpipe->tgsi.image[i]);
       FREE(softpipe->tgsi.buffer[i]);
    }
 
diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c
index 03fcf64..137ad05 100644
--- a/src/gallium/drivers/softpipe/sp_draw_arrays.c
+++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c
@@ -75,28 +75,29 @@ softpipe_draw_vbo(struct pipe_context *pipe,
    }
 
    sp->reduced_api_prim = u_reduced_prim(info->mode);
 
    if (sp->dirty) {
       softpipe_update_derived(sp, sp->reduced_api_prim);
    }
 
    /* Map vertex buffers */
    for (i = 0; i < sp->num_vertex_buffers; i++) {
-      const void *buf = sp->vertex_buffer[i].user_buffer;
+      const void *buf = sp->vertex_buffer[i].is_user_buffer ?
+                           sp->vertex_buffer[i].buffer.user : NULL;
       size_t size = ~0;
       if (!buf) {
-         if (!sp->vertex_buffer[i].buffer) {
+         if (!sp->vertex_buffer[i].buffer.resource) {
             continue;
          }
-         buf = softpipe_resource_data(sp->vertex_buffer[i].buffer);
-         size = sp->vertex_buffer[i].buffer->width0;
+         buf = softpipe_resource_data(sp->vertex_buffer[i].buffer.resource);
+         size = sp->vertex_buffer[i].buffer.resource->width0;
       }
       draw_set_mapped_vertex_buffer(draw, i, buf, size);
    }
 
    /* Map index buffer, if present */
    if (info->indexed) {
       unsigned available_space = ~0;
       mapped_indices = sp->index_buffer.user_buffer;
       if (!mapped_indices) {
          mapped_indices = softpipe_resource_data(sp->index_buffer.buffer);
diff --git a/src/gallium/drivers/svga/svga_draw.c b/src/gallium/drivers/svga/svga_draw.c
index 6de2338..6a89e66 100644
--- a/src/gallium/drivers/svga/svga_draw.c
+++ b/src/gallium/drivers/svga/svga_draw.c
@@ -67,21 +67,21 @@ svga_hwtnl_destroy(struct svga_hwtnl *hwtnl)
 {
    unsigned i, j;
 
    for (i = 0; i < PIPE_PRIM_MAX; i++) {
       for (j = 0; j < IDX_CACHE_MAX; j++) {
          pipe_resource_reference(&hwtnl->index_cache[i][j].buffer, NULL);
       }
    }
 
    for (i = 0; i < hwtnl->cmd.vbuf_count; i++)
-      pipe_resource_reference(&hwtnl->cmd.vbufs[i].buffer, NULL);
+      pipe_vertex_buffer_unreference(&hwtnl->cmd.vbufs[i]);
 
    for (i = 0; i < hwtnl->cmd.prim_count; i++)
       pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL);
 
    FREE(hwtnl);
 }
 
 
 void
 svga_hwtnl_set_flatshade(struct svga_hwtnl *hwtnl,
@@ -132,30 +132,26 @@ svga_hwtnl_vertex_decls(struct svga_hwtnl *hwtnl,
  */
 void
 svga_hwtnl_vertex_buffers(struct svga_hwtnl *hwtnl,
                           unsigned count, struct pipe_vertex_buffer *buffers)
 {
    struct pipe_vertex_buffer *dst = hwtnl->cmd.vbufs;
    const struct pipe_vertex_buffer *src = buffers;
    unsigned i;
 
    for (i = 0; i < count; i++) {
-      pipe_resource_reference(&dst[i].buffer, src[i].buffer);
-      dst[i].user_buffer = src[i].user_buffer;
-      dst[i].stride = src[i].stride;
-      dst[i].buffer_offset = src[i].buffer_offset;
+      pipe_vertex_buffer_reference(&dst[i], &src[i]);
    }
 
    /* release old buffer references */
    for ( ; i < hwtnl->cmd.vbuf_count; i++) {
-      pipe_resource_reference(&dst[i].buffer, NULL);
-      dst[i].user_buffer = NULL;  /* just to be safe */
+      pipe_vertex_buffer_unreference(&dst[i]);
       /* don't bother zeroing stride/offset fields */
    }
 
    hwtnl->cmd.vbuf_count = count;
 }
 
 
 /**
  * Determine whether the specified buffer is referred in the primitive queue,
  * for which no commands have been written yet.
@@ -168,21 +164,21 @@ svga_hwtnl_is_buffer_referred(struct svga_hwtnl *hwtnl,
 
    if (svga_buffer_is_user_buffer(buffer)) {
       return FALSE;
    }
 
    if (!hwtnl->cmd.prim_count) {
       return FALSE;
    }
 
    for (i = 0; i < hwtnl->cmd.vbuf_count; ++i) {
-      if (hwtnl->cmd.vbufs[i].buffer == buffer) {
+      if (hwtnl->cmd.vbufs[i].buffer.resource == buffer) {
          return TRUE;
       }
    }
 
    for (i = 0; i < hwtnl->cmd.prim_count; ++i) {
       if (hwtnl->cmd.prim_ib[i] == buffer) {
          return TRUE;
       }
    }
 
@@ -198,21 +194,21 @@ draw_vgpu9(struct svga_hwtnl *hwtnl)
    enum pipe_error ret;
    struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];
    struct svga_winsys_surface *ib_handle[QSZ];
    struct svga_winsys_surface *handle;
    SVGA3dVertexDecl *vdecl;
    SVGA3dPrimitiveRange *prim;
    unsigned i;
 
    for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
       unsigned j = hwtnl->cmd.vdecl_buffer_index[i];
-      handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer);
+      handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer.resource);
       if (!handle)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
       vb_handle[i] = handle;
    }
 
    for (i = 0; i < hwtnl->cmd.prim_count; i++) {
       if (hwtnl->cmd.prim_ib[i]) {
          handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]);
          if (!handle)
@@ -519,21 +515,21 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
    ret = validate_sampler_resources(svga);
    if (ret != PIPE_OK)
       return ret;
 
    ret = validate_constant_buffers(svga);
    if (ret != PIPE_OK)
       return ret;
 
    /* Get handle for each referenced vertex buffer */
    for (i = 0; i < vbuf_count; i++) {
-      struct svga_buffer *sbuf = svga_buffer(hwtnl->cmd.vbufs[i].buffer);
+      struct svga_buffer *sbuf = svga_buffer(hwtnl->cmd.vbufs[i].buffer.resource);
 
       if (sbuf) {
          assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);
          vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b.b);
          if (vbuffer_handles[i] == NULL)
             return PIPE_ERROR_OUT_OF_MEMORY;
          vbuffers[i] = &sbuf->b.b;
          last_vbuf = i;
       }
       else {
@@ -793,21 +789,21 @@ check_draw_params(struct svga_hwtnl *hwtnl,
                   unsigned min_index, unsigned max_index,
                   struct pipe_resource *ib)
 {
    unsigned i;
 
    assert(!svga_have_vgpu10(hwtnl->svga));
 
    for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
       unsigned j = hwtnl->cmd.vdecl_buffer_index[i];
       const struct pipe_vertex_buffer *vb = &hwtnl->cmd.vbufs[j];
-      unsigned size = vb->buffer ? vb->buffer->width0 : 0;
+      unsigned size = vb->buffer.resource ? vb->buffer.resource->width0 : 0;
       unsigned offset = hwtnl->cmd.vdecl[i].array.offset;
       unsigned stride = hwtnl->cmd.vdecl[i].array.stride;
       int index_bias = (int) range->indexBias + hwtnl->index_bias;
       unsigned width;
 
       if (size == 0)
          continue;
 
       assert(vb);
       assert(size);
diff --git a/src/gallium/drivers/svga/svga_pipe_vertex.c b/src/gallium/drivers/svga/svga_pipe_vertex.c
index 4b3f5d8..5243ae6 100644
--- a/src/gallium/drivers/svga/svga_pipe_vertex.c
+++ b/src/gallium/drivers/svga/svga_pipe_vertex.c
@@ -321,21 +321,21 @@ svga_delete_vertex_elements_state(struct pipe_context *pipe, void *state)
 
    FREE(velems);
    svga->hud.num_vertexelement_objects--;
 }
 
 void svga_cleanup_vertex_state( struct svga_context *svga )
 {
    unsigned i;
    
    for (i = 0 ; i < svga->curr.num_vertex_buffers; i++)
-      pipe_resource_reference(&svga->curr.vb[i].buffer, NULL);
+      pipe_vertex_buffer_unreference(&svga->curr.vb[i]);
 
    pipe_resource_reference(&svga->state.hw_draw.ib, NULL);
 
    for (i = 0; i < svga->state.hw_draw.num_vbuffers; i++)
       pipe_resource_reference(&svga->state.hw_draw.vbuffers[i], NULL);
 }
 
 
 void svga_init_vertex_functions( struct svga_context *svga )
 {
diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c
index e1b6a1c..fd6a238 100644
--- a/src/gallium/drivers/svga/svga_state_vdecl.c
+++ b/src/gallium/drivers/svga/svga_state_vdecl.c
@@ -66,42 +66,42 @@ emit_hw_vs_vdecl(struct svga_context *svga, unsigned dirty)
     * confusion.
     */
 
    for (i = 0; i < svga->curr.velems->count; i++) {
       const struct pipe_vertex_buffer *vb =
          &svga->curr.vb[ve[i].vertex_buffer_index];
       struct svga_buffer *buffer;
       unsigned int offset = vb->buffer_offset + ve[i].src_offset;
       unsigned tmp_neg_bias = 0;
 
-      if (!vb->buffer)
+      if (!vb->buffer.resource)
          continue;
 
-      buffer = svga_buffer(vb->buffer);
+      buffer = svga_buffer(vb->buffer.resource);
       if (buffer->uploaded.start > offset) {
          tmp_neg_bias = buffer->uploaded.start - offset;
          if (vb->stride)
             tmp_neg_bias = (tmp_neg_bias + vb->stride - 1) / vb->stride;
          neg_bias = MAX2(neg_bias, tmp_neg_bias);
       }
    }
 
    for (i = 0; i < svga->curr.velems->count; i++) {
       const struct pipe_vertex_buffer *vb =
          &svga->curr.vb[ve[i].vertex_buffer_index];
       unsigned usage, index;
       struct svga_buffer *buffer;
 
-      if (!vb->buffer)
+      if (!vb->buffer.resource)
          continue;
 
-      buffer = svga_buffer(vb->buffer);
+      buffer = svga_buffer(vb->buffer.resource);
       svga_generate_vdecl_semantics( i, &usage, &index );
 
       /* SVGA_NEW_VELEMENT
        */
       decls[i].identity.type = svga->curr.velems->decl_type[i];
       decls[i].identity.method = SVGA3D_DECLMETHOD_DEFAULT;
       decls[i].identity.usage = usage;
       decls[i].identity.usageIndex = index;
       decls[i].array.stride = vb->stride;
 
diff --git a/src/gallium/drivers/svga/svga_swtnl_backend.c b/src/gallium/drivers/svga/svga_swtnl_backend.c
index 576fd85..51be484 100644
--- a/src/gallium/drivers/svga/svga_swtnl_backend.c
+++ b/src/gallium/drivers/svga/svga_swtnl_backend.c
@@ -238,24 +238,24 @@ svga_vbuf_submit_state( struct svga_vbuf_render *svga_render )
 
    svga_hwtnl_vertex_decls(svga->hwtnl,
                            svga_render->vdecl_count,
                            vdecl,
                            zero,
                            svga_render->layout_id);
 
    /* Specify the vertex buffer (there's only ever one) */
    {
       struct pipe_vertex_buffer vb;
-      vb.buffer = svga_render->vbuf;
+      vb.is_user_buffer = false;
+      vb.buffer.resource = svga_render->vbuf;
       vb.buffer_offset = svga_render->vdecl_offset;
       vb.stride = vdecl[0].array.stride;
-      vb.user_buffer = NULL;
       svga_hwtnl_vertex_buffers(svga->hwtnl, 1, &vb);
    }
 
    /* We have already taken care of flatshading, so let the hwtnl
     * module use whatever is most convenient:
     */
    if (svga->state.sw.need_pipeline) {
       svga_hwtnl_set_flatshade(svga->hwtnl, FALSE, FALSE);
       svga_hwtnl_set_fillmode(svga->hwtnl, PIPE_POLYGON_MODE_FILL);
    }
diff --git a/src/gallium/drivers/svga/svga_swtnl_draw.c b/src/gallium/drivers/svga/svga_swtnl_draw.c
index 24b4f5c..76d128d 100644
--- a/src/gallium/drivers/svga/svga_swtnl_draw.c
+++ b/src/gallium/drivers/svga/svga_swtnl_draw.c
@@ -63,23 +63,23 @@ svga_swtnl_draw_vbo(struct svga_context *svga,
       svga_context_flush(svga, NULL);
       ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW);
       svga->swtnl.new_vbuf = TRUE;
       assert(ret == PIPE_OK);
    }
 
    /*
     * Map vertex buffers
     */
    for (i = 0; i < svga->curr.num_vertex_buffers; i++) {
-      if (svga->curr.vb[i].buffer) {
+      if (svga->curr.vb[i].buffer.resource) {
          map = pipe_buffer_map(&svga->pipe,
-                               svga->curr.vb[i].buffer,
+                               svga->curr.vb[i].buffer.resource,
                                PIPE_TRANSFER_READ,
                                &vb_transfer[i]);
 
          draw_set_mapped_vertex_buffer(draw, i, map, ~0);
       }
    }
    old_num_vertex_buffers = svga->curr.num_vertex_buffers;
 
    /* Map index buffer, if present */
    map = NULL;
@@ -113,21 +113,21 @@ svga_swtnl_draw_vbo(struct svga_context *svga,
 
    draw_flush(svga->swtnl.draw);
 
    /* Ensure the draw module didn't touch this */
    assert(old_num_vertex_buffers == svga->curr.num_vertex_buffers);
 
    /*
     * unmap vertex/index buffers
     */
    for (i = 0; i < svga->curr.num_vertex_buffers; i++) {
-      if (svga->curr.vb[i].buffer) {
+      if (svga->curr.vb[i].buffer.resource) {
          pipe_buffer_unmap(&svga->pipe, vb_transfer[i]);
          draw_set_mapped_vertex_buffer(draw, i, NULL, 0);
       }
    }
 
    if (ib_transfer) {
       pipe_buffer_unmap(&svga->pipe, ib_transfer);
       draw_set_indexes(draw, NULL, 0, 0);
    }
 
diff --git a/src/gallium/drivers/swr/swr_state.cpp b/src/gallium/drivers/swr/swr_state.cpp
index 56b1374..e224f20 100644
--- a/src/gallium/drivers/swr/swr_state.cpp
+++ b/src/gallium/drivers/swr/swr_state.cpp
@@ -737,22 +737,22 @@ swr_update_resource_status(struct pipe_context *pipe,
          if (fb->cbufs[i])
             swr_resource_write(fb->cbufs[i]->texture);
 
    /* depth/stencil target */
    if (fb->zsbuf)
       swr_resource_write(fb->zsbuf->texture);
 
    /* VBO vertex buffers */
    for (uint32_t i = 0; i < ctx->num_vertex_buffers; i++) {
       struct pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
-      if (!vb->user_buffer)
-         swr_resource_read(vb->buffer);
+      if (!vb->is_user_buffer)
+         swr_resource_read(vb->buffer.resource);
    }
 
    /* VBO index buffer */
    if (p_draw_info && p_draw_info->indexed) {
       struct pipe_index_buffer *ib = &ctx->index_buffer;
       if (!ib->user_buffer)
          swr_resource_read(ib->buffer);
    }
 
    /* transform feedback buffers */
@@ -1225,21 +1225,21 @@ swr_update_derived(struct pipe_context *pipe,
       /* If being called by swr_draw_vbo, copy draw details */
       struct pipe_draw_info info = {0};
       if (p_draw_info)
          info = *p_draw_info;
 
       /* We must get all the scratch space in one go */
       scratch_total = 0;
       for (UINT i = 0; i < ctx->num_vertex_buffers; i++) {
          struct pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
 
-         if (!vb->user_buffer)
+         if (!vb->is_user_buffer)
             continue;
 
          uint32_t elems, base, size;
          swr_user_vbuf_range(&info, ctx->velems, vb, i, &elems, &base, &size);
          scratch_total += AlignUp(size, 4);
       }
 
       if (scratch_total) {
          scratch = (uint8_t *)swr_copy_to_scratch_space(
                ctx, &ctx->scratch->vertex_buffer, NULL, scratch_total);
@@ -1247,44 +1247,44 @@ swr_update_derived(struct pipe_context *pipe,
 
       /* vertex buffers */
       SWR_VERTEX_BUFFER_STATE swrVertexBuffers[PIPE_MAX_ATTRIBS];
       for (UINT i = 0; i < ctx->num_vertex_buffers; i++) {
          uint32_t size, pitch, elems, partial_inbounds;
          uint32_t min_vertex_index;
          const uint8_t *p_data;
          struct pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
 
          pitch = vb->stride;
-         if (!vb->user_buffer) {
+         if (!vb->is_user_buffer) {
             /* VBO
              * size is based on buffer->width0 rather than info.max_index
              * to prevent having to validate VBO on each draw */
-            size = vb->buffer->width0;
+            size = vb->buffer.resource->width0;
             elems = size / pitch;
             partial_inbounds = size % pitch;
             min_vertex_index = 0;
 
-            p_data = swr_resource_data(vb->buffer) + vb->buffer_offset;
+            p_data = swr_resource_data(vb->buffer.resource) + vb->buffer_offset;
          } else {
             /* Client buffer
              * client memory is one-time use, re-trigger SWR_NEW_VERTEX to
              * revalidate on each draw */
             post_update_dirty_flags |= SWR_NEW_VERTEX;
 
             uint32_t base;
             swr_user_vbuf_range(&info, ctx->velems, vb, i, &elems, &base, &size);
             partial_inbounds = 0;
             min_vertex_index = info.min_index;
 
             /* Copy only needed vertices to scratch space */
             size = AlignUp(size, 4);
-            const void *ptr = (const uint8_t *) vb->user_buffer + base;
+            const void *ptr = (const uint8_t *) vb->buffer.user + base;
             memcpy(scratch, ptr, size);
             ptr = scratch;
             scratch += size;
             p_data = (const uint8_t *)ptr - base;
          }
 
          swrVertexBuffers[i] = {0};
          swrVertexBuffers[i].index = i;
          swrVertexBuffers[i].pitch = pitch;
          swrVertexBuffers[i].pData = p_data;
diff --git a/src/gallium/drivers/trace/tr_dump_state.c b/src/gallium/drivers/trace/tr_dump_state.c
index 4c6f6d6..13c0a9d 100644
--- a/src/gallium/drivers/trace/tr_dump_state.c
+++ b/src/gallium/drivers/trace/tr_dump_state.c
@@ -646,23 +646,23 @@ void trace_dump_vertex_buffer(const struct pipe_vertex_buffer *state)
       return;
 
    if (!state) {
       trace_dump_null();
       return;
    }
 
    trace_dump_struct_begin("pipe_vertex_buffer");
 
    trace_dump_member(uint, state, stride);
+   trace_dump_member(bool, state, is_user_buffer);
    trace_dump_member(uint, state, buffer_offset);
-   trace_dump_member(ptr, state, buffer);
-   trace_dump_member(ptr, state, user_buffer);
+   trace_dump_member(ptr, state, buffer.resource);
 
    trace_dump_struct_end();
 }
 
 
 void trace_dump_index_buffer(const struct pipe_index_buffer *state)
 {
    if (!trace_dumping_enabled_locked())
       return;
 
diff --git a/src/gallium/drivers/vc4/vc4_draw.c b/src/gallium/drivers/vc4/vc4_draw.c
index 61694ec..01fae27 100644
--- a/src/gallium/drivers/vc4/vc4_draw.c
+++ b/src/gallium/drivers/vc4/vc4_draw.c
@@ -179,21 +179,21 @@ vc4_emit_gl_shader_state(struct vc4_context *vc4,
         cl_u8(&shader_rec, vc4->prog.cs->vattrs_live);
         cl_u8(&shader_rec, vc4->prog.cs->vattr_offsets[8]);
         cl_reloc(job, &job->shader_rec, &shader_rec, vc4->prog.cs->bo, 0);
         cl_u32(&shader_rec, 0); /* UBO offset written by kernel */
 
         uint32_t max_index = 0xffff;
         for (int i = 0; i < vtx->num_elements; i++) {
                 struct pipe_vertex_element *elem = &vtx->pipe[i];
                 struct pipe_vertex_buffer *vb =
                         &vertexbuf->vb[elem->vertex_buffer_index];
-                struct vc4_resource *rsc = vc4_resource(vb->buffer);
+                struct vc4_resource *rsc = vc4_resource(vb->buffer.resource);
                 /* not vc4->dirty tracked: vc4->last_index_bias */
                 uint32_t offset = (vb->buffer_offset +
                                    elem->src_offset +
                                    vb->stride * (info->index_bias +
                                                  extra_index_bias));
                 uint32_t vb_size = rsc->bo->size - offset;
                 uint32_t elem_size =
                         util_format_get_blocksize(elem->src_format);
 
                 cl_reloc(job, &job->shader_rec, &shader_rec, rsc->bo, offset);
diff --git a/src/gallium/drivers/virgl/virgl_context.c b/src/gallium/drivers/virgl/virgl_context.c
index 25b24c8..8d7094f 100644
--- a/src/gallium/drivers/virgl/virgl_context.c
+++ b/src/gallium/drivers/virgl/virgl_context.c
@@ -117,21 +117,21 @@ static void virgl_attach_res_sampler_views(struct virgl_context *vctx,
    }
 }
 
 static void virgl_attach_res_vertex_buffers(struct virgl_context *vctx)
 {
    struct virgl_winsys *vws = virgl_screen(vctx->base.screen)->vws;
    struct virgl_resource *res;
    unsigned i;
 
    for (i = 0; i < vctx->num_vertex_buffers; i++) {
-      res = virgl_resource(vctx->vertex_buffer[i].buffer);
+      res = virgl_resource(vctx->vertex_buffer[i].buffer.resource);
       if (res)
          vws->emit_res(vws, vctx->cbuf, res->hw_res, FALSE);
    }
 }
 
 static void virgl_attach_res_index_buffer(struct virgl_context *vctx)
 {
    struct virgl_winsys *vws = virgl_screen(vctx->base.screen)->vws;
    struct virgl_resource *res;
 
diff --git a/src/gallium/drivers/virgl/virgl_encode.c b/src/gallium/drivers/virgl/virgl_encode.c
index cbe8d19..8a6a5fb 100644
--- a/src/gallium/drivers/virgl/virgl_encode.c
+++ b/src/gallium/drivers/virgl/virgl_encode.c
@@ -382,21 +382,21 @@ int virgl_encoder_create_vertex_elements(struct virgl_context *ctx,
    return 0;
 }
 
 int virgl_encoder_set_vertex_buffers(struct virgl_context *ctx,
                                     unsigned num_buffers,
                                     const struct pipe_vertex_buffer *buffers)
 {
    int i;
    virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_SET_VERTEX_BUFFERS, 0, VIRGL_SET_VERTEX_BUFFERS_SIZE(num_buffers)));
    for (i = 0; i < num_buffers; i++) {
-      struct virgl_resource *res = virgl_resource(buffers[i].buffer);
+      struct virgl_resource *res = virgl_resource(buffers[i].buffer.resource);
       virgl_encoder_write_dword(ctx->cbuf, buffers[i].stride);
       virgl_encoder_write_dword(ctx->cbuf, buffers[i].buffer_offset);
       virgl_encoder_write_res(ctx, res);
    }
    return 0;
 }
 
 int virgl_encoder_set_index_buffer(struct virgl_context *ctx,
                                   const struct pipe_index_buffer *ib)
 {
diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
index ce9ca34..0c9b4b4 100644
--- a/src/gallium/include/pipe/p_state.h
+++ b/src/gallium/include/pipe/p_state.h
@@ -527,32 +527,35 @@ struct pipe_transfer
 {
    struct pipe_resource *resource; /**< resource to transfer to/from  */
    unsigned level;                 /**< texture mipmap level */
    enum pipe_transfer_usage usage;
    struct pipe_box box;            /**< region of the resource to access */
    unsigned stride;                /**< row stride in bytes */
    unsigned layer_stride;          /**< image/layer stride in bytes */
 };
 
 
-
 /**
  * A vertex buffer.  Typically, all the vertex data/attributes for
  * drawing something will be in one buffer.  But it's also possible, for
  * example, to put colors in one buffer and texcoords in another.
  */
 struct pipe_vertex_buffer
 {
-   unsigned stride;    /**< stride to same attrib in next vertex, in bytes */
+   uint16_t stride;    /**< stride to same attrib in next vertex, in bytes */
+   bool is_user_buffer;
    unsigned buffer_offset;  /**< offset to start of data in buffer, in bytes */
-   struct pipe_resource *buffer;  /**< the actual buffer */
-   const void *user_buffer;  /**< pointer to a user buffer if buffer == NULL */
+
+   union {
+      struct pipe_resource *resource;  /**< the actual buffer */
+      const void *user;  /**< pointer to a user buffer */
+   } buffer;
 };
 
 
 /**
  * A constant buffer.  A subrange of an existing buffer can be set
  * as a constant buffer.
  */
 struct pipe_constant_buffer
 {
    struct pipe_resource *buffer; /**< the actual buffer */
diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c
index 4943658..6f97ddd 100644
--- a/src/gallium/state_trackers/nine/device9.c
+++ b/src/gallium/state_trackers/nine/device9.c
@@ -2808,40 +2808,41 @@ NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This,
     DBG("iface %p, PrimitiveType %u, PrimitiveCount %u, data %p, stride %u\n",
         This, PrimitiveType, PrimitiveCount,
         pVertexStreamZeroData, VertexStreamZeroStride);
 
     user_assert(pVertexStreamZeroData && VertexStreamZeroStride,
                 D3DERR_INVALIDCALL);
     user_assert(PrimitiveCount, D3D_OK);
 
     vtxbuf.stride = VertexStreamZeroStride;
     vtxbuf.buffer_offset = 0;
-    vtxbuf.buffer = NULL;
-    vtxbuf.user_buffer = pVertexStreamZeroData;
+    vtxbuf.is_user_buffer = true;
+    vtxbuf.buffer.user = pVertexStreamZeroData;
 
     if (!This->driver_caps.user_vbufs) {
+        vtxbuf.is_user_buffer = false;
+        vtxbuf.buffer.resource = NULL;
         u_upload_data(This->vertex_uploader,
                       0,
                       (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * VertexStreamZeroStride, /* XXX */
                       4,
-                      vtxbuf.user_buffer,
+                      pVertexStreamZeroData,
                       &vtxbuf.buffer_offset,
-                      &vtxbuf.buffer);
+                      &vtxbuf.buffer.resource);
         u_upload_unmap(This->vertex_uploader);
-        vtxbuf.user_buffer = NULL;
     }
 
     NineBeforeDraw(This);
     nine_context_draw_primitive_from_vtxbuf(This, PrimitiveType, PrimitiveCount, &vtxbuf);
     NineAfterDraw(This);
 
-    pipe_resource_reference(&vtxbuf.buffer, NULL);
+    pipe_vertex_buffer_unreference(&vtxbuf);
 
     NineDevice9_PauseRecording(This);
     NineDevice9_SetStreamSource(This, 0, NULL, 0, 0);
     NineDevice9_ResumeRecording(This);
 
     return D3D_OK;
 }
 
 HRESULT NINE_WINAPI
 NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
@@ -2865,41 +2866,42 @@ NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
         pVertexStreamZeroData, VertexStreamZeroStride);
 
     user_assert(pIndexData && pVertexStreamZeroData, D3DERR_INVALIDCALL);
     user_assert(VertexStreamZeroStride, D3DERR_INVALIDCALL);
     user_assert(IndexDataFormat == D3DFMT_INDEX16 ||
                 IndexDataFormat == D3DFMT_INDEX32, D3DERR_INVALIDCALL);
     user_assert(PrimitiveCount, D3D_OK);
 
     vbuf.stride = VertexStreamZeroStride;
     vbuf.buffer_offset = 0;
-    vbuf.buffer = NULL;
-    vbuf.user_buffer = pVertexStreamZeroData;
+    vbuf.is_user_buffer = true;
+    vbuf.buffer.user = pVertexStreamZeroData;
 
     ibuf.index_size = (IndexDataFormat == D3DFMT_INDEX16) ? 2 : 4;
     ibuf.offset = 0;
     ibuf.buffer = NULL;
     ibuf.user_buffer = pIndexData;
 
     if (!This->driver_caps.user_vbufs) {
         const unsigned base = MinVertexIndex * VertexStreamZeroStride;
+        vbuf.is_user_buffer = false;
+        vbuf.buffer.resource = NULL;
         u_upload_data(This->vertex_uploader,
                       base,
                       NumVertices * VertexStreamZeroStride, /* XXX */
                       4,
-                      (const uint8_t *)vbuf.user_buffer + base,
+                      (const uint8_t *)pVertexStreamZeroData + base,
                       &vbuf.buffer_offset,
-                      &vbuf.buffer);
+                      &vbuf.buffer.resource);
         u_upload_unmap(This->vertex_uploader);
         /* Won't be used: */
         vbuf.buffer_offset -= base;
-        vbuf.user_buffer = NULL;
     }
     if (This->csmt_active) {
         u_upload_data(This->pipe_secondary->stream_uploader,
                       0,
                       (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * ibuf.index_size,
                       4,
                       ibuf.user_buffer,
                       &ibuf.offset,
                       &ibuf.buffer);
         u_upload_unmap(This->pipe_secondary->stream_uploader);
@@ -2908,21 +2910,21 @@ NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
 
     NineBeforeDraw(This);
     nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf(This, PrimitiveType,
                                                            MinVertexIndex,
                                                            NumVertices,
                                                            PrimitiveCount,
                                                            &vbuf,
                                                            &ibuf);
     NineAfterDraw(This);
 
-    pipe_resource_reference(&vbuf.buffer, NULL);
+    pipe_vertex_buffer_unreference(&vbuf);
     pipe_resource_reference(&ibuf.buffer, NULL);
 
     NineDevice9_PauseRecording(This);
     NineDevice9_SetIndices(This, NULL);
     NineDevice9_SetStreamSource(This, 0, NULL, 0, 0);
     NineDevice9_ResumeRecording(This);
 
     return D3D_OK;
 }
 
diff --git a/src/gallium/state_trackers/nine/nine_csmt_helper.h b/src/gallium/state_trackers/nine/nine_csmt_helper.h
index dc46bbd..7286cc3 100644
--- a/src/gallium/state_trackers/nine/nine_csmt_helper.h
+++ b/src/gallium/state_trackers/nine/nine_csmt_helper.h
@@ -395,21 +395,32 @@ name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) )
         args->_##y.dst.resource = NULL; \
         pipe_resource_reference(&args->_##y.src.resource, y->src.resource); \
         pipe_resource_reference(&args->_##y.dst.resource, y->dst.resource);,\
         x *y ,\
         &args->_##y ,\
         pipe_resource_reference(&args->_##y.src.resource, NULL); \
         pipe_resource_reference(&args->_##y.dst.resource, NULL);,\
         ,\
         y
 
-#define ARG_BIND_BUF(x, y) \
+#define ARG_BIND_VBUF(x, y) \
+        x _##y ,\
+        memcpy(&args->_##y , y, sizeof(x)); \
+        args->_##y.buffer.resource = NULL; \
+        pipe_resource_reference(&args->_##y.buffer.resource, y->buffer.resource); ,\
+        x *y ,\
+        &args->_##y ,\
+        pipe_resource_reference(&args->_##y.buffer.resource, NULL); ,\
+        ,\
+        y
+
+#define ARG_BIND_IBUF(x, y) \
         x _##y ,\
         memcpy(&args->_##y , y, sizeof(x)); \
         args->_##y.buffer = NULL; \
         pipe_resource_reference(&args->_##y.buffer, y->buffer); ,\
         x *y ,\
         &args->_##y ,\
         pipe_resource_reference(&args->_##y.buffer, NULL); ,\
         ,\
         y
 
diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c
index 26c21f2..2046d9d 100644
--- a/src/gallium/state_trackers/nine/nine_state.c
+++ b/src/gallium/state_trackers/nine/nine_state.c
@@ -892,34 +892,34 @@ update_vertex_buffers(struct NineDevice9 *device)
     struct nine_context *context = &device->context;
     struct pipe_context *pipe = context->pipe;
     struct pipe_vertex_buffer dummy_vtxbuf;
     uint32_t mask = context->changed.vtxbuf;
     unsigned i;
 
     DBG("mask=%x\n", mask);
 
     if (context->dummy_vbo_bound_at >= 0) {
         if (!context->vbo_bound_done) {
-            dummy_vtxbuf.buffer = device->dummy_vbo;
+            dummy_vtxbuf.buffer.resource = device->dummy_vbo;
             dummy_vtxbuf.stride = 0;
-            dummy_vtxbuf.user_buffer = NULL;
+            dummy_vtxbuf.is_user_buffer = false;
             dummy_vtxbuf.buffer_offset = 0;
             pipe->set_vertex_buffers(pipe, context->dummy_vbo_bound_at,
                                      1, &dummy_vtxbuf);
             context->vbo_bound_done = TRUE;
         }
         mask &= ~(1 << context->dummy_vbo_bound_at);
     }
 
     for (i = 0; mask; mask >>= 1, ++i) {
         if (mask & 1) {
-            if (context->vtxbuf[i].buffer)
+            if (context->vtxbuf[i].buffer.resource)
                 pipe->set_vertex_buffers(pipe, i, 1, &context->vtxbuf[i]);
             else
                 pipe->set_vertex_buffers(pipe, i, 1, NULL);
         }
     }
 
     context->changed.vtxbuf = 0;
 }
 
 static inline boolean
@@ -1519,21 +1519,21 @@ CSMT_ITEM_NO_WAIT(nine_context_set_stream_source_apply,
                   ARG_VAL(UINT, StreamNumber),
                   ARG_BIND_RES(struct pipe_resource, res),
                   ARG_VAL(UINT, OffsetInBytes),
                   ARG_VAL(UINT, Stride))
 {
     struct nine_context *context = &device->context;
     const unsigned i = StreamNumber;
 
     context->vtxbuf[i].stride = Stride;
     context->vtxbuf[i].buffer_offset = OffsetInBytes;
-    pipe_resource_reference(&context->vtxbuf[i].buffer, res);
+    pipe_resource_reference(&context->vtxbuf[i].buffer.resource, res);
 
     context->changed.vtxbuf |= 1 << StreamNumber;
 }
 
 void
 nine_context_set_stream_source(struct NineDevice9 *device,
                                UINT StreamNumber,
                                struct NineVertexBuffer9 *pVBuf9,
                                UINT OffsetInBytes,
                                UINT Stride)
@@ -2602,21 +2602,21 @@ CSMT_ITEM_NO_WAIT(nine_context_draw_indexed_primitive,
     /* These don't include index bias: */
     info.min_index = MinVertexIndex;
     info.max_index = MinVertexIndex + NumVertices - 1;
 
     context->pipe->draw_vbo(context->pipe, &info);
 }
 
 CSMT_ITEM_NO_WAIT(nine_context_draw_primitive_from_vtxbuf,
                   ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType),
                   ARG_VAL(UINT, PrimitiveCount),
-                  ARG_BIND_BUF(struct pipe_vertex_buffer, vtxbuf))
+                  ARG_BIND_VBUF(struct pipe_vertex_buffer, vtxbuf))
 {
     struct nine_context *context = &device->context;
     struct pipe_draw_info info;
 
     nine_update_state(device);
 
     init_draw_info(&info, device, PrimitiveType, PrimitiveCount);
     info.indexed = FALSE;
     info.start = 0;
     info.index_bias = 0;
@@ -2626,22 +2626,22 @@ CSMT_ITEM_NO_WAIT(nine_context_draw_primitive_from_vtxbuf,
     context->pipe->set_vertex_buffers(context->pipe, 0, 1, vtxbuf);
 
     context->pipe->draw_vbo(context->pipe, &info);
 }
 
 CSMT_ITEM_NO_WAIT(nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf,
                   ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType),
                   ARG_VAL(UINT, MinVertexIndex),
                   ARG_VAL(UINT, NumVertices),
                   ARG_VAL(UINT, PrimitiveCount),
-                  ARG_BIND_BUF(struct pipe_vertex_buffer, vbuf),
-                  ARG_BIND_BUF(struct pipe_index_buffer, ibuf))
+                  ARG_BIND_VBUF(struct pipe_vertex_buffer, vbuf),
+                  ARG_BIND_IBUF(struct pipe_index_buffer, ibuf))
 {
     struct nine_context *context = &device->context;
     struct pipe_draw_info info;
 
     nine_update_state(device);
 
     init_draw_info(&info, device, PrimitiveType, PrimitiveCount);
     info.indexed = TRUE;
     info.start = 0;
     info.index_bias = 0;
@@ -3138,21 +3138,21 @@ nine_context_clear(struct NineDevice9 *device)
     pipe->set_vertex_buffers(pipe, 0, device->caps.MaxStreams, NULL);
     pipe->set_index_buffer(pipe, NULL);
 
     for (i = 0; i < ARRAY_SIZE(context->rt); ++i)
        nine_bind(&context->rt[i], NULL);
     nine_bind(&context->ds, NULL);
     nine_bind(&context->vs, NULL);
     nine_bind(&context->ps, NULL);
     nine_bind(&context->vdecl, NULL);
     for (i = 0; i < PIPE_MAX_ATTRIBS; ++i)
-        pipe_resource_reference(&context->vtxbuf[i].buffer, NULL);
+        pipe_vertex_buffer_unreference(&context->vtxbuf[i]);
     pipe_resource_reference(&context->idxbuf.buffer, NULL);
 
     for (i = 0; i < NINE_MAX_SAMPLERS; ++i) {
         context->texture[i].enabled = FALSE;
         pipe_resource_reference(&context->texture[i].resource,
                                 NULL);
         pipe_sampler_view_reference(&context->texture[i].view[0],
                                     NULL);
         pipe_sampler_view_reference(&context->texture[i].view[1],
                                     NULL);
@@ -3276,47 +3276,50 @@ update_vertex_buffers_sw(struct NineDevice9 *device, int start_vertice, int num_
     DBG("mask=%x\n", mask);
 
     /* TODO: handle dummy_vbo_bound_at */
 
     for (i = 0; mask; mask >>= 1, ++i) {
         if (mask & 1) {
             if (state->stream[i]) {
                 unsigned offset;
                 struct pipe_resource *buf;
                 struct pipe_box box;
+                void *userbuf;
 
                 vtxbuf = state->vtxbuf[i];
-                vtxbuf.buffer = NineVertexBuffer9_GetResource(state->stream[i], &offset);
+                buf = NineVertexBuffer9_GetResource(state->stream[i], &offset);
 
-                DBG("Locking %p (offset %d, length %d)\n", vtxbuf.buffer,
+                DBG("Locking %p (offset %d, length %d)\n", buf,
                     vtxbuf.buffer_offset, num_vertices * vtxbuf.stride);
 
                 u_box_1d(vtxbuf.buffer_offset + offset + start_vertice * vtxbuf.stride,
                          num_vertices * vtxbuf.stride, &box);
-                buf = vtxbuf.buffer;
-                vtxbuf.user_buffer = pipe->transfer_map(pipe, buf, 0, PIPE_TRANSFER_READ, &box,
-                                                        &(sw_internal->transfers_so[i]));
-                vtxbuf.buffer = NULL;
+
+                userbuf = pipe->transfer_map(pipe, buf, 0, PIPE_TRANSFER_READ, &box,
+                                             &(sw_internal->transfers_so[i]));
+                vtxbuf.is_user_buffer = true;
+                vtxbuf.buffer.user = userbuf;
+
                 if (!device->driver_caps.user_sw_vbufs) {
+                    vtxbuf.buffer.resource = NULL;
+                    vtxbuf.is_user_buffer = false;
                     u_upload_data(device->pipe_sw->stream_uploader,
                                   0,
                                   box.width,
                                   16,
-                                  vtxbuf.user_buffer,
+                                  userbuf,
                                   &(vtxbuf.buffer_offset),
-                                  &(vtxbuf.buffer));
+                                  &(vtxbuf.buffer.resource));
                     u_upload_unmap(device->pipe_sw->stream_uploader);
-                    vtxbuf.user_buffer = NULL;
                 }
                 pipe_sw->set_vertex_buffers(pipe_sw, i, 1, &vtxbuf);
-                if (vtxbuf.buffer)
-                    pipe_resource_reference(&vtxbuf.buffer, NULL);
+                pipe_vertex_buffer_unreference(&vtxbuf);
             } else
                 pipe_sw->set_vertex_buffers(pipe_sw, i, 1, NULL);
         }
     }
     nine_context_get_pipe_release(device);
 }
 
 static void
 update_vs_constants_sw(struct NineDevice9 *device)
 {
diff --git a/src/mesa/state_tracker/st_atom_array.c b/src/mesa/state_tracker/st_atom_array.c
index e58cedb..b638457 100644
--- a/src/mesa/state_tracker/st_atom_array.c
+++ b/src/mesa/state_tracker/st_atom_array.c
@@ -501,42 +501,42 @@ setup_interleaved_attribs(struct st_context *st,
       init_velement_lowered(st, vp, velements, src_offset, src_format,
                             array->InstanceDivisor, 0,
                             array->Size, array->Doubles, &attr);
    }
 
    /*
     * Return the vbuffer info and setup user-space attrib info, if needed.
     */
    if (vpv->num_inputs == 0) {
       /* just defensive coding here */
-      vbuffer->buffer = NULL;
-      vbuffer->user_buffer = NULL;
+      vbuffer->buffer.resource = NULL;
+      vbuffer->is_user_buffer = false;
       vbuffer->buffer_offset = 0;
       vbuffer->stride = 0;
    }
    else if (usingVBO) {
       /* all interleaved arrays in a VBO */
       struct st_buffer_object *stobj = st_buffer_object(bufobj);
 
       if (!stobj || !stobj->buffer) {
          return FALSE; /* out-of-memory error probably */
       }
 
-      vbuffer->buffer = stobj->buffer;
-      vbuffer->user_buffer = NULL;
+      vbuffer->buffer.resource = stobj->buffer;
+      vbuffer->is_user_buffer = false;
       vbuffer->buffer_offset = pointer_to_offset(low_addr);
       vbuffer->stride = stride;
    }
    else {
       /* all interleaved arrays in user memory */
-      vbuffer->buffer = NULL;
-      vbuffer->user_buffer = low_addr;
+      vbuffer->buffer.user = low_addr;
+      vbuffer->is_user_buffer = !!low_addr; /* if NULL, then unbind */
       vbuffer->buffer_offset = 0;
       vbuffer->stride = stride;
    }
    return TRUE;
 }
 
 /**
  * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each
  * vertex attribute.
  * \param vbuffer  returns vertex buffer info
@@ -578,41 +578,41 @@ setup_non_interleaved_attribs(struct st_context *st,
          /* Attribute data is in a VBO.
           * Recall that for VBOs, the gl_vertex_array->Ptr field is
           * really an offset from the start of the VBO, not a pointer.
           */
          struct st_buffer_object *stobj = st_buffer_object(bufobj);
 
          if (!stobj || !stobj->buffer) {
             return FALSE; /* out-of-memory error probably */
          }
 
-         vbuffer[bufidx].buffer = stobj->buffer;
-         vbuffer[bufidx].user_buffer = NULL;
+         vbuffer[bufidx].buffer.resource = stobj->buffer;
+         vbuffer[bufidx].is_user_buffer = false;
          vbuffer[bufidx].buffer_offset = pointer_to_offset(array->Ptr);
       }
       else {
          /* wrap user data */
          void *ptr;
 
          if (array->Ptr) {
             ptr = (void *) array->Ptr;
          }
          else {
             /* no array, use ctx->Current.Attrib[] value */
             ptr = (void *) ctx->Current.Attrib[mesaAttr];
             stride = 0;
          }
 
          assert(ptr);
 
-         vbuffer[bufidx].buffer = NULL;
-         vbuffer[bufidx].user_buffer = ptr;
+         vbuffer[bufidx].buffer.user = ptr;
+         vbuffer[bufidx].is_user_buffer = !!ptr; /* if NULL, then unbind */
          vbuffer[bufidx].buffer_offset = 0;
       }
 
       /* common-case setup */
       vbuffer[bufidx].stride = stride; /* in bytes */
 
       src_format = st_pipe_vertex_format(array->Type,
                                          array->Size,
                                          array->Format,
                                          array->Normalized,
diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c
index e0745f4..9e83c0e 100644
--- a/src/mesa/state_tracker/st_cb_bitmap.c
+++ b/src/mesa/state_tracker/st_cb_bitmap.c
@@ -687,21 +687,21 @@ st_DrawAtlasBitmaps(struct gl_context *ctx,
    if (!sv) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCallLists(bitmap text)");
       return;
    }
 
    setup_render_state(ctx, sv, color, true);
 
    vb.stride = sizeof(struct st_util_vertex);
 
    u_upload_alloc(pipe->stream_uploader, 0, num_vert_bytes, 4,
-                  &vb.buffer_offset, &vb.buffer, (void **) &verts);
+                  &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
 
    if (unlikely(!verts)) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCallLists(bitmap text)");
       goto out;
    }
 
    /* build quads vertex data */
    for (i = 0; i < count; i++) {
       const GLfloat epsilon = 0.0001F;
       const struct gl_bitmap_glyph *g = &atlas->glyphs[ids[i]];
@@ -774,21 +774,21 @@ st_DrawAtlasBitmaps(struct gl_context *ctx,
 
    cso_set_vertex_buffers(st->cso_context,
                           cso_get_aux_vertex_buffer_slot(st->cso_context),
                           1, &vb);
 
    cso_draw_arrays(st->cso_context, PIPE_PRIM_QUADS, 0, num_verts);
 
 out:
    restore_render_state(ctx);
 
-   pipe_resource_reference(&vb.buffer, NULL);
+   pipe_resource_reference(&vb.buffer.resource, NULL);
 
    pipe_sampler_view_reference(&sv, NULL);
 
    /* We uploaded modified constants, need to invalidate them. */
    st->dirty |= ST_NEW_FS_CONSTANTS;
 }
 
 
 
 /** Per-context init */
diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index e510d43..5c9f7ea 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -378,22 +378,22 @@ st_draw_quad(struct st_context *st,
              const float *color,
              unsigned num_instances)
 {
    struct pipe_vertex_buffer vb = {0};
    struct st_util_vertex *verts;
 
    vb.stride = sizeof(struct st_util_vertex);
 
    u_upload_alloc(st->pipe->stream_uploader, 0,
                   4 * sizeof(struct st_util_vertex), 4,
-                  &vb.buffer_offset, &vb.buffer, (void **) &verts);
-   if (!vb.buffer) {
+                  &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
+   if (!vb.buffer.resource) {
       return false;
    }
 
    /* lower-left */
    verts[0].x = x0;
    verts[0].y = y1;
    verts[0].z = z;
    verts[0].r = color[0];
    verts[0].g = color[1];
    verts[0].b = color[2];
@@ -446,14 +446,14 @@ st_draw_quad(struct st_context *st,
                           cso_get_aux_vertex_buffer_slot(st->cso_context),
                           1, &vb);
 
    if (num_instances > 1) {
       cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4,
                                 0, num_instances);
    } else {
       cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4);
    }
 
-   pipe_resource_reference(&vb.buffer, NULL);
+   pipe_resource_reference(&vb.buffer.resource, NULL);
 
    return true;
 }
diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c
index 9d68777..ad92ff5 100644
--- a/src/mesa/state_tracker/st_draw_feedback.c
+++ b/src/mesa/state_tracker/st_draw_feedback.c
@@ -187,41 +187,41 @@ st_feedback_draw_vbo(struct gl_context *ctx,
       void *map;
 
       if (bufobj && bufobj->Name) {
          /* Attribute data is in a VBO.
           * Recall that for VBOs, the gl_vertex_array->Ptr field is
           * really an offset from the start of the VBO, not a pointer.
           */
          struct st_buffer_object *stobj = st_buffer_object(bufobj);
          assert(stobj->buffer);
 
-         vbuffers[attr].buffer = NULL;
-         vbuffers[attr].user_buffer = NULL;
-         pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer);
+         vbuffers[attr].buffer.resource = NULL;
+         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;
 
          /* map the attrib buffer */
-         map = pipe_buffer_map(pipe, vbuffers[attr].buffer,
+         map = pipe_buffer_map(pipe, vbuffers[attr].buffer.resource,
                                PIPE_TRANSFER_READ,
                                &vb_transfer[attr]);
          draw_set_mapped_vertex_buffer(draw, attr, map,
-                                       vbuffers[attr].buffer->width0);
+                                       vbuffers[attr].buffer.resource->width0);
       }
       else {
-         vbuffers[attr].buffer = NULL;
-         vbuffers[attr].user_buffer = arrays[mesaAttr]->Ptr;
+         vbuffers[attr].buffer.user = arrays[mesaAttr]->Ptr;
+         vbuffers[attr].is_user_buffer = true;
          vbuffers[attr].buffer_offset = 0;
          velements[attr].src_offset = 0;
 
-         draw_set_mapped_vertex_buffer(draw, attr, vbuffers[attr].user_buffer,
-                                       ~0);
+         draw_set_mapped_vertex_buffer(draw, attr,
+                                       vbuffers[attr].buffer.user, ~0);
       }
 
       /* common-case setup */
       vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* 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,
@@ -285,14 +285,14 @@ st_feedback_draw_vbo(struct gl_context *ctx,
       if (ib_transfer)
          pipe_buffer_unmap(pipe, ib_transfer);
       pipe_resource_reference(&ibuffer.buffer, NULL);
    }
 
  out_unref_vertex:
    for (attr = 0; attr < vp->num_inputs; attr++) {
       if (vb_transfer[attr])
          pipe_buffer_unmap(pipe, vb_transfer[attr]);
       draw_set_mapped_vertex_buffer(draw, attr, NULL, 0);
-      pipe_resource_reference(&vbuffers[attr].buffer, NULL);
+      pipe_vertex_buffer_unreference(&vbuffers[attr]);
    }
    draw_set_vertex_buffers(draw, 0, vp->num_inputs, NULL);
 }
diff --git a/src/mesa/state_tracker/st_pbo.c b/src/mesa/state_tracker/st_pbo.c
index 1ded583..303c853 100644
--- a/src/mesa/state_tracker/st_pbo.c
+++ b/src/mesa/state_tracker/st_pbo.c
@@ -208,36 +208,34 @@ st_pbo_draw(struct st_context *st, const struct st_pbo_addresses *addr,
    cso_set_vertex_shader_handle(cso, st->pbo.vs);
 
    cso_set_geometry_shader_handle(cso, addr->depth != 1 ? st->pbo.gs : NULL);
 
    cso_set_tessctrl_shader_handle(cso, NULL);
 
    cso_set_tesseval_shader_handle(cso, NULL);
 
    /* Upload vertices */
    {
-      struct pipe_vertex_buffer vbo;
+      struct pipe_vertex_buffer vbo = {0};
       struct pipe_vertex_element velem;
 
       float x0 = (float) addr->xoffset / surface_width * 2.0f - 1.0f;
       float y0 = (float) addr->yoffset / surface_height * 2.0f - 1.0f;
       float x1 = (float) (addr->xoffset + addr->width) / surface_width * 2.0f - 1.0f;
       float y1 = (float) (addr->yoffset + addr->height) / surface_height * 2.0f - 1.0f;
 
       float *verts = NULL;
 
-      vbo.user_buffer = NULL;
-      vbo.buffer = NULL;
       vbo.stride = 2 * sizeof(float);
 
       u_upload_alloc(st->pipe->stream_uploader, 0, 8 * sizeof(float), 4,
-                     &vbo.buffer_offset, &vbo.buffer, (void **) &verts);
+                     &vbo.buffer_offset, &vbo.buffer.resource, (void **) &verts);
       if (!verts)
          return false;
 
       verts[0] = x0;
       verts[1] = y0;
       verts[2] = x0;
       verts[3] = y1;
       verts[4] = x1;
       verts[5] = y0;
       verts[6] = x1;
@@ -247,21 +245,21 @@ st_pbo_draw(struct st_context *st, const struct st_pbo_addresses *addr,
 
       velem.src_offset = 0;
       velem.instance_divisor = 0;
       velem.vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
       velem.src_format = PIPE_FORMAT_R32G32_FLOAT;
 
       cso_set_vertex_elements(cso, 1, &velem);
 
       cso_set_vertex_buffers(cso, velem.vertex_buffer_index, 1, &vbo);
 
-      pipe_resource_reference(&vbo.buffer, NULL);
+      pipe_resource_reference(&vbo.buffer.resource, NULL);
    }
 
    /* Upload constants */
    {
       struct pipe_constant_buffer cb;
 
       if (!st->has_user_constbuf) {
          cb.buffer = NULL;
          cb.user_buffer = NULL;
          u_upload_data(st->pipe->const_uploader, 0, sizeof(addr->constants),
-- 
2.7.4



More information about the mesa-dev mailing list