mesa: Branch 'vbo_0_1_branch' - 8 commits

Keith Whitwell keithw at kemper.freedesktop.org
Mon Jan 15 14:35:06 UTC 2007


 src/mesa/main/context.c          |    1 
 src/mesa/sources                 |    3 
 src/mesa/tnl/t_draw.c            |  128 +++++++--
 src/mesa/vbo/vbo.h               |   36 ++
 src/mesa/vbo/vbo_attrib_tmp.h    |    5 
 src/mesa/vbo/vbo_context.c       |   11 
 src/mesa/vbo/vbo_context.h       |    8 
 src/mesa/vbo/vbo_exec_array.c    |    6 
 src/mesa/vbo/vbo_save.h          |    2 
 src/mesa/vbo/vbo_save_api.c      |   42 --
 src/mesa/vbo/vbo_save_loopback.c |  149 ----------
 src/mesa/vbo/vbo_split.c         |  161 +++++++++++
 src/mesa/vbo/vbo_split.h         |   72 +++++
 src/mesa/vbo/vbo_split_copy.c    |  549 +++++++++++++++++++++++++++++++++++++++
 src/mesa/vbo/vbo_split_inplace.c |  287 ++++++++++++++++++++
 15 files changed, 1244 insertions(+), 216 deletions(-)

New commits:
diff-tree 6ff9b48fe2bb2113689e45c89a7c643e44906d67 (from 50f76b9d9b4b17940798b44233b9b5af2f932117)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date:   Mon Jan 15 14:30:16 2007 +0000

    Don't special-case FOG attribute initialization.
    
    Initial fog value was being set to {0,0,0,0}.  This results in vector
    size 4, but isn't necessary.  The regular {0,0,0,1} works fine.

diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 91f3af3..94d0ff6 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -970,7 +970,6 @@ _mesa_init_current( GLcontext *ctx )
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
-   ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_FOG], 0.0, 0.0, 0.0, 0.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
 }
diff-tree 50f76b9d9b4b17940798b44233b9b5af2f932117 (from 82152a2a8e1afeb61710318e769b1379be6c02c6)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date:   Mon Jan 15 14:20:21 2007 +0000

    Correctly initialize current attribute sizes.
    
    Some legacy attributes (eg color) have an initial value other than {0,0,0,1}
    which means that their initial size != 1 either.

diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c
index 165e32d..65998e7 100644
--- a/src/mesa/vbo/vbo_context.c
+++ b/src/mesa/vbo/vbo_context.c
@@ -47,6 +47,14 @@ extern void _tnl_draw_prims( GLcontext *
 #define NR_GENERIC_ATTRIBS 16
 #define NR_MAT_ATTRIBS 12
 
+static GLuint check_size( const GLfloat *attr )
+{
+   if (attr[3] != 1.0) return 4;
+   if (attr[2] != 0.0) return 3;
+   if (attr[1] != 0.0) return 2;
+   return 1;		
+}
+
 static void init_legacy_currval(GLcontext *ctx)
 {
    struct vbo_context *vbo = vbo_context(ctx);
@@ -63,7 +71,7 @@ static void init_legacy_currval(GLcontex
 
       /* Size will have to be determined at runtime:
        */
-      cl->Size = 1;
+      cl->Size = check_size(ctx->Current.Attrib[i]);
       cl->Stride = 0;
       cl->StrideB = 0;
       cl->Enabled = 1;
@@ -88,7 +96,6 @@ static void init_generic_currval(GLconte
       /* This will have to be determined at runtime:
        */
       cl->Size = 1;
-
       cl->Type = GL_FLOAT;
       cl->Ptr = (const void *)ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i];
       cl->Stride = 0;
diff-tree 82152a2a8e1afeb61710318e769b1379be6c02c6 (from 5464cd0a60f474753abc6af047fd21b0e29b8ac4)
Author: keithw <keithw at keithw-laptop.(none)>
Date:   Mon Jan 15 14:10:42 2007 +0000

    Remove debug, reenable inplace splitting.

diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index 25b8708..0e7c2b6 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -375,7 +375,6 @@ void _tnl_draw_prims( GLcontext *ctx,
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
    GLint max = VB->Size;
-   GLuint i;
 
 #ifdef TEST_SPLIT
    max = 8 + MAX_CLIPPED_VERTICES;
@@ -387,12 +386,15 @@ void _tnl_draw_prims( GLcontext *ctx,
    VB->Elts = NULL;
 
 #if 0
-   _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
-   for (i = 0; i < nr_prims; i++)
-      _mesa_printf("prim %d: %s start %d count %d\n", i, 
-		   _mesa_lookup_enum_by_nr(prim[i].mode),
-		   prim[i].start,
-		   prim[i].count);
+   {
+      GLuint i;
+      _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+      for (i = 0; i < nr_prims; i++)
+	 _mesa_printf("prim %d: %s start %d count %d\n", i, 
+		      _mesa_lookup_enum_by_nr(prim[i].mode),
+		      prim[i].start,
+		      prim[i].count);
+   }
 #endif
 
    /* The software TNL pipeline has a fixed amount of storage for
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index f339436..ade48d2 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -598,8 +598,6 @@ do {								\
    if (save->active_sz[A] != N)				\
       save_fixup_vertex(ctx, A, N);				\
 								\
-   _mesa_printf("Attr %d, sz %d: %f %f %f %f\n", A, N, V0, V1, V2, V3 );	\
-								\
    {								\
       GLfloat *dest = save->attrptr[A];			\
       if (N>0) dest[0] = V0;					\
diff --git a/src/mesa/vbo/vbo_save_loopback.c b/src/mesa/vbo/vbo_save_loopback.c
index 2c28126..430333b 100644
--- a/src/mesa/vbo/vbo_save_loopback.c
+++ b/src/mesa/vbo/vbo_save_loopback.c
@@ -45,7 +45,8 @@ typedef void (*attr_func)( GLcontext *ct
 
 
 /* This file makes heavy use of the aliasing of NV vertex attributes
- * with the legacy attributes. 
+ * with the legacy attributes, and also with ARB and Material
+ * attributes as currently implemented.
  */
 static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
 {
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
index 66c94ac..d3649c5 100644
--- a/src/mesa/vbo/vbo_split_inplace.c
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -49,9 +49,6 @@ struct split_context {
 
    const struct split_limits *limits;
 
-/*    GLuint out_maxindex; */
-/*    GLuint out_minindex; */
-
    struct _mesa_prim dstprim[MAX_PRIM];
    GLuint dstprim_nr;
 };
@@ -151,13 +148,6 @@ static void split_prims( struct split_co
       GLuint available = align(split->limits->max_verts - csr - 1, 2); 
       assert(split->limits->max_verts >= csr);
 
-      _mesa_printf("%s: prim %d: %s %d..%d\n", __FUNCTION__,
-		   i,
-		   _mesa_lookup_enum_by_nr(prim->mode),
-		   prim->start, prim->count);
-
-      _mesa_printf("a: available %d\n", available);
-
       if (prim->count < first)
 	 continue;
       
@@ -171,15 +161,13 @@ static void split_prims( struct split_co
 	 available = align(split->limits->max_verts - csr - 1, 2);
       }
       
-      _mesa_printf("b: available %d\n", available);
-
       if (available >= count) {
 	 struct _mesa_prim *outprim = next_outprim(split);
 	 *outprim = *prim;
 	 csr += prim->count;
 	 available = align(split->limits->max_verts - csr - 1, 2); 
       } 
-      else if (0 && split_inplace) {
+      else if (split_inplace) {
 	 GLuint j, nr;
 
 
@@ -207,8 +195,6 @@ static void split_prims( struct split_co
 	    else {
 	       /* Wrapped the primitive: 
 		*/
-	       _mesa_printf("wrap %d %d\n", nr, first-incr);
-
 	       j += nr - (first - incr);
 	       flush_vertex(split);
 	       csr = 0;
diff-tree 5464cd0a60f474753abc6af047fd21b0e29b8ac4 (from 2421b25dd777ebfd614ae45907fd4af8c2713102)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date:   Mon Jan 15 13:54:08 2007 +0000

    Split too-large draw commands.
    
    Use the vbo_split_ functionality to split incoming drawing command
    to fit within the fixed-size buffers used by software t&l module.

diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index 0f9615e..25b8708 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -32,6 +32,7 @@
 #include "state.h"
 #include "mtypes.h"
 #include "macros.h"
+#include "enums.h"
 
 #include "t_context.h"
 #include "t_pipeline.h"
@@ -182,7 +183,7 @@ static GLboolean *_tnl_import_edgeflag( 
 
 static void bind_inputs( GLcontext *ctx, 
 			 const struct gl_client_array *inputs[],
-			 GLint start, GLint end,
+			 GLint min_index, GLint max_index,
 			 struct gl_buffer_object **bo,
 			 GLuint *nr_bo )
 {
@@ -214,15 +215,20 @@ static void bind_inputs( GLcontext *ctx,
 	 ptr = inputs[i]->Ptr;
 
       /* Just make sure the array is floating point, otherwise convert to
-       * temporary storage.  Rebase arrays so that 'start' becomes
+       * temporary storage.  Rebase arrays so that 'min_index' becomes
        * element zero.
        *
        * XXX: remove the GLvector4f type at some stage and just use
        * client arrays.
        */
-      _tnl_import_array(ctx, i, start, end, inputs[i], ptr);
+      _tnl_import_array(ctx, i, min_index, max_index, inputs[i], ptr);
    }
 
+   /* We process only the vertices between min & max index:
+    */
+   VB->Count = max_index - min_index;
+
+
    /* Legacy pointers -- remove one day.
     */
    VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
@@ -256,10 +262,11 @@ static void bind_inputs( GLcontext *ctx,
 
 /* Translate indices to GLuints and store in VB->Elts.
  */
-static void bind_indicies( GLcontext *ctx,
-			   const struct _mesa_index_buffer *ib,
-			   struct gl_buffer_object **bo,
-			   GLuint *nr_bo)
+static void bind_indices( GLcontext *ctx,
+			  const struct _mesa_index_buffer *ib,
+			  GLuint min_index,
+			  struct gl_buffer_object **bo,
+			  GLuint *nr_bo)
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
@@ -282,7 +289,7 @@ static void bind_indicies( GLcontext *ct
 
    ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
 
-   if (ib->type == GL_UNSIGNED_INT) {
+   if (ib->type == GL_UNSIGNED_INT && min_index == 0) {
       VB->Elts = (GLuint *) ptr;
       VB->Elts += ib->rebase;
    }
@@ -291,22 +298,54 @@ static void bind_indicies( GLcontext *ct
       VB->Elts = elts;
 
       switch (ib->type) {
+      case GL_UNSIGNED_INT: {
+	 const GLuint *in = ((GLuint *)ptr) + ib->rebase;
+	 for (i = 0; i < ib->count; i++) 
+	    *elts++ = *in++ - min_index;
+	 break;
+      }
       case GL_UNSIGNED_SHORT: {
 	 const GLushort *in = ((GLushort *)ptr) + ib->rebase;
 	 for (i = 0; i < ib->count; i++) 
-	    *elts++ = *in++;
+	    *elts++ = (GLuint)(*in++) - min_index;
 	 break;
       }
       case GL_UNSIGNED_BYTE: {
 	 const GLubyte *in = ((GLubyte *)ptr) + ib->rebase;
 	 for (i = 0; i < ib->count; i++) 
-	    *elts++ = *in++;
+	    *elts++ = (GLuint)(*in++) - min_index;
 	 break;
       }
       }      
    }
 }
 
+static void bind_prims( GLcontext *ctx,
+			const struct _mesa_prim *prim,
+			GLuint nr_prims,
+			GLuint min_index )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &tnl->vb;
+   GLuint i;
+
+   if (min_index != 0) {
+      struct _mesa_prim *tmp = (struct _mesa_prim *)get_space(ctx, nr_prims * sizeof(*prim));
+
+      for (i = 0; i < nr_prims; i++) {
+	 tmp[i] = prim[i];
+	 tmp[i].start -= min_index;
+      }
+
+      VB->Primitive = tmp;
+   }
+   else {
+      VB->Primitive = prim;
+   }
+
+   VB->PrimitiveCount = nr_prims;
+}
+
 static void unmap_vbos( GLcontext *ctx,
 			struct gl_buffer_object **bo,
 			GLuint nr_bo )
@@ -335,26 +374,63 @@ void _tnl_draw_prims( GLcontext *ctx,
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
+   GLint max = VB->Size;
+   GLuint i;
 
-   /* May need to map a vertex buffer object for every attribute plus
-    * one for the index buffer.
-    */
-   struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
-   GLuint nr_bo = 0;
+#ifdef TEST_SPLIT
+   max = 8 + MAX_CLIPPED_VERTICES;
+#endif
+   
+   assert(max_index > min_index);
+   assert(!(max_index & 0x80000000));
 
-   /* Binding inputs may imply mapping some vertex buffer objects.
-    * They will need to be unmapped below.
+   VB->Elts = NULL;
+
+#if 0
+   _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+   for (i = 0; i < nr_prims; i++)
+      _mesa_printf("prim %d: %s start %d count %d\n", i, 
+		   _mesa_lookup_enum_by_nr(prim[i].mode),
+		   prim[i].start,
+		   prim[i].count);
+#endif
+
+   /* The software TNL pipeline has a fixed amount of storage for
+    * vertices and it is necessary to split incoming drawing commands
+    * if they exceed that limit.
     */
-   bind_inputs(ctx, arrays, min_index, max_index, bo, &nr_bo);
-   bind_indicies(ctx, ib, bo, &nr_bo);
+   if (max_index - min_index >= max - MAX_CLIPPED_VERTICES) {
+      struct split_limits limits;
+      limits.max_verts = max - MAX_CLIPPED_VERTICES;
+      limits.max_vb_size = ~0;
+      limits.max_indices = ~0;
 
-   VB->Primitive = prim;
-   VB->PrimitiveCount = nr_prims;
-   VB->Count = max_index - min_index;
+      /* This will split the buffers one way or another and
+       * recursively call back into this function.
+       */
+      vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 
+		       min_index, max_index,
+		       _tnl_draw_prims,
+		       &limits );
+   }
+   else {
+      /* May need to map a vertex buffer object for every attribute plus
+       * one for the index buffer.
+       */
+      struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
+      GLuint nr_bo = 0;
+
+      /* Binding inputs may imply mapping some vertex buffer objects.
+       * They will need to be unmapped below.
+       */
+      bind_inputs(ctx, arrays, min_index, max_index+1, bo, &nr_bo);
+      bind_indices(ctx, ib, min_index, bo, &nr_bo);
+      bind_prims(ctx, prim, nr_prims, VB->Elts ? 0 : min_index );
 
-   TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
+      TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
 
-   unmap_vbos(ctx, bo, nr_bo);
-   free_space(ctx);
+      unmap_vbos(ctx, bo, nr_bo);
+      free_space(ctx);
+   }
 }
 
diff-tree 2421b25dd777ebfd614ae45907fd4af8c2713102 (from 1b7c24c33c43e2c0db391735b2f2ca0026459cc9)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date:   Mon Jan 15 13:40:38 2007 +0000

    Remove special-case handling for index and edgeflag
    
    This isn't required with the changes to core mesa and the new
    attribute layout.

diff --git a/src/mesa/vbo/vbo_attrib_tmp.h b/src/mesa/vbo/vbo_attrib_tmp.h
index 72a8b04..ff11c7d 100644
--- a/src/mesa/vbo/vbo_attrib_tmp.h
+++ b/src/mesa/vbo/vbo_attrib_tmp.h
@@ -357,9 +357,10 @@ static void GLAPIENTRY TAG(VertexAttrib4
 }
 
 
-/* Although we don't export NV_vertex_program, these entrypoints are
+/* In addition to supporting NV_vertex_program, these entrypoints are
  * used by the display list and other code specifically because of
- * their property of aliasing with other attributes.
+ * their property of aliasing with other attributes.  (See
+ * vbo_save_loopback.c)
  */
 static void GLAPIENTRY TAG(VertexAttrib1fNV)( GLuint index, GLfloat x )
 {
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 803e58c..15fbdcf 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -96,10 +96,10 @@ static void bind_array_obj( GLcontext *c
    exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &ctx->Array.ArrayObj->SecondaryColor;
    exec->array.legacy_array[VERT_ATTRIB_FOG] = &ctx->Array.ArrayObj->FogCoord;
    exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &ctx->Array.ArrayObj->Index;
-   exec->array.legacy_array[VBO_ATTRIB_EDGEFLAG] = &ctx->Array.ArrayObj->EdgeFlag;
+   exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &ctx->Array.ArrayObj->EdgeFlag;
 
    for (i = 0; i < 8; i++)
-      exec->array.legacy_array[VBO_ATTRIB_TEX0 + i] = &ctx->Array.ArrayObj->TexCoord[i];
+      exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &ctx->Array.ArrayObj->TexCoord[i];
 
    for (i = 0; i < VERT_ATTRIB_MAX; i++)
       exec->array.generic_array[i] = &ctx->Array.ArrayObj->VertexAttrib[i];
@@ -117,8 +117,6 @@ static void recalculate_input_bindings( 
    exec->array.program_mode = get_program_mode(ctx);
    exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled;
 
-   /* TODO:  Get rid of NV_program (please!).
-    */
    switch (exec->array.program_mode) {
    case VP_NONE:
       /* When no vertex program is active, we put the material values
diff --git a/src/mesa/vbo/vbo_save.h b/src/mesa/vbo/vbo_save.h
index 3051f5c..b81f275 100644
--- a/src/mesa/vbo/vbo_save.h
+++ b/src/mesa/vbo/vbo_save.h
@@ -142,8 +142,6 @@ struct vbo_save_context {
 
    struct vbo_save_copied_vtx copied;
    
-   GLfloat CurrentFloatEdgeFlag;
-
    GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->ListState */
    GLubyte *currentsz[VBO_ATTRIB_MAX];
 };
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index efe018b..f339436 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -415,26 +415,14 @@ static void _save_copy_to_current( GLcon
    struct vbo_save_context *save = &vbo_context(ctx)->save; 
    GLuint i;
 
-   for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; i++) {
+   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
       if (save->attrsz[i]) {
 	 save->currentsz[i][0] = save->attrsz[i];
 	 COPY_CLEAN_4V(save->current[i], 
-		    save->attrsz[i], 
-		    save->attrptr[i]);
+		       save->attrsz[i], 
+		       save->attrptr[i]);
       }
    }
-
-   /* Edgeflag requires special treatment: 
-    *
-    * TODO: change edgeflag to GLfloat in Mesa.
-    */
-   if (save->attrsz[VBO_ATTRIB_EDGEFLAG]) {
-      ctx->ListState.ActiveEdgeFlag = 1;
-      save->CurrentFloatEdgeFlag = 
-	 save->attrptr[VBO_ATTRIB_EDGEFLAG][0];
-      ctx->ListState.CurrentEdgeFlag = 
-	 (save->CurrentFloatEdgeFlag == 1.0);
-   }
 }
 
 
@@ -443,7 +431,7 @@ static void _save_copy_from_current( GLc
    struct vbo_save_context *save = &vbo_context(ctx)->save; 
    GLint i;
 
-   for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; i++) 
+   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
       switch (save->attrsz[i]) {
       case 4: save->attrptr[i][3] = save->current[i][3];
       case 3: save->attrptr[i][2] = save->current[i][2];
@@ -451,12 +439,6 @@ static void _save_copy_from_current( GLc
       case 1: save->attrptr[i][0] = save->current[i][0];
       case 0: break;
       }
-
-   /* Edgeflag requires special treatment:
-    */
-   if (save->attrsz[VBO_ATTRIB_EDGEFLAG]) {
-      save->CurrentFloatEdgeFlag = (GLfloat)ctx->ListState.CurrentEdgeFlag;
-      save->attrptr[VBO_ATTRIB_EDGEFLAG][0] = save->CurrentFloatEdgeFlag;
    }
 }
 
@@ -616,6 +598,8 @@ do {								\
    if (save->active_sz[A] != N)				\
       save_fixup_vertex(ctx, A, N);				\
 								\
+   _mesa_printf("Attr %d, sz %d: %f %f %f %f\n", A, N, V0, V1, V2, V3 );	\
+								\
    {								\
       GLfloat *dest = save->attrptr[A];			\
       if (N>0) dest[0] = V0;					\
@@ -1106,23 +1090,19 @@ static void _save_current_init( GLcontex
    struct vbo_save_context *save = &vbo_context(ctx)->save;
    GLint i;
 
-   for (i = 0; i < VBO_ATTRIB_FIRST_MATERIAL; i++) {
-      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
-      save->current[i] = ctx->ListState.CurrentAttrib[i];
+   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
+      const GLuint j = i - VBO_ATTRIB_POS;
+      ASSERT(j < VERT_ATTRIB_MAX);
+      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
+      save->current[i] = ctx->ListState.CurrentAttrib[j];
    }
 
-   for (i = VBO_ATTRIB_FIRST_MATERIAL; i < VBO_ATTRIB_INDEX; i++) {
+   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_MAT_FRONT_AMBIENT; i++) {
       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
       ASSERT(j < MAT_ATTRIB_MAX);
       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
       save->current[i] = ctx->ListState.CurrentMaterial[j];
    }
-
-   save->currentsz[VBO_ATTRIB_INDEX] = &ctx->ListState.ActiveIndex;
-   save->current[VBO_ATTRIB_INDEX] = &ctx->ListState.CurrentIndex;
-
-   save->currentsz[VBO_ATTRIB_EDGEFLAG] = &ctx->ListState.ActiveEdgeFlag;
-   save->current[VBO_ATTRIB_EDGEFLAG] = &save->CurrentFloatEdgeFlag;
 }
 
 /**
diff --git a/src/mesa/vbo/vbo_save_loopback.c b/src/mesa/vbo/vbo_save_loopback.c
index 941c4be..2c28126 100644
--- a/src/mesa/vbo/vbo_save_loopback.c
+++ b/src/mesa/vbo/vbo_save_loopback.c
@@ -44,7 +44,9 @@
 typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
 
 
-/* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
+/* This file makes heavy use of the aliasing of NV vertex attributes
+ * with the legacy attributes. 
+ */
 static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
 {
    CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
@@ -72,118 +74,6 @@ static attr_func vert_attrfunc[4] = {
    VertexAttrib4fvNV
 };
 
-#if 0
-static void VertexAttrib1fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
-   CALL_VertexAttrib1fvARB(ctx->Exec, (target, v));
-}
-
-static void VertexAttrib2fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
-   CALL_VertexAttrib2fvARB(ctx->Exec, (target, v));
-}
-
-static void VertexAttrib3fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
-   CALL_VertexAttrib3fvARB(ctx->Exec, (target, v));
-}
-
-static void VertexAttrib4fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
-   CALL_VertexAttrib4fvARB(ctx->Exec, (target, v));
-}
-
-
-static attr_func vert_attrfunc_arb[4] = {
-   VertexAttrib1fvARB,
-   VertexAttrib2fvARB,
-   VertexAttrib3fvARB,
-   VertexAttrib4fvARB
-};
-#endif
-
-
-
-
-
-
-static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
-{
-   switch (target) {
-   case VBO_ATTRIB_MAT_FRONT_SHININESS:
-      CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SHININESS, v ));
-      break;
-   case VBO_ATTRIB_MAT_BACK_SHININESS:
-      CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SHININESS, v ));
-      break;
-   }
-}
-
-
-static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
-{
-   switch (target) {
-   case VBO_ATTRIB_MAT_FRONT_INDEXES:
-      CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_COLOR_INDEXES, v ));
-      break;
-   case VBO_ATTRIB_MAT_BACK_INDEXES:
-      CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_COLOR_INDEXES, v ));
-      break;
-   }
-}
-
-
-static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
-{
-   switch (target) {
-   case VBO_ATTRIB_MAT_FRONT_EMISSION:
-      CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_EMISSION, v ));
-      break;
-   case VBO_ATTRIB_MAT_BACK_EMISSION:
-      CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_EMISSION, v ));
-      break;
-   case VBO_ATTRIB_MAT_FRONT_AMBIENT:
-      CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_AMBIENT, v ));
-      break;
-   case VBO_ATTRIB_MAT_BACK_AMBIENT:
-      CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_AMBIENT, v ));
-      break;
-   case VBO_ATTRIB_MAT_FRONT_DIFFUSE:
-      CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_DIFFUSE, v ));
-      break;
-   case VBO_ATTRIB_MAT_BACK_DIFFUSE:
-      CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_DIFFUSE, v ));
-      break;
-   case VBO_ATTRIB_MAT_FRONT_SPECULAR:
-      CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SPECULAR, v ));
-      break;
-   case VBO_ATTRIB_MAT_BACK_SPECULAR:
-      CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SPECULAR, v ));
-      break;
-   }
-}
-
-
-static attr_func mat_attrfunc[4] = {
-   mat_attr1fv,
-   NULL,
-   mat_attr3fv,
-   mat_attr4fv
-};
-
-
-static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
-{
-   (void) target;
-   CALL_Indexf(ctx->Exec, (v[0]));
-}
-
-static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
-{
-   (void) target;
-   CALL_EdgeFlag(ctx->Exec, ((GLboolean)(v[0] == 1.0)));
-}
-
 struct loopback_attr {
    GLint target;
    GLint sz;
@@ -277,7 +167,10 @@ void vbo_loopback_vertex_list( GLcontext
    struct loopback_attr la[VBO_ATTRIB_MAX];
    GLuint i, nr = 0;
 
-   for (i = 0 ; i <= VBO_ATTRIB_TEX7 ; i++) {
+   /* All Legacy, NV, ARB and Material attributes are routed through
+    * the NV attributes entrypoints:
+    */
+   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
       if (attrsz[i]) {
 	 la[nr].target = i;
 	 la[nr].sz = attrsz[i];
@@ -286,33 +179,6 @@ void vbo_loopback_vertex_list( GLcontext
       }
    }
 
-   for (i = VBO_ATTRIB_MAT_FRONT_AMBIENT ; 
-	i <= VBO_ATTRIB_MAT_BACK_INDEXES ; 
-	i++) {
-      if (attrsz[i]) {
-	 la[nr].target = i;
-	 la[nr].sz = attrsz[i];
-	 la[nr].func = mat_attrfunc[attrsz[i]-1];
-	 nr++;
-      }
-   }
-
-   if (attrsz[VBO_ATTRIB_EDGEFLAG]) {
-      la[nr].target = VBO_ATTRIB_EDGEFLAG;
-      la[nr].sz = attrsz[VBO_ATTRIB_EDGEFLAG];
-      la[nr].func = edgeflag_attr1fv;
-      nr++;
-   }
-
-   if (attrsz[VBO_ATTRIB_INDEX]) {
-      la[nr].target = VBO_ATTRIB_INDEX;
-      la[nr].sz = attrsz[VBO_ATTRIB_INDEX];
-      la[nr].func = index_attr1fv;
-      nr++;
-   }
-
-   /* XXX ARB vertex attribs */
-
    for (i = 0 ; i < prim_count ; i++) {
       if ((prim[i].mode & VBO_SAVE_PRIM_WEAK) &&
 	  (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END))
diff-tree 1b7c24c33c43e2c0db391735b2f2ca0026459cc9 (from 4557dfe13206495916d4ff8557f1633194a12c0f)
Author: keithw <keithw at keithw-laptop.(none)>
Date:   Mon Jan 15 11:58:06 2007 +0000

    Hook in split functionality

diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index 80f7a33..c81d83f 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -65,4 +65,40 @@ void _vbo_DestroyContext( GLcontext *ctx
 void _vbo_InvalidateState( GLcontext *ctx, GLuint new_state );
 
 
+typedef void (*vbo_draw_func)( GLcontext *ctx,
+			       const struct gl_client_array **arrays,
+			       const struct _mesa_prim *prims,
+			       GLuint nr_prims,
+			       const struct _mesa_index_buffer *ib,
+			       GLuint min_index,
+			       GLuint max_index );
+
+
+
+
+/* Utility function to cope with various constraints on tnl modules or
+ * hardware.  This can be used to split an incoming set of arrays and
+ * primitives against the following constraints:
+ *    - Maximum number of indices in index buffer.
+ *    - Maximum number of vertices referenced by index buffer.
+ *    - Maximum hardware vertex buffer size.
+ */
+struct split_limits {
+   GLuint max_verts;
+   GLuint max_indices;
+   GLuint max_vb_size;		/* bytes */
+};
+
+
+void vbo_split_prims( GLcontext *ctx,
+		      const struct gl_client_array *arrays[],
+		      const struct _mesa_prim *prim,
+		      GLuint nr_prims,
+		      const struct _mesa_index_buffer *ib,
+		      GLuint min_index,
+		      GLuint max_index,
+		      vbo_draw_func draw,
+		      const struct split_limits *limits );
+
+
 #endif
diff --git a/src/mesa/vbo/vbo_context.h b/src/mesa/vbo/vbo_context.h
index 4c5ed96..0dc1019 100644
--- a/src/mesa/vbo/vbo_context.h
+++ b/src/mesa/vbo/vbo_context.h
@@ -79,13 +79,7 @@ struct vbo_context {
    /* Callback into the driver.  This must always succeed, the driver
     * is responsible for initiating any fallback actions required:
     */
-   void (*draw_prims)( GLcontext *ctx,
-		       const struct gl_client_array *arrays[],
-		       const struct _mesa_prim *prims,
-		       GLuint nr_prims,
-		       const struct _mesa_index_buffer *ib,
-		       GLuint min_index,
-		       GLuint max_index );
+   vbo_draw_func draw_prims;
 };
 
 
diff-tree 4557dfe13206495916d4ff8557f1633194a12c0f (from a38cb37913b7cd2f9c3c7aa11dcbb9485d623924)
Author: keithw <keithw at keithw-laptop.(none)>
Date:   Mon Jan 15 11:54:40 2007 +0000

    Add vbo_split files

diff --git a/src/mesa/sources b/src/mesa/sources
index b589111..a32ecaf 100644
--- a/src/mesa/sources
+++ b/src/mesa/sources
@@ -143,6 +143,9 @@ VBO_SOURCES = \
 	vbo/vbo_exec_array.c \
 	vbo/vbo_exec_draw.c \
 	vbo/vbo_exec_eval.c \
+	vbo/vbo_split.c \
+	vbo/vbo_split_copy.c \
+	vbo/vbo_split_inplace.c \
 	vbo/vbo_save.c \
 	vbo/vbo_save_api.c \
 	vbo/vbo_save_draw.c \
diff-tree a38cb37913b7cd2f9c3c7aa11dcbb9485d623924 (from dd60eaa6d9f61735141976db0e83d25176ac73c7)
Author: keithw <keithw at keithw-laptop.(none)>
Date:   Mon Jan 15 11:52:58 2007 +0000

    New files to manage splitting drawing commands

diff --git a/src/mesa/vbo/vbo_split.c b/src/mesa/vbo/vbo_split.c
new file mode 100644
index 0000000..171859a
--- /dev/null
+++ b/src/mesa/vbo/vbo_split.c
@@ -0,0 +1,161 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5
+ *
+ * Copyright (C) 1999-2006  Brian Paul   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, sublicense,
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ *
+ * Authors:
+ *    Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+/* Deal with hardware and/or swtnl maximums:
+ * - maximum number of vertices in buffer
+ * - maximum number of elements (maybe zero)
+ *
+ * The maximums may vary with opengl state (eg if a larger hardware
+ * vertex is required in this state, the maximum number of vertices
+ * may be smaller than in another state).
+ *
+ * We want buffer splitting to be a convenience function for the code
+ * actually drawing the primitives rather than a system-wide maximum,
+ * otherwise it is hard to avoid pessimism.  
+ *
+ * For instance, if a driver has no hardware limits on vertex buffer
+ * dimensions, it would not ordinarily want to split vbos.  But if
+ * there is an unexpected fallback, eg memory manager fails to upload
+ * textures, it will want to pass the drawing commands onto swtnl,
+ * which does have limitations.  A convenience function allows swtnl
+ * to split the drawing and vbos internally without imposing its
+ * limitations on drivers which want to use it as a fallback path.
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "vbo_split.h"
+#include "vbo.h"
+
+/* True if a primitive can be split without copying of vertices, false
+ * otherwise.
+ */
+GLboolean split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr)
+{
+   switch (mode) {
+   case GL_POINTS:
+      *first = 1;
+      *incr = 1;
+      return GL_TRUE;
+   case GL_LINES:
+      *first = 2;
+      *incr = 2;
+      return GL_TRUE;
+   case GL_LINE_STRIP:
+      *first = 2;
+      *incr = 1;
+      return GL_TRUE;
+   case GL_TRIANGLES:
+      *first = 3;
+      *incr = 3;
+      return GL_TRUE;
+   case GL_TRIANGLE_STRIP:
+      *first = 3;
+      *incr = 1;
+      return GL_TRUE;
+   case GL_QUADS:
+      *first = 4;
+      *incr = 4;
+      return GL_TRUE;
+   case GL_QUAD_STRIP:
+      *first = 4;
+      *incr = 2;
+      return GL_TRUE;
+   default:
+      *first = 0;
+      *incr = 1;		/* so that count % incr works */
+      return GL_FALSE;
+   }
+}
+
+
+
+void vbo_split_prims( GLcontext *ctx,
+		      const struct gl_client_array *arrays[],
+		      const struct _mesa_prim *prim,
+		      GLuint nr_prims,
+		      const struct _mesa_index_buffer *ib,
+		      GLuint min_index,
+		      GLuint max_index,
+		      vbo_draw_func draw,
+		      const struct split_limits *limits )
+{
+  
+   if (ib) {
+      if (limits->max_indices == 0) {
+	 /* Could traverse the indices, re-emitting vertices in turn.
+	  * But it's hard to see why this case would be needed - for
+	  * software tnl, it is better to convert to non-indexed
+	  * rendering after transformation is complete, as is done in
+	  * the t_dd_rendertmp.h templates.  Are there any devices
+	  * with hardware tnl that cannot do indexed rendering?
+	  *
+	  * For now, this path is disabled.
+	  */
+	 assert(0);
+      }
+      else if (max_index - min_index > limits->max_verts) {
+	 /* The vertex buffers are too large for hardware (or the
+	  * swtnl module).  Traverse the indices, re-emitting vertices
+	  * in turn.  Use a vertex cache to preserve some of the
+	  * sharing from the original index list.
+	  */
+	 vbo_split_copy(ctx, arrays, prim, nr_prims, ib,
+			draw, limits );
+      }
+      else if (ib->count > limits->max_indices) {
+	 /* The index buffer is too large for hardware.  Try to split
+	  * on whole-primitive boundaries, otherwise try to split the
+	  * individual primitives.
+	  */
+	 vbo_split_inplace(ctx, arrays, prim, nr_prims, ib,
+			   min_index, max_index, draw, limits );
+      }
+      else {
+	 /* Why were we called? */
+	 assert(0);
+      }
+   }
+   else {
+      if (max_index - min_index >= limits->max_verts) {
+	 /* The vertex buffer is too large for hardware (or the swtnl
+	  * module).  Try to split on whole-primitive boundaries,
+	  * otherwise try to split the individual primitives.
+	  */
+	 vbo_split_inplace(ctx, arrays, prim, nr_prims, ib,
+			   min_index, max_index, draw, limits );
+      }
+      else {
+	 /* Why were we called? */
+	 assert(0);
+      }
+   }
+}
+
diff --git a/src/mesa/vbo/vbo_split.h b/src/mesa/vbo/vbo_split.h
new file mode 100644
index 0000000..05888d0
--- /dev/null
+++ b/src/mesa/vbo/vbo_split.h
@@ -0,0 +1,72 @@
+/*
+ * mesa 3-D graphics library
+ * Version:  6.5
+ *
+ * Copyright (C) 1999-2006  Brian Paul   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, sublicense,
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+/**
+ * \file vbo_context.h
+ * \brief VBO builder module datatypes and definitions.
+ * \author Keith Whitwell
+ */
+
+
+/**
+ * \mainpage The VBO splitter
+ *
+ * This is the private data used internally to the vbo_split_prims()
+ * helper function.  Nobody outside the vbo_split* files needs to
+ * include or know about this structure.
+ */
+
+
+#ifndef _VBO_SPLIT_H
+#define _VBO_SPLIT_H
+
+#include "vbo.h"
+
+
+/* True if a primitive can be split without copying of vertices, false
+ * otherwise.
+ */
+GLboolean split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr);
+
+void vbo_split_inplace( GLcontext *ctx,
+			const struct gl_client_array *arrays[],
+			const struct _mesa_prim *prim,
+			GLuint nr_prims,
+			const struct _mesa_index_buffer *ib,
+			GLuint min_index,
+			GLuint max_index,
+			vbo_draw_func draw,
+			const struct split_limits *limits );
+
+/* Requires ib != NULL:
+ */
+void vbo_split_copy( GLcontext *ctx,
+		     const struct gl_client_array *arrays[],
+		     const struct _mesa_prim *prim,
+		     GLuint nr_prims,
+		     const struct _mesa_index_buffer *ib,
+		     vbo_draw_func draw,
+		     const struct split_limits *limits );
+
+#endif
diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c
new file mode 100644
index 0000000..0adad71
--- /dev/null
+++ b/src/mesa/vbo/vbo_split_copy.c
@@ -0,0 +1,549 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5
+ *
+ * Copyright (C) 1999-2006  Brian Paul   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, sublicense,
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ *
+ * Authors:
+ *    Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+/* Split indexed primitives with per-vertex copying.
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "macros.h"
+#include "enums.h"
+#include "mtypes.h"
+
+#include "vbo_split.h"
+#include "vbo.h"
+
+
+#define ELT_TABLE_SIZE 16
+
+/* Used for vertex-level splitting of indexed buffers.  Note that
+ * non-indexed primitives may be converted to indexed in some cases
+ * (eg loops, fans) in order to use this splitting path.
+ */
+struct copy_context {
+
+   GLcontext *ctx;
+   const struct gl_client_array **array;
+   const struct _mesa_prim *prim;
+   GLuint nr_prims;
+   const struct _mesa_index_buffer *ib;
+   vbo_draw_func draw;
+
+   const struct split_limits *limits;
+
+   struct {
+      GLuint attr;
+      GLuint size;
+      const struct gl_client_array *array;
+      const GLubyte *src_ptr;
+
+      struct gl_client_array dstarray;
+
+   } varying[VERT_ATTRIB_MAX];
+   GLuint nr_varying;
+
+   const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
+   struct _mesa_index_buffer dstib;
+
+   GLuint *translated_elt_buf;
+   const GLuint *srcelt;
+
+   /* A baby hash table to avoid re-emitting (some) duplicate
+    * vertices when splitting indexed primitives.
+    */
+   struct { 
+      GLuint in;
+      GLuint out;
+   } vert_cache[ELT_TABLE_SIZE];
+      
+
+   GLuint vertex_size;
+   GLubyte *dstbuf;
+   GLubyte *dstptr;		/* dstptr == dstbuf + dstelt_max * vertsize */
+   GLuint dstbuf_size;	/* in vertices */
+   GLuint dstbuf_nr;		/* count of emitted vertices, also the
+				 * largest value in dstelt.  Our
+				 * MaxIndex.
+				 */
+
+   GLuint *dstelt;
+   GLuint dstelt_nr;
+   GLuint dstelt_size;
+
+#define MAX_PRIM 32
+   struct _mesa_prim dstprim[MAX_PRIM];
+   GLuint dstprim_nr;
+
+};
+
+
+static GLuint type_size( GLenum type )
+{
+   switch(type) {
+   case GL_BYTE: return sizeof(GLbyte);
+   case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
+   case GL_SHORT: return sizeof(GLshort);
+   case GL_UNSIGNED_SHORT: return sizeof(GLushort);
+   case GL_INT: return sizeof(GLint);
+   case GL_UNSIGNED_INT: return sizeof(GLuint);
+   case GL_FLOAT: return sizeof(GLfloat);
+   case GL_DOUBLE: return sizeof(GLdouble);
+   default: return 0;
+   }
+}
+
+static GLuint attr_size( const struct gl_client_array *array )
+{
+   return array->Size * type_size(array->Type);
+}
+
+
+/* Starts returning true slightly before the buffer fills, to ensure
+ * that there is sufficient room for any remaining vertices to finish
+ * off the prim:
+ */
+static GLboolean check_flush( struct copy_context *copy )
+{
+   if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
+      return GL_TRUE;
+
+   if (copy->dstelt_nr + 4 > copy->dstelt_size)
+      return GL_TRUE;
+
+   return GL_FALSE;
+}
+
+static void flush( struct copy_context *copy )
+{
+   GLuint i;
+
+   /* Set some counters: 
+    */
+   copy->dstib.count = copy->dstelt_nr;
+
+   copy->draw( copy->ctx,
+	       copy->dstarray_ptr,
+	       copy->dstprim,
+	       copy->dstprim_nr,
+	       &copy->dstib,
+	       0,
+	       copy->dstbuf_nr );
+
+   /* Reset all pointers: 
+    */
+   copy->dstprim_nr = 0;
+   copy->dstelt_nr = 0;
+   copy->dstbuf_nr = 0;
+   copy->dstptr = copy->dstbuf;
+
+   /* Clear the vertex cache:
+    */
+   for (i = 0; i < ELT_TABLE_SIZE; i++)
+      copy->vert_cache[i].in = ~0;
+}
+
+
+
+static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
+{
+   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
+
+   _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag);
+		
+   prim->mode = mode;
+   prim->begin = begin_flag;
+}
+
+
+/* Use a hashtable to attempt to identify recently-emitted vertices
+ * and avoid re-emitting them.
+ */
+static GLuint elt(struct copy_context *copy, GLuint elt_idx)
+{
+   GLuint elt = copy->srcelt[elt_idx];
+   GLuint slot = elt & (ELT_TABLE_SIZE-1);
+
+   _mesa_printf("elt %d\n", elt);
+
+   /* Look up the incoming element in the vertex cache.  Re-emit if
+    * necessary.   
+    */
+   if (copy->vert_cache[slot].in != elt) {
+      GLubyte *csr = copy->dstptr;
+      GLuint i;
+
+      _mesa_printf("  --> emit to dstelt %d\n", copy->dstbuf_nr);
+
+      for (i = 0; i < copy->nr_varying; i++) {
+	 const struct gl_client_array *srcarray = copy->varying[i].array;
+	 const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
+
+	 memcpy(csr, srcptr, copy->varying[i].size);
+	 csr += copy->varying[i].size;
+
+	 {
+	    const GLuint *f = (const GLuint *)srcptr;
+	    GLuint j;
+	    _mesa_printf("  varying %d: ", i);
+	    for(j = 0; j < copy->varying[i].size / 4; j++)
+	       _mesa_printf("%x ", f[j]);
+	    _mesa_printf("\n");
+	 }
+	       
+      }
+
+      copy->vert_cache[slot].in = elt;
+      copy->vert_cache[slot].out = copy->dstbuf_nr++;
+      copy->dstptr += copy->vertex_size;
+
+      assert(csr == copy->dstptr);
+      assert(copy->dstptr == (copy->dstbuf + 
+				    copy->dstbuf_nr * 
+				    copy->vertex_size));
+   }
+   else
+      _mesa_printf("  --> reuse vertex\n");
+   
+   _mesa_printf("  --> emit %d\n", copy->vert_cache[slot].out);
+   copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
+   return check_flush(copy);
+}
+
+static void end( struct copy_context *copy, GLboolean end_flag )
+{
+   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
+
+   _mesa_printf("end (%d)\n", end_flag);
+
+   prim->end = end_flag;
+   prim->count = copy->dstelt_nr - prim->start;
+
+   if (++copy->dstprim_nr == MAX_PRIM ||
+       check_flush(copy)) 
+      flush(copy);
+}
+
+
+
+static void replay_elts( struct copy_context *copy )
+{
+   GLuint i, j, k;
+   GLboolean split;
+
+   for (i = 0; i < copy->nr_prims; i++) {
+      const struct _mesa_prim *prim = &copy->prim[i];
+      const GLuint start = prim->start;
+      GLuint first, incr;
+
+      switch (prim->mode) {
+	 
+      case GL_LINE_LOOP:
+	 /* Convert to linestrip and emit the final vertex explicitly,
+	  * but only in the resultant strip that requires it.
+	  */
+	 j = 0;
+	 while (j != prim->count) {
+	    begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
+
+	    for (split = GL_FALSE; j != prim->count && !split; j++)
+	       split = elt(copy, start + j);
+
+	    if (j == prim->count) {
+	       /* Done, emit final line.  Split doesn't matter as
+		* it is always raised a bit early so we can emit
+		* the last verts if necessary!
+		*/
+	       if (prim->end) 
+		  (void)elt(copy, start + 0);
+
+	       end(copy, prim->end);
+	    }
+	    else {
+	       /* Wrap
+		*/
+	       assert(split);
+	       end(copy, 0);
+	       j--;
+	    }
+	 }
+	 break;
+
+      case GL_TRIANGLE_FAN:
+      case GL_POLYGON:
+	 j = 2;
+	 while (j != prim->count) {
+	    begin(copy, prim->mode, prim->begin && j == 0);
+
+	    split = elt(copy, start+0); 
+	    assert(!split);
+
+	    split = elt(copy, start+j-1); 
+	    assert(!split);
+
+	    for (; j != prim->count && !split; j++)
+	       split = elt(copy, start+j);
+
+	    end(copy, prim->end && j == prim->count);
+
+	    if (j != prim->count) {
+	       /* Wrapped the primitive, need to repeat some vertices:
+		*/
+	       j -= 1;
+	    }
+	 }
+	 break;
+
+      default:
+	 (void)split_prim_inplace(prim->mode, &first, &incr);
+	 
+	 j = 0;
+	 while (j != prim->count) {
+
+	    begin(copy, prim->mode, prim->begin && j == 0);
+
+	    split = 0;
+	    for (k = 0; k < first; k++, j++)
+	       split |= elt(copy, start+j);
+
+	    assert(!split);
+
+	    for (; j != prim->count && !split; )
+	       for (k = 0; k < incr; k++, j++)
+		  split |= elt(copy, start+j);
+
+	    end(copy, prim->end && j == prim->count);
+
+	    if (j != prim->count) {
+	       /* Wrapped the primitive, need to repeat some vertices:
+		*/
+	       assert(j > first - incr);
+	       j -= (first - incr);
+	    }
+	 }
+	 break;
+      }
+   }
+
+   if (copy->dstprim_nr)
+      flush(copy);
+}
+
+
+static void replay_init( struct copy_context *copy )
+{
+   GLcontext *ctx = copy->ctx;
+   GLuint i;
+   GLuint offset;
+
+   /* Make a list of varying attributes and their vbo's.  Also
+    * calculate vertex size.
+    */
+   copy->vertex_size = 0;
+   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
+
+      if (copy->array[i]->StrideB == 0) {
+	 copy->dstarray_ptr[i] = copy->array[i];
+      }
+      else {
+	 GLuint j = copy->nr_varying++;
+	 
+	 copy->varying[j].attr = i;
+	 copy->varying[j].array = copy->array[i];
+	 copy->varying[j].size = attr_size(copy->array[i]);
+	 copy->vertex_size += attr_size(copy->array[i]);
+      
+	 if (vbo->Name && !vbo->Pointer) 
+	    ctx->Driver.MapBuffer(ctx,
+				  GL_ARRAY_BUFFER_ARB, 
+				  GL_DYNAMIC_DRAW_ARB, /* XXX */
+				  vbo);
+
+	 copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
+						 copy->array[i]->Ptr);
+
+	 copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
+      }
+   }
+
+   /* There must always be an index buffer.  Currently require the
+    * caller convert non-indexed prims to indexed.  Could alternately
+    * do it internally.
+    */
+   if (copy->ib->obj->Name && !copy->ib->obj->Pointer) 
+      ctx->Driver.MapBuffer(ctx, 
+			    GL_ARRAY_BUFFER_ARB, /* XXX */
+			    GL_DYNAMIC_DRAW_ARB, /* XXX */
+			    copy->ib->obj);
+
+   switch (copy->ib->type) {
+   case GL_UNSIGNED_BYTE:
+      copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
+      copy->srcelt = copy->translated_elt_buf;
+      
+      for (i = 0; i < copy->ib->count; i++)
+	 copy->translated_elt_buf[i] = ((const GLubyte *)copy->ib->ptr)[i];
+      break;
+
+   case GL_UNSIGNED_SHORT:
+      copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
+      copy->srcelt = copy->translated_elt_buf;
+
+      for (i = 0; i < copy->ib->count; i++)
+	 copy->translated_elt_buf[i] = ((const GLushort *)copy->ib->ptr)[i];
+      break;
+
+   case GL_UNSIGNED_INT:
+      copy->translated_elt_buf = NULL;
+      copy->srcelt = (const GLuint *)ADD_POINTERS(copy->ib->obj->Pointer, 
+						  copy->ib->ptr);
+      break;
+   }
+   
+
+   /* Figure out the maximum allowed vertex buffer size:
+    */
+   if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
+      copy->dstbuf_size = copy->limits->max_verts;
+   }
+   else {
+      copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
+   }
+
+   /* Allocate an output vertex buffer:
+    *
+    * XXX:  This should be a VBO!
+    */
+   copy->dstbuf = _mesa_malloc(copy->dstbuf_size * 
+			       copy->vertex_size);   
+   copy->dstptr = copy->dstbuf;
+
+   /* Setup new vertex arrays to point into the output buffer: 
+    */
+   for (offset = 0, i = 0; i < copy->nr_varying; i++) {
+      const struct gl_client_array *src = copy->varying[i].array;
+      struct gl_client_array *dst = &copy->varying[i].dstarray;
+
+      dst->Size = src->Size;
+      dst->Type = src->Type;
+      dst->Stride = copy->vertex_size;
+      dst->StrideB = copy->vertex_size;
+      dst->Ptr = copy->dstbuf + offset;
+      dst->Enabled = GL_TRUE;
+      dst->Normalized = GL_TRUE;
+      dst->BufferObj = ctx->Array.NullBufferObj;
+      dst->_MaxElement = copy->dstbuf_size; /* may be less! */
+
+      offset += copy->varying[i].size;
+   }
+
+   /* Allocate an output element list:
+    */
+   copy->dstelt_size = MIN2(65536,
+			    copy->ib->count * 2);
+   copy->dstelt_size = MIN2(copy->dstelt_size,
+			    copy->limits->max_indices);
+   copy->dstelt = _mesa_malloc(copy->dstelt_size);
+   copy->dstelt_nr = 0;
+
+   /* Setup the new index buffer to point to the allocated element
+    * list:
+    */
+   copy->dstib.count = 0;	/* duplicates dstelt_nr */
+   copy->dstib.type = GL_UNSIGNED_INT;
+   copy->dstib.obj = ctx->Array.NullBufferObj;
+   copy->dstib.ptr = copy->dstelt;
+   copy->dstib.rebase = 0;	
+}
+
+
+static void replay_finish( struct copy_context *copy )
+{
+   GLcontext *ctx = copy->ctx;
+   GLuint i;
+
+   /* Free our vertex and index buffers: 
+    */
+   _mesa_free(copy->translated_elt_buf);
+   _mesa_free(copy->dstbuf);
+   _mesa_free(copy->dstelt);
+   
+   /* Unmap VBO's 
+    */
+   for (i = 0; i < copy->nr_varying; i++) {
+      struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
+
+      if (vbo->Name && vbo->Pointer) 
+	 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vbo);
+   }
+
+   /* Unmap index buffer:
+    */
+   if (copy->ib->obj->Name && copy->ib->obj->Pointer) {
+      ctx->Driver.UnmapBuffer(ctx, 
+			      GL_ARRAY_BUFFER_ARB, /* XXX */
+			      copy->ib->obj);
+   }
+}
+
+void vbo_split_copy( GLcontext *ctx,
+		     const struct gl_client_array *arrays[],
+		     const struct _mesa_prim *prim,
+		     GLuint nr_prims,
+		     const struct _mesa_index_buffer *ib,
+		     vbo_draw_func draw,
+		     const struct split_limits *limits )
+{
+   struct copy_context copy;
+   GLuint i;
+
+   memset(&copy, 0, sizeof(copy));
+
+   /* Require indexed primitives:
+    */
+   assert(ib);
+   
+   copy.ctx = ctx;
+   copy.array = arrays;
+   copy.prim = prim;
+   copy.nr_prims = nr_prims;
+   copy.ib = ib;
+   copy.draw = draw;
+   copy.limits = limits;
+
+
+   /* Clear the vertex cache:
+    */
+   for (i = 0; i < ELT_TABLE_SIZE; i++)
+      copy.vert_cache[i].in = ~0;
+
+
+   replay_init(&copy);
+   replay_elts(&copy);
+   replay_finish(&copy);
+}
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
new file mode 100644
index 0000000..66c94ac
--- /dev/null
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -0,0 +1,301 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5
+ *
+ * Copyright (C) 1999-2006  Brian Paul   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, sublicense,
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ *
+ * Authors:
+ *    Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+
+#include "mtypes.h"
+#include "macros.h"
+#include "enums.h"
+#include "vbo_split.h"
+
+
+#define MAX_PRIM 32
+
+/* Used for splitting without copying.
+ */
+struct split_context {
+   GLcontext *ctx;
+   const struct gl_client_array **array;
+   const struct _mesa_prim *prim;
+   GLuint nr_prims;
+   const struct _mesa_index_buffer *ib;
+   GLuint min_index;
+   GLuint max_index;
+   vbo_draw_func draw;
+
+   const struct split_limits *limits;
+
+/*    GLuint out_maxindex; */
+/*    GLuint out_minindex; */
+
+   struct _mesa_prim dstprim[MAX_PRIM];
+   GLuint dstprim_nr;
+};
+
+
+
+
+static void flush_vertex( struct split_context *split )
+{
+   GLint min_index, max_index;
+
+   if (!split->dstprim_nr) 
+      return;
+
+   if (split->ib) {
+      /* This should basically be multipass rendering over the same
+       * unchanging set of VBO's.  Would like the driver not to
+       * re-upload the data, or swtnl not to re-transform the
+       * vertices.
+       */
+      assert(split->max_index - split->min_index < split->limits->max_verts);
+      min_index = split->min_index;
+      max_index = split->max_index;
+   }
+   else {
+      /* Non-indexed rendering.  Cannot assume that the primitives are
+       * ordered by increasing vertex, because of entrypoints like
+       * MultiDrawArrays.
+       */
+      GLuint i;
+      min_index = split->dstprim[0].start;
+      max_index = min_index + split->dstprim[0].count - 1;
+
+      for (i = 1; i < split->dstprim_nr; i++) {
+	 GLuint tmp_min = split->dstprim[i].start;
+	 GLuint tmp_max = tmp_min + split->dstprim[i].count - 1;
+
+	 if (tmp_min < min_index) 
+	    min_index = tmp_min;
+
+	 if (tmp_max > max_index) 
+	    max_index = tmp_max;
+      }
+   }
+
+   assert(max_index >= min_index);
+
+   split->draw( split->ctx, 
+		split->array, 
+		split->dstprim,
+		split->dstprim_nr,
+		NULL,
+		min_index,
+		max_index);
+
+   split->dstprim_nr = 0;
+}
+
+
+static struct _mesa_prim *next_outprim( struct split_context *split )
+{
+   if (split->dstprim_nr == MAX_PRIM-1) {
+      flush_vertex(split);
+   }
+
+   {
+      struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
+      memset(prim, 0, sizeof(*prim));
+      return prim;
+   }
+}
+
+static int align(int value, int alignment)
+{
+   return (value + alignment - 1) & ~(alignment - 1);
+}
+
+
+
+/* Break large primitives into smaller ones.  If not possible, convert
+ * the primitive to indexed and pass to split_elts().
+ */
+static void split_prims( struct split_context *split) 
+{
+   GLuint csr = 0;
+   GLuint i;
+
+   for (i = 0; i < split->nr_prims; i++) {
+      const struct _mesa_prim *prim = &split->prim[i];
+      GLuint first, incr;
+      GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
+      GLuint count;
+
+      /* Always wrap on an even numbered vertex to avoid problems with
+       * triangle strips.  
+       */
+      GLuint available = align(split->limits->max_verts - csr - 1, 2); 
+      assert(split->limits->max_verts >= csr);
+
+      _mesa_printf("%s: prim %d: %s %d..%d\n", __FUNCTION__,
+		   i,
+		   _mesa_lookup_enum_by_nr(prim->mode),
+		   prim->start, prim->count);
+
+      _mesa_printf("a: available %d\n", available);
+
+      if (prim->count < first)
+	 continue;
+      
+      count = prim->count - (prim->count - first) % incr; 
+
+
+      if ((available < count && !split_inplace) || 
+	  (available < first && split_inplace)) {
+	 flush_vertex(split);
+	 csr = 0;
+	 available = align(split->limits->max_verts - csr - 1, 2);
+      }
+      
+      _mesa_printf("b: available %d\n", available);
+
+      if (available >= count) {
+	 struct _mesa_prim *outprim = next_outprim(split);
+	 *outprim = *prim;
+	 csr += prim->count;
+	 available = align(split->limits->max_verts - csr - 1, 2); 
+      } 
+      else if (0 && split_inplace) {
+	 GLuint j, nr;
+
+
+	 for (j = 0 ; j < count ; ) {
+	    GLuint remaining = count - j;
+	    struct _mesa_prim *outprim = next_outprim(split);
+
+	    nr = MIN2( available, remaining );
+	    
+	    nr -= (nr - first) % incr;
+	    
+	    outprim->mode = prim->mode;
+	    outprim->begin = (j == 0 && prim->begin);
+	    outprim->end = (nr == remaining && prim->end);
+	    outprim->start = prim->start + j;
+	    outprim->count = nr;
+	    
+	    if (nr == remaining) {
+	       /* Finished. 
+		*/
+	       j += nr;		
+	       csr += nr;
+	       available = align(split->limits->max_verts - csr - 1, 2); 
+	    }
+	    else {
+	       /* Wrapped the primitive: 
+		*/
+	       _mesa_printf("wrap %d %d\n", nr, first-incr);
+
+	       j += nr - (first - incr);
+	       flush_vertex(split);
+	       csr = 0;
+	       available = align(split->limits->max_verts - csr - 1, 2); 
+	    }
+	 }
+      }
+      else if (split->ib == NULL) {
+	 /* XXX: could at least send the first max_verts off from the
+	  * inplace buffers.
+	  */
+
+	 /* else convert to indexed primitive and pass to split_elts,
+	  * which will do the necessary copying and turn it back into a
+	  * vertex primitive for rendering...
+	  */
+	 struct _mesa_index_buffer ib;
+	 struct _mesa_prim tmpprim;
+	 GLuint *elts = malloc(count * sizeof(GLuint));
+	 GLuint j;
+	 
+	 for (j = 0; j < count; j++)
+	    elts[j] = prim->start + j;
+
+	 ib.count = count;
+	 ib.type = GL_UNSIGNED_INT;
+	 ib.obj = split->ctx->Array.NullBufferObj;
+	 ib.ptr = elts;
+	 ib.rebase = 0;		/* ? */
+	    
+	 tmpprim = *prim;
+	 tmpprim.indexed = 1;
+	 tmpprim.start = 0;
+	 tmpprim.count = count;
+
+	 flush_vertex(split);
+
+	 vbo_split_copy(split->ctx,
+			split->array,
+			&tmpprim, 1, 
+			&ib,
+			split->draw,
+			split->limits);
+	    
+	 free(elts);
+      }
+      else {
+	 flush_vertex(split);
+
+	 vbo_split_copy(split->ctx,
+			split->array,
+			prim, 1, 
+			split->ib,
+			split->draw,
+			split->limits);
+      }
+   }
+
+   flush_vertex(split);
+}
+
+
+void vbo_split_inplace( GLcontext *ctx,
+			const struct gl_client_array *arrays[],
+			const struct _mesa_prim *prim,
+			GLuint nr_prims,
+			const struct _mesa_index_buffer *ib,
+			GLuint min_index,
+			GLuint max_index,
+			vbo_draw_func draw,
+			const struct split_limits *limits )
+{
+   struct split_context split;
+
+   memset(&split, 0, sizeof(split));
+
+   split.ctx = ctx;
+   split.array = arrays;
+   split.prim = prim;
+   split.nr_prims = nr_prims;
+   split.ib = ib;
+   split.min_index = min_index;
+   split.max_index = max_index;
+   split.draw = draw;
+   split.limits = limits;
+
+   split_prims( &split );
+}
+
+



More information about the mesa-commit mailing list