First attempt at building vertex buffers post-clip.
authorKeith Whitwell <keith@tungstengraphics.com>
Tue, 25 Sep 2007 12:20:53 +0000 (13:20 +0100)
committerKeith Whitwell <keith@tungstengraphics.com>
Tue, 25 Sep 2007 12:23:20 +0000 (13:23 +0100)
Build a buffer of contigous vertices and indices at the backend of our
software transformation/clipping path.  This will become the mechanism
for emitting buffers of vertices to rasterization hardware.

This is similar to but not the same as the post-transform vertex cache.
In particular, these vertices are subject to clipping, culling, poly offset,
etc.  The vertices emitted will all be used by hardware.

TODOs include the actual transformation to hardware vertex formats, moving
this out of softpipe to somewhere more useful and allowing >1 primitive to
share the generated VB.

src/mesa/pipe/draw/draw_clip.c
src/mesa/pipe/draw/draw_prim.c
src/mesa/pipe/draw/draw_private.h
src/mesa/pipe/draw/draw_vertex_cache.c
src/mesa/pipe/draw/draw_vertex_shader.c
src/mesa/pipe/softpipe/Makefile
src/mesa/pipe/softpipe/sp_context.c
src/mesa/pipe/softpipe/sp_context.h
src/mesa/pipe/softpipe/sp_prim_setup.c
src/mesa/pipe/softpipe/sp_prim_setup.h
src/mesa/pipe/softpipe/sp_prim_vbuf.c [new file with mode: 0644]

index e2af69e04853ea2b331889f1d5eb752191a92655..3ccc408bc0b3e2ee50f8c0d4a0d747e3561326ea 100644 (file)
@@ -109,6 +109,7 @@ static void interp( const struct clipper *clip,
       dst->clipmask = 0;
       dst->edgeflag = 0;
       dst->pad = 0;
+      dst->vertex_id = 0;
    }
 
    /* Clip coordinates:  interpolate normally
index e82e48b90b8f3bf0f1868f108d3e6977e0e4fe83..be2f987b9a0f9fb2dd2a3bab2703a64db385b160 100644 (file)
@@ -106,9 +106,12 @@ void draw_flush( struct draw_context *draw )
 static struct prim_header *get_queued_prim( struct draw_context *draw,
                                            unsigned nr_verts )
 {
-   if (draw->pq.queue_nr + 1 >= PRIM_QUEUE_LENGTH ||
-       !draw_vertex_cache_check_space( draw, nr_verts )) 
-   {
+   if (draw->pq.queue_nr + 1 >= PRIM_QUEUE_LENGTH) {
+//      fprintf(stderr, "p");
+      draw_flush( draw );
+   }
+   else if (!draw_vertex_cache_check_space( draw, nr_verts )) {
+//      fprintf(stderr, "v");
       draw_flush( draw );
    }
 
index 1285f3200c8ff2ce37cfc86ee13c157c27d98d71..04d38c4e0c205030d6e31dfdfe8792f7e72446d9 100644 (file)
@@ -54,7 +54,8 @@
 struct vertex_header {
    unsigned clipmask:12;
    unsigned edgeflag:1;
-   unsigned pad:19;
+   unsigned pad:3;
+   unsigned vertex_id:16;
 
    float clip[4];
 
@@ -230,6 +231,8 @@ extern int draw_vertex_cache_check_space( struct draw_context *draw,
 extern void draw_vertex_cache_validate( struct draw_context *draw );
 extern void draw_vertex_cache_invalidate( struct draw_context *draw );
 extern void draw_vertex_cache_unreference( struct draw_context *draw );
+extern void draw_vertex_cache_reset_vertex_ids( struct draw_context *draw );
+
 
 extern void draw_vertex_shader_queue_flush( struct draw_context *draw );
 
@@ -255,6 +258,7 @@ dup_vert( struct draw_stage *stage,
 {   
    struct vertex_header *tmp = stage->tmp[idx];
    memcpy(tmp, vert, stage->draw->vertex_info.size * sizeof(float) );
+   tmp->vertex_id = ~0;
    return tmp;
 }
 
index f1b0cb14bd33cf94e9002ba86121f8aae4f4ada2..a226798123c22dd515b24ad4b20d2e00aec67805 100644 (file)
@@ -46,6 +46,8 @@ void draw_vertex_cache_invalidate( struct draw_context *draw )
    
    for (i = 0; i < Elements( draw->vcache.idx ); i++)
       draw->vcache.idx[i] = ~0;
+
+//   fprintf(stderr, "x\n");
 }
 
 
@@ -63,10 +65,14 @@ static struct vertex_header *get_vertex( struct draw_context *draw,
 
       /* If slot is in use, use the overflow area:
        */
-      if (draw->vcache.referenced & (1 << slot))
+      if (draw->vcache.referenced & (1 << slot)) {
+//         fprintf(stderr, "o");
         slot = VCACHE_SIZE + draw->vcache.overflow++;
-      else
+      }
+      else {
+//         fprintf(stderr, ".");
          draw->vcache.referenced |= (1 << slot);  /* slot now in use */
+      }
 
       draw->vcache.idx[slot] = i;
 
@@ -79,7 +85,10 @@ static struct vertex_header *get_vertex( struct draw_context *draw,
       /* Need to set the vertex's edge flag here.  If we're being called
        * by do_ef_triangle(), that function needs edge flag info!
        */
+      draw->vcache.vertex[slot]->clipmask = 0;
       draw->vcache.vertex[slot]->edgeflag = 1; /*XXX use user's edge flag! */
+      draw->vcache.vertex[slot]->pad = 0;
+      draw->vcache.vertex[slot]->vertex_id = ~0;
    }
 
    return draw->vcache.vertex[slot];
@@ -110,6 +119,13 @@ static struct vertex_header *get_ubyte_elt_vertex( struct draw_context *draw,
 }
 
 
+void draw_vertex_cache_reset_vertex_ids( struct draw_context *draw )
+{
+   unsigned i;
+
+   for (i = 0; i < Elements(draw->vcache.vertex); i++)
+      draw->vcache.vertex[i]->vertex_id = ~0;
+}
 
 void draw_vertex_cache_validate( struct draw_context *draw )
 {
index ef0399c46e5f87405871b20db3445ad8b254edf9..fe4f124dd2f0f3e59b914bb015a8faad05f1475d 100644 (file)
@@ -189,6 +189,8 @@ void draw_vertex_shader_queue_flush( struct draw_context *draw )
 {
    unsigned i, j;
 
+//   fprintf(stderr, " q(%d) ", draw->vs.queue_nr );
+
    /* run vertex shader on vertex cache entries, four per invokation */
    for (i = 0; i < draw->vs.queue_nr; i += 4) {
       struct vertex_header *dests[4];
index 0335f56b99ece06b83ef9f9da98053a85e1c0c71..63eb6b576157966ef2df5b30f48ffd8a25065547 100644 (file)
@@ -10,6 +10,7 @@ DRIVER_SOURCES = \
        sp_context.c \
        sp_draw_arrays.c \
        sp_prim_setup.c \
+       sp_prim_vbuf.c \
        sp_quad.c \
        sp_quad_alpha_test.c \
        sp_quad_blend.c \
index a6ab45314cfd3e5a32501e7e6f0c1f2cd708d116..e415966dae1429d3aa481151c2c4a5f9e2133cba 100644 (file)
@@ -334,7 +334,19 @@ struct pipe_context *softpipe_create( struct pipe_winsys *pipe_winsys,
     */
    softpipe->draw = draw_create();
    assert(softpipe->draw);
-   draw_set_rasterize_stage(softpipe->draw, sp_draw_render_stage(softpipe));
+   softpipe->setup = sp_draw_render_stage(softpipe);
+
+   if (getenv("SP_VBUF")) {
+      softpipe->vbuf = sp_draw_vbuf_stage(softpipe->draw, 
+                                          &softpipe->pipe, 
+                                          sp_vbuf_setup_draw);
+
+      draw_set_rasterize_stage(softpipe->draw, softpipe->vbuf);
+   }
+   else {
+      draw_set_rasterize_stage(softpipe->draw, softpipe->setup);
+   }
+
 
    sp_init_region_functions(softpipe);
    sp_init_surface_functions(softpipe);
index 7b1518cfaca9f4f57520b1515ac90e10615a8b7a..c0a681f3d6b30134050e2758395c3e421c15bcaf 100644 (file)
@@ -146,6 +146,8 @@ struct softpipe_context {
 
    /** The primitive drawing context */
    struct draw_context *draw;
+   struct draw_stage *setup;
+   struct draw_stage *vbuf;
 
    struct pipe_surface *cbuf;      /**< current color buffer (one of cbufs) */
 };
index 6d63cc94123d041c0740c63cee2be09abe615c59..2e27d00acfb02c4fec960caa3fbe63a67e38fd09 100644 (file)
@@ -41,7 +41,7 @@
 #include "pipe/draw/draw_vertex.h"
 #include "pipe/p_util.h"
 
-
+#define DEBUG_VERTS 0
 
 /**
  * Triangle edge info
@@ -241,15 +241,15 @@ static void flush_spans( struct setup_stage *setup )
    setup->span.right[1] = 0;
 }
 
-#if 0
+#if DEBUG_VERTS
 static void print_vertex(const struct setup_stage *setup,
                          const struct vertex_header *v)
 {
    int i;
-   printf("Vertex:\n");
+   fprintf(stderr, "Vertex: (%p)\n", v);
    for (i = 0; i < setup->quad.nr_attrs; i++) {
-      printf("  %d: %f %f %f\n",  i, 
-          v->data[i][0], v->data[i][1], v->data[i][2]);
+      fprintf(stderr, "  %d: %f %f %f %f\n",  i, 
+              v->data[i][0], v->data[i][1], v->data[i][2], v->data[i][3]);
    }
 }
 #endif
@@ -261,8 +261,8 @@ static boolean setup_sort_vertices( struct setup_stage *setup,
    const struct vertex_header *v1 = prim->v[1];
    const struct vertex_header *v2 = prim->v[2];
 
-#if 0
-   printf("Triangle:\n");
+#if DEBUG_VERTS
+   fprintf(stderr, "Triangle:\n");
    print_vertex(setup, v0);
    print_vertex(setup, v1);
    print_vertex(setup, v2);
@@ -1096,3 +1096,85 @@ struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe )
 
    return &setup->stage;
 }
+
+
+/* Recalculate det.  This is only used in the test harness below:
+ */
+static void calc_det( struct prim_header *header )
+{
+   /* Window coords: */
+   const float *v0 = header->v[0]->data[0];
+   const float *v1 = header->v[1]->data[0];
+   const float *v2 = header->v[2]->data[0];
+
+   /* edge vectors e = v0 - v2, f = v1 - v2 */
+   const float ex = v0[0] - v2[0];
+   const float ey = v0[1] - v2[1];
+   const float fx = v1[0] - v2[0];
+   const float fy = v1[1] - v2[1];
+   
+   /* det = cross(e,f).z */
+   header->det = ex * fy - ey * fx;
+}
+
+
+
+/* Test harness - feed vertex buffer back into prim pipeline.
+ *
+ * The big issue at this point is that reset_stipple doesn't make it
+ * through the interface.  Probably need to split primitives at reset
+ * stipple, perhaps using the ~0 index marker.
+ */
+void sp_vbuf_setup_draw( struct pipe_context *pipe,
+                         unsigned primitive,
+                         const ushort *elements,
+                         unsigned nr_elements,
+                         const void *vertex_buffer,
+                         unsigned nr_vertices )
+{
+   struct softpipe_context *softpipe = softpipe_context( pipe );
+   struct setup_stage *setup = setup_stage( softpipe->setup );
+   struct prim_header prim;
+   unsigned vertex_size = setup->stage.draw->vertex_info.size * sizeof(float);
+   int i, j;
+
+   prim.det = 0;
+   prim.reset_line_stipple = 0;
+   prim.edgeflags = 0;
+   prim.pad = 0;
+
+   setup->stage.begin( &setup->stage );
+
+   switch (primitive) {
+   case PIPE_PRIM_TRIANGLES:
+      for (i = 0; i < nr_elements; i += 3) {
+         for (j = 0; j < 3; j++) 
+            prim.v[j] = (struct vertex_header *)((char *)vertex_buffer + 
+                                                 elements[i+j] * vertex_size);
+         
+         calc_det(&prim);
+         setup->stage.tri( &setup->stage, &prim );
+      }
+      break;
+
+   case PIPE_PRIM_LINES:
+      for (i = 0; i < nr_elements; i += 2) {
+         for (j = 0; j < 2; j++) 
+            prim.v[j] = (struct vertex_header *)((char *)vertex_buffer + 
+                                                 elements[i+j] * vertex_size);
+         
+         setup->stage.line( &setup->stage, &prim );
+      }
+      break;
+
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < nr_elements; i += 2) {
+         prim.v[i] = (struct vertex_header *)((char *)vertex_buffer + 
+                                              elements[i] * vertex_size);         
+         setup->stage.point( &setup->stage, &prim );
+      }
+      break;
+   }
+
+   setup->stage.end( &setup->stage );
+}
index dece42fe4573de046692cdffa5161b49ca275804..598394f73ee3742004c5444f4e4deaaa3cc2d8c3 100644 (file)
@@ -44,5 +44,39 @@ struct softpipe_context;
 extern struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe );
 
 
+/* A special stage to gather the stream of triangles, lines, points
+ * together and reconstruct vertex buffers for hardware upload.
+ *
+ * First attempt, work in progress.
+ * 
+ * TODO:
+ *    - separate out vertex buffer building and primitive emit, ie >1 draw per vb.
+ *    - tell vbuf stage how to build hw vertices directly
+ *    - pass vbuf stage a buffer pointer for direct emit to agp/vram.
+ */
+typedef void (*vbuf_draw_func)( struct pipe_context *pipe,
+                                unsigned prim,
+                                const ushort *elements,
+                                unsigned nr_elements,
+                                const void *vertex_buffer,
+                                unsigned nr_vertices );
+
+
+extern struct draw_stage *sp_draw_vbuf_stage( struct draw_context *draw_context,
+                                              struct pipe_context *pipe,
+                                              vbuf_draw_func draw );
+
+
+
+/* Test harness
+ */
+void sp_vbuf_setup_draw( struct pipe_context *pipe,
+                         unsigned prim,
+                         const ushort *elements,
+                         unsigned nr_elements,
+                         const void *vertex_buffer,
+                         unsigned nr_vertices );
+
+
 
 #endif /* SP_PRIM_SETUP_H */
diff --git a/src/mesa/pipe/softpipe/sp_prim_vbuf.c b/src/mesa/pipe/softpipe/sp_prim_vbuf.c
new file mode 100644 (file)
index 0000000..235903c
--- /dev/null
@@ -0,0 +1,305 @@
+/**************************************************************************
+ * 
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 
+ **************************************************************************/
+
+/**
+ * Build post-transformation, post-clipping vertex buffers and element
+ * lists by hooking into the end of the primitive pipeline and
+ * manipulating the vertex_id field in the vertex headers.
+ *
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+#include "sp_context.h"
+#include "sp_headers.h"
+#include "sp_quad.h"
+#include "sp_prim_setup.h"
+#include "pipe/draw/draw_private.h"
+#include "pipe/draw/draw_vertex.h"
+#include "pipe/p_util.h"
+
+static void vbuf_flush_elements( struct draw_stage *stage );
+
+
+#define VBUF_SIZE (64*1024)
+#define IBUF_SIZE (16*1024)
+
+
+/**
+ * Vertex buffer emit stage.
+ */
+struct vbuf_stage {
+   struct draw_stage stage; /**< This must be first (base class) */
+
+   struct draw_context *draw_context;
+   struct pipe_context *pipe;
+   vbuf_draw_func draw;
+
+   /* Vertices are passed in as an array of floats making up each
+    * attribute in turn.  Will eventually convert to hardware format
+    * in this stage.
+    */
+   char *vertex_map;
+   char *vertex_ptr;
+   unsigned vertex_size;
+   unsigned nr_vertices;
+
+   unsigned max_vertices;
+
+   ushort *element_map;
+   unsigned nr_elements;
+
+   unsigned prim;
+   
+};
+
+/**
+ * Basically a cast wrapper.
+ */
+static INLINE struct vbuf_stage *vbuf_stage( struct draw_stage *stage )
+{
+   return (struct vbuf_stage *)stage;
+}
+
+
+
+
+static boolean overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
+{
+   unsigned long used = (char *)ptr - (char *)map;
+   return (used + bytes) > bufsz;
+}
+
+
+static boolean check_space( struct vbuf_stage *vbuf )
+{
+   if (overflow( vbuf->vertex_map, 
+                 vbuf->vertex_ptr,  
+                 4 * vbuf->vertex_size, 
+                 VBUF_SIZE ))
+      return FALSE;
+
+   
+   if (vbuf->nr_elements + 4 > IBUF_SIZE / sizeof(ushort) )
+      return FALSE;
+   
+   return TRUE;
+}
+
+
+static void emit_vertex( struct vbuf_stage *vbuf,
+                         struct vertex_header *vertex )
+{
+   fprintf(stderr, "emit vertex %d to %p\n", 
+           vbuf->nr_vertices, vbuf->vertex_ptr);
+
+   vertex->vertex_id = vbuf->nr_vertices++;
+
+   //vbuf->emit_vertex( vbuf->vertex_ptr, vertex );
+   memcpy(vbuf->vertex_ptr, vertex, vbuf->vertex_size);
+
+   vbuf->vertex_ptr += vbuf->vertex_size;
+}
+
+
+
+/**
+ * 
+ */
+static void vbuf_tri( struct draw_stage *stage,
+                      struct prim_header *prim )
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+   unsigned i;
+
+   if (!check_space( vbuf ))
+      vbuf_flush_elements( stage );
+
+   for (i = 0; i < 3; i++) {
+      if (prim->v[i]->vertex_id == 0xffff) 
+         emit_vertex( vbuf, prim->v[i] );
+      
+      vbuf->element_map[vbuf->nr_elements++] = prim->v[i]->vertex_id;
+   }
+}
+
+
+static void vbuf_line(struct draw_stage *stage, 
+                      struct prim_header *prim)
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+   unsigned i;
+
+   if (!check_space( vbuf ))
+      vbuf_flush_elements( stage );
+
+   for (i = 0; i < 2; i++) {
+      if (prim->v[i]->vertex_id == 0xffff) 
+         emit_vertex( vbuf, prim->v[i] );
+
+      vbuf->element_map[vbuf->nr_elements++] = prim->v[i]->vertex_id;
+   }   
+}
+
+
+static void vbuf_point(struct draw_stage *stage, 
+                       struct prim_header *prim)
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+
+   if (!check_space( vbuf ))
+      vbuf_flush_elements( stage );
+
+   if (prim->v[0]->vertex_id == 0xffff) 
+      emit_vertex( vbuf, prim->v[0] );
+   
+   vbuf->element_map[vbuf->nr_elements++] = prim->v[0]->vertex_id;
+}
+
+
+static void vbuf_first_tri( struct draw_stage *stage,
+                            struct prim_header *prim )
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+
+   vbuf_flush_elements( stage );   
+   stage->tri = vbuf_tri;
+   stage->tri( stage, prim );
+   vbuf->prim = PIPE_PRIM_TRIANGLES;
+}
+
+static void vbuf_first_line( struct draw_stage *stage,
+                             struct prim_header *prim )
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+
+   vbuf_flush_elements( stage );
+   stage->line = vbuf_line;
+   stage->line( stage, prim );
+   vbuf->prim = PIPE_PRIM_LINES;
+}
+
+static void vbuf_first_point( struct draw_stage *stage,
+                              struct prim_header *prim )
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+
+   vbuf_flush_elements( stage );
+   stage->point = vbuf_point;
+   stage->point( stage, prim );
+   vbuf->prim = PIPE_PRIM_POINTS;
+}
+
+
+
+static void vbuf_flush_elements( struct draw_stage *stage )
+{
+   struct vbuf_stage *vbuf = vbuf_stage( stage );
+
+   if (vbuf->nr_elements) {
+      fprintf(stderr, "%s (%d elts)\n", __FUNCTION__, vbuf->nr_elements);
+
+      /* Draw now or add to list of primitives???
+       */
+      vbuf->draw( vbuf->pipe,
+                  vbuf->prim,
+                  vbuf->element_map,
+                  vbuf->nr_elements,
+                  vbuf->vertex_map,
+                  (vbuf->vertex_ptr - vbuf->vertex_map) / vbuf->vertex_size );
+      
+      vbuf->nr_elements = 0;
+
+      vbuf->vertex_ptr = vbuf->vertex_map;
+      vbuf->nr_vertices = 0;
+
+      /* Reset vertex ids?  Actually, want to not do that unless our
+       * vertex buffer is full.  Would like separate
+       * flush-on-index-full and flush-on-vb-full, but may raise
+       * issues uploading vertices if the hardware wants to flush when
+       * we flush.
+       */
+      draw_vertex_cache_reset_vertex_ids( vbuf->draw_context );
+   }
+
+   stage->tri = vbuf_first_tri;
+   stage->line = vbuf_first_line;
+   stage->point = vbuf_first_point;
+}
+
+
+static void vbuf_begin( struct draw_stage *stage )
+{
+   struct vbuf_stage *vbuf = vbuf_stage(stage);
+
+   vbuf->vertex_size = vbuf->draw_context->vertex_info.size * sizeof(float);
+}
+
+
+static void vbuf_end( struct draw_stage *stage )
+{
+   /* Overkill.
+    */
+   vbuf_flush_elements( stage );
+}
+
+
+static void reset_stipple_counter( struct draw_stage *stage )
+{
+   /* XXX:  This doesn't work.
+    */
+}
+
+
+/**
+ * Create a new primitive vbuf/render stage.
+ */
+struct draw_stage *sp_draw_vbuf_stage( struct draw_context *draw_context,
+                                         struct pipe_context *pipe,
+                                         vbuf_draw_func draw )
+{
+   struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
+
+   vbuf->stage.begin = vbuf_begin;
+   vbuf->stage.point = vbuf_first_point;
+   vbuf->stage.line = vbuf_first_line;
+   vbuf->stage.tri = vbuf_first_tri;
+   vbuf->stage.end = vbuf_end;
+   vbuf->stage.reset_stipple_counter = reset_stipple_counter;
+
+   vbuf->pipe = pipe;
+   vbuf->draw = draw;
+   vbuf->draw_context = draw_context;
+
+   vbuf->element_map = malloc( IBUF_SIZE );
+   vbuf->vertex_map = malloc( VBUF_SIZE );
+   
+   vbuf->vertex_ptr = vbuf->vertex_map;
+   
+
+   return &vbuf->stage;
+}