Checkpoint of new vbo-building code. Currently builds regular arrays
authorKeith Whitwell <keith@tungstengraphics.com>
Sun, 29 Oct 2006 09:46:11 +0000 (09:46 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Sun, 29 Oct 2006 09:46:11 +0000 (09:46 +0000)
rather than VBO's - VBOs are easy but need to look closer at the
driver interface.  The trivial/tri demo works.

15 files changed:
src/mesa/vbo/vbo_attrib.h [new file with mode: 0644]
src/mesa/vbo/vbo_attrib_tmp.h [new file with mode: 0644]
src/mesa/vbo/vbo_context.c [new file with mode: 0644]
src/mesa/vbo/vbo_context.h [new file with mode: 0644]
src/mesa/vbo/vbo_exec.c [new file with mode: 0644]
src/mesa/vbo/vbo_exec.h [new file with mode: 0644]
src/mesa/vbo/vbo_exec_api.c [new file with mode: 0644]
src/mesa/vbo/vbo_exec_array.c [new file with mode: 0644]
src/mesa/vbo/vbo_exec_draw.c [new file with mode: 0644]
src/mesa/vbo/vbo_exec_eval.c [new file with mode: 0644]
src/mesa/vbo/vbo_save.c [new file with mode: 0644]
src/mesa/vbo/vbo_save.h [new file with mode: 0644]
src/mesa/vbo/vbo_save_api.c [new file with mode: 0644]
src/mesa/vbo/vbo_save_draw.c [new file with mode: 0644]
src/mesa/vbo/vbo_save_loopback.c [new file with mode: 0644]

diff --git a/src/mesa/vbo/vbo_attrib.h b/src/mesa/vbo/vbo_attrib.h
new file mode 100644 (file)
index 0000000..caedbd5
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) Intel Corp.  2006.  All Rights Reserved.
+ Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ develop this 3D driver.
+ 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 (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 NONINFRINGEMENT.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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.
+ **********************************************************************/
+ /*
+  * Authors:
+  *   Keith Whitwell <keith@tungstengraphics.com>
+  */
+
+#ifndef VBO_ATTRIB_H
+#define VBO_ATTRIB_H
+
+
+/*
+ * Note: The first attributes match the VERT_ATTRIB_* definitions
+ * in mtypes.h.  However, the tnl module has additional attributes
+ * for materials, color indexes, edge flags, etc.
+ */
+/* Although it's nice to use these as bit indexes in a DWORD flag, we
+ * could manage without if necessary.  Another limit currently is the
+ * number of bits allocated for these numbers in places like vertex
+ * program instruction formats and register layouts.
+ */
+enum {
+       VBO_ATTRIB_POS = 0,
+       VBO_ATTRIB_WEIGHT = 1,
+       VBO_ATTRIB_NORMAL = 2,
+       VBO_ATTRIB_COLOR0 = 3,
+       VBO_ATTRIB_COLOR1 = 4,
+       VBO_ATTRIB_FOG = 5,
+       VBO_ATTRIB_INDEX = 6,        
+       VBO_ATTRIB_EDGEFLAG = 7,     
+       VBO_ATTRIB_TEX0 = 8,
+       VBO_ATTRIB_TEX1 = 9,
+       VBO_ATTRIB_TEX2 = 10,
+       VBO_ATTRIB_TEX3 = 11,
+       VBO_ATTRIB_TEX4 = 12,
+       VBO_ATTRIB_TEX5 = 13,
+       VBO_ATTRIB_TEX6 = 14,
+       VBO_ATTRIB_TEX7 = 15,
+
+       VBO_ATTRIB_GENERIC0 = 16, /* Not used? */
+       VBO_ATTRIB_GENERIC1 = 17,
+       VBO_ATTRIB_GENERIC2 = 18,
+       VBO_ATTRIB_GENERIC3 = 19,
+       VBO_ATTRIB_GENERIC4 = 20,
+       VBO_ATTRIB_GENERIC5 = 21,
+       VBO_ATTRIB_GENERIC6 = 22,
+       VBO_ATTRIB_GENERIC7 = 23,
+       VBO_ATTRIB_GENERIC8 = 24,
+       VBO_ATTRIB_GENERIC9 = 25,
+       VBO_ATTRIB_GENERIC10 = 26,
+       VBO_ATTRIB_GENERIC11 = 27,
+       VBO_ATTRIB_GENERIC12 = 28,
+       VBO_ATTRIB_GENERIC13 = 29,
+       VBO_ATTRIB_GENERIC14 = 30,
+       VBO_ATTRIB_GENERIC15 = 31,
+
+       /* XXX: in the vertex program InputsRead flag, we alias
+        * materials and generics and use knowledge about the program
+        * (whether it is a fixed-function emulation) to
+        * differentiate.  Here we must keep them apart instead.
+        */
+       VBO_ATTRIB_MAT_FRONT_AMBIENT = 32, 
+       VBO_ATTRIB_MAT_BACK_AMBIENT = 33,
+       VBO_ATTRIB_MAT_FRONT_DIFFUSE = 34,
+       VBO_ATTRIB_MAT_BACK_DIFFUSE = 35,
+       VBO_ATTRIB_MAT_FRONT_SPECULAR = 36,
+       VBO_ATTRIB_MAT_BACK_SPECULAR = 37,
+       VBO_ATTRIB_MAT_FRONT_EMISSION = 38,
+       VBO_ATTRIB_MAT_BACK_EMISSION = 39,
+       VBO_ATTRIB_MAT_FRONT_SHININESS = 40,
+       VBO_ATTRIB_MAT_BACK_SHININESS = 41,
+       VBO_ATTRIB_MAT_FRONT_INDEXES = 42,
+       VBO_ATTRIB_MAT_BACK_INDEXES = 43, 
+
+       VBO_ATTRIB_MAX = 44
+};
+
+#define VBO_ATTRIB_FIRST_MATERIAL VBO_ATTRIB_MAT_FRONT_AMBIENT
+
+#define VBO_MAX_COPIED_VERTS 3
+
+struct _mesa_prim {
+   GLuint mode:8;
+   GLuint indexed:1;
+   GLuint begin:1;
+   GLuint end:1;
+   GLuint weak:1;
+   GLuint pad:20;
+
+   GLuint start;
+   GLuint count;
+};
+
+/* Would like to call this a "vbo_index_buffer", but this would be
+ * confusing as the indices are not neccessarily yet in a non-null
+ * buffer object.
+ */
+struct _mesa_index_buffer {
+   GLuint count;
+   GLenum type;
+   struct gl_buffer_object *obj;
+   const void *ptr;
+   GLuint rebase;
+};
+
+
+#endif
diff --git a/src/mesa/vbo/vbo_attrib_tmp.h b/src/mesa/vbo/vbo_attrib_tmp.h
new file mode 100644 (file)
index 0000000..72a8b04
--- /dev/null
@@ -0,0 +1,485 @@
+/**************************************************************************
+
+Copyright 2002 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
+on 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 THEIR 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.
+
+**************************************************************************/
+
+#define ATTR1FV( A, V ) ATTR( A, 1, (V)[0], 0, 0, 1 )
+#define ATTR2FV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 )
+#define ATTR3FV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 )
+#define ATTR4FV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] )
+
+#define ATTR1F( A, X )          ATTR( A, 1, X, 0, 0, 1 )
+#define ATTR2F( A, X, Y )       ATTR( A, 2, X, Y, 0, 1 )
+#define ATTR3F( A, X, Y, Z )    ATTR( A, 3, X, Y, Z, 1 )
+#define ATTR4F( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W )
+
+#define MAT_ATTR( A, N, V ) ATTR( A, N, (V)[0], (V)[1], (V)[2], (V)[3] )
+
+static void GLAPIENTRY TAG(Vertex2f)( GLfloat x, GLfloat y )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR2F( VBO_ATTRIB_POS, x, y );
+}
+
+static void GLAPIENTRY TAG(Vertex2fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR2FV( VBO_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY TAG(Vertex3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3F( VBO_ATTRIB_POS, x, y, z );
+}
+
+static void GLAPIENTRY TAG(Vertex3fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3FV( VBO_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY TAG(Vertex4f)( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR4F( VBO_ATTRIB_POS, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(Vertex4fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR4FV( VBO_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord1f)( GLfloat x )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1F( VBO_ATTRIB_TEX0, x );
+}
+
+static void GLAPIENTRY TAG(TexCoord1fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1FV( VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord2f)( GLfloat x, GLfloat y )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR2F( VBO_ATTRIB_TEX0, x, y );
+}
+
+static void GLAPIENTRY TAG(TexCoord2fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR2FV( VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3F( VBO_ATTRIB_TEX0, x, y, z );
+}
+
+static void GLAPIENTRY TAG(TexCoord3fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3FV( VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord4f)( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR4F( VBO_ATTRIB_TEX0, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(TexCoord4fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR4FV( VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(Normal3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3F( VBO_ATTRIB_NORMAL, x, y, z );
+}
+
+static void GLAPIENTRY TAG(Normal3fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3FV( VBO_ATTRIB_NORMAL, v );
+}
+
+static void GLAPIENTRY TAG(FogCoordfEXT)( GLfloat x )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1F( VBO_ATTRIB_FOG, x );
+}
+
+static void GLAPIENTRY TAG(FogCoordfvEXT)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1FV( VBO_ATTRIB_FOG, v );
+}
+
+static void GLAPIENTRY TAG(Color3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3F( VBO_ATTRIB_COLOR0, x, y, z );
+}
+
+static void GLAPIENTRY TAG(Color3fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3FV( VBO_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY TAG(Color4f)( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR4F( VBO_ATTRIB_COLOR0, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(Color4fv)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR4FV( VBO_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY TAG(SecondaryColor3fEXT)( GLfloat x, GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3F( VBO_ATTRIB_COLOR1, x, y, z );
+}
+
+static void GLAPIENTRY TAG(SecondaryColor3fvEXT)( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR3FV( VBO_ATTRIB_COLOR1, v );
+}
+
+
+static void GLAPIENTRY TAG(EdgeFlag)( GLboolean b )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1F( VBO_ATTRIB_EDGEFLAG, (GLfloat)b );
+}
+
+static void GLAPIENTRY TAG(Indexf)( GLfloat f )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1F( VBO_ATTRIB_INDEX, f );
+}
+
+static void GLAPIENTRY TAG(Indexfv)( const GLfloat *f )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   ATTR1FV( VBO_ATTRIB_INDEX, f );
+}
+
+
+static void GLAPIENTRY TAG(MultiTexCoord1f)( GLenum target, GLfloat x  )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR1F( attr, x );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord1fv)( GLenum target, const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR1FV( attr, v );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord2f)( GLenum target, GLfloat x, GLfloat y )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR2F( attr, x, y );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord2fv)( GLenum target, const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR2FV( attr, v );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord3f)( GLenum target, GLfloat x, GLfloat y,
+                                   GLfloat z)
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR3F( attr, x, y, z );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord3fv)( GLenum target, const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR3FV( attr, v );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord4f)( GLenum target, GLfloat x, GLfloat y,
+                                   GLfloat z, GLfloat w )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR4F( attr, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord4fv)( GLenum target, const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+   ATTR4FV( attr, v );
+}
+
+
+static void GLAPIENTRY TAG(VertexAttrib1fARB)( GLuint index, GLfloat x )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR1F(0, x);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR1F(VBO_ATTRIB_GENERIC0 + index, x);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib1fvARB)( GLuint index, 
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR1FV(0, v);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR1FV(VBO_ATTRIB_GENERIC0 + index, v);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fARB)( GLuint index, GLfloat x, 
+                                             GLfloat y )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR2F(0, x, y);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR2F(VBO_ATTRIB_GENERIC0 + index, x, y);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fvARB)( GLuint index,
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR2FV(0, v);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR2FV(VBO_ATTRIB_GENERIC0 + index, v);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fARB)( GLuint index, GLfloat x,
+                                             GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR3F(0, x, y, z);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR3F(VBO_ATTRIB_GENERIC0 + index, x, y, z);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fvARB)( GLuint index,
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR3FV(0, v);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR3FV(VBO_ATTRIB_GENERIC0 + index, v);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fARB)( GLuint index, GLfloat x,
+                                             GLfloat y, GLfloat z,
+                                             GLfloat w )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR4F(0, x, y, z, w);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR4F(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
+   else
+      ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fvARB)( GLuint index, 
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index == 0) 
+      ATTR4FV(0, v);
+   else if (index < MAX_VERTEX_ATTRIBS)
+      ATTR4FV(VBO_ATTRIB_GENERIC0 + index, v);
+   else
+      ERROR();
+}
+
+
+/* Although we don't export NV_vertex_program, these entrypoints are
+ * used by the display list and other code specifically because of
+ * their property of aliasing with other attributes.
+ */
+static void GLAPIENTRY TAG(VertexAttrib1fNV)( GLuint index, GLfloat x )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX)
+      ATTR1F(index, x);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib1fvNV)( GLuint index, 
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR1FV(index, v);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fNV)( GLuint index, GLfloat x, 
+                                             GLfloat y )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR2F(index, x, y);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fvNV)( GLuint index,
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR2FV(index, v);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fNV)( GLuint index, GLfloat x,
+                                             GLfloat y, GLfloat z )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR3F(index, x, y, z);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fvNV)( GLuint index,
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR3FV(index, v);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fNV)( GLuint index, GLfloat x,
+                                             GLfloat y, GLfloat z,
+                                             GLfloat w )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR4F(index, x, y, z, w);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fvNV)( GLuint index, 
+                                              const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   if (index < VBO_ATTRIB_MAX) 
+      ATTR4FV(index, v);
+}
+
+
+#define MAT( ATTR, N, face, params )                   \
+do {                                                   \
+   if (face != GL_BACK)                                        \
+      MAT_ATTR( ATTR, N, params ); /* front */         \
+   if (face != GL_FRONT)                               \
+      MAT_ATTR( ATTR + 1, N, params ); /* back */      \
+} while (0)
+
+
+/* Colormaterial conflicts are dealt with later.
+ */
+static void GLAPIENTRY TAG(Materialfv)( GLenum face, GLenum pname, 
+                              const GLfloat *params )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   switch (pname) {
+   case GL_EMISSION:
+      MAT( VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
+      break;
+   case GL_AMBIENT:
+      MAT( VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+      break;
+   case GL_DIFFUSE:
+      MAT( VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+      break;
+   case GL_SPECULAR:
+      MAT( VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
+      break;
+   case GL_SHININESS:
+      MAT( VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
+      break;
+   case GL_COLOR_INDEXES:
+      MAT( VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
+      break;
+   case GL_AMBIENT_AND_DIFFUSE:
+      MAT( VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+      MAT( VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+      break;
+   default:
+      ERROR();
+      return;
+   }
+}
+
+
+#undef ATTR1FV
+#undef ATTR2FV
+#undef ATTR3FV
+#undef ATTR4FV
+
+#undef ATTR1F
+#undef ATTR2F
+#undef ATTR3F
+#undef ATTR4F
+
+#undef MAT
+#undef MAT_ATTR
diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c
new file mode 100644 (file)
index 0000000..5f28e6b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.3
+ *
+ * Copyright (C) 1999-2005  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@tungstengraphics.com>
+ */
+
+#include "mtypes.h"
+#include "vbo_context.h"
+#include "imports.h"
+#include "api_arrayelt.h"
+
+/* Reach out and grab this to use as the default:
+ */
+extern void _tnl_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 );
+
+GLboolean _vbo_CreateContext( GLcontext *ctx )
+{
+   struct vbo_context *vbo = CALLOC_STRUCT(vbo_context);
+
+   ctx->swtnl_im = (void *)vbo;
+
+   /* Initialize the arrayelt helper
+    */
+   if (!ctx->aelt_context &&
+       !_ae_create_context( ctx )) {
+      return GL_FALSE;
+   }
+
+   /* Hook our functions into exec and compile dispatch tables.  These
+    * will pretty much be permanently installed, which means that the
+    * vtxfmt mechanism can be removed now.
+    */
+   vbo_exec_init( ctx );
+   vbo_save_init( ctx );
+
+   /* By default: 
+    */
+   vbo->draw_prims = _tnl_draw_prims;
+   
+   return GL_TRUE;
+}
+
+void vbo_save_invalidate_state( GLcontext *ctx, GLuint new_state )
+{
+   _ae_invalidate_state(ctx, new_state);
+}
+
+
+void _vbo_DestroyContext( GLcontext *ctx )
+{
+   if (ctx->aelt_context) {
+      _ae_destroy_context( ctx );
+      ctx->aelt_context = NULL;
+   }
+
+   FREE(vbo_context(ctx));
+   ctx->swtnl_im = NULL;
+
+}
diff --git a/src/mesa/vbo/vbo_context.h b/src/mesa/vbo/vbo_context.h
new file mode 100644 (file)
index 0000000..6b0f14d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 builder module
+ *
+ * This module hooks into the GL dispatch table and catches all vertex
+ * building and drawing commands, such as glVertex3f, glBegin and
+ * glDrawArrays.  The module stores all incoming vertex data as arrays
+ * in GL vertex buffer objects (VBOs), and translates all drawing
+ * commands into calls to a driver supplied DrawPrimitives() callback.
+ *
+ * The module captures both immediate mode and display list drawing,
+ * and manages the allocation, reference counting and deallocation of
+ * vertex buffer objects itself.
+ * 
+ * The DrawPrimitives() callback can be either implemented by the
+ * driver itself or hooked to the tnl module's _tnl_draw_primitives()
+ * function for hardware without tnl capablilties or during fallbacks.
+ */
+
+
+#ifndef _VBO_CONTEXT_H
+#define _VBO_CONTEXT_H
+
+#include "vbo_attrib.h"
+#include "vbo_save.h"
+#include "vbo_exec.h"
+
+GLboolean _vbo_CreateContext( GLcontext *ctx );
+void _vbo_DestroyContext( GLcontext *ctx );
+
+
+struct vbo_context {
+   struct vbo_exec_context exec;
+   struct vbo_save_context save;
+
+   /* 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 );
+};
+
+
+static INLINE struct vbo_context *vbo_context(GLcontext *ctx) 
+{
+   return (struct vbo_context *)(ctx->swtnl_im);
+}
+
+enum {
+   VP_NONE = 1,
+   VP_NV,
+   VP_ARB
+};
+
+static INLINE GLuint get_program_mode( GLcontext *ctx )
+{
+   if (!ctx->VertexProgram._Enabled)
+      return VP_NONE;
+   else if (ctx->VertexProgram.Current->IsNVProgram)
+      return VP_NV;
+   else
+      return VP_ARB;
+}
+
+
+#endif
diff --git a/src/mesa/vbo/vbo_exec.c b/src/mesa/vbo/vbo_exec.c
new file mode 100644 (file)
index 0000000..4499803
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.3
+ *
+ * Copyright (C) 1999-2005  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@tungstengraphics.com>
+ */
+
+
+#include "api_arrayelt.h"
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "dlist.h"
+#include "vtxfmt.h"
+
+#include "vbo_context.h"
+
+
+#define NR_LEGACY_ATTRIBS 16
+#define NR_GENERIC_ATTRIBS 16
+#define NR_MAT_ATTRIBS 12
+
+static void init_legacy_currval(GLcontext *ctx)
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   struct gl_client_array *arrays = exec->legacy_currval;
+   GLuint i;
+
+   memset(arrays, 0, sizeof(*arrays) * NR_LEGACY_ATTRIBS);
+
+   /* Set up a constant (StrideB == 0) array for each current
+    * attribute:
+    */
+   for (i = 0; i < NR_LEGACY_ATTRIBS; i++) {
+      struct gl_client_array *cl = &arrays[i];
+
+      switch (i) {
+      case VBO_ATTRIB_EDGEFLAG:
+        cl->Type = GL_UNSIGNED_BYTE;
+        cl->Ptr = (const void *)&ctx->Current.EdgeFlag;
+        break;
+      case VBO_ATTRIB_INDEX:
+        cl->Type = GL_FLOAT;
+        cl->Ptr = (const void *)&ctx->Current.Index;
+        break;
+      default:
+        cl->Type = GL_FLOAT;
+        cl->Ptr = (const void *)ctx->Current.Attrib[i];
+        break;
+      }
+
+      /* This will have to be determined at runtime:
+       */
+      cl->Size = 1;
+      cl->Stride = 0;
+      cl->StrideB = 0;
+      cl->Enabled = 1;
+      cl->BufferObj = ctx->Array.NullBufferObj;
+   }
+}
+
+
+static void init_generic_currval(GLcontext *ctx)
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   struct gl_client_array *arrays = exec->generic_currval;
+   GLuint i;
+
+   memset(arrays, 0, sizeof(*arrays) * NR_GENERIC_ATTRIBS);
+
+   for (i = 0; i < NR_GENERIC_ATTRIBS; i++) {
+      struct gl_client_array *cl = &arrays[i];
+
+      /* 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;
+      cl->StrideB = 0;
+      cl->Enabled = 1;
+      cl->BufferObj = ctx->Array.NullBufferObj;
+   }
+}
+
+
+static void init_mat_currval(GLcontext *ctx)
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   struct gl_client_array *arrays = exec->mat_currval;
+   GLuint i;
+
+   memset(arrays, 0, sizeof(*arrays) * NR_GENERIC_ATTRIBS);
+
+   /* Set up a constant (StrideB == 0) array for each current
+    * attribute:
+    */
+   for (i = 0; i < NR_GENERIC_ATTRIBS; i++) {
+      struct gl_client_array *cl = &arrays[i];
+
+      /* Size is fixed for the material attributes, for others will
+       * be determined at runtime:
+       */
+      switch (i - VERT_ATTRIB_GENERIC0) {
+      case MAT_ATTRIB_FRONT_SHININESS:
+      case MAT_ATTRIB_BACK_SHININESS:
+        cl->Size = 1;
+        break;
+      case MAT_ATTRIB_FRONT_INDEXES:
+      case MAT_ATTRIB_BACK_INDEXES:
+        cl->Size = 3;
+        break;
+      default:
+        cl->Size = 4;
+        break;
+      }
+
+      if (i < MAT_ATTRIB_MAX)
+        cl->Ptr = (const void *)ctx->Light.Material.Attrib[i];
+      else 
+        cl->Ptr = (const void *)ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i];
+
+      cl->Type = GL_FLOAT;
+      cl->Stride = 0;
+      cl->StrideB = 0;
+      cl->Enabled = 1;
+      cl->BufferObj = ctx->Array.NullBufferObj;
+   }
+}
+
+
+void vbo_exec_init( GLcontext *ctx )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   exec->ctx = ctx;
+
+   /* Initialize the arrayelt helper
+    */
+   if (!ctx->aelt_context &&
+       !_ae_create_context( ctx )) 
+      return;
+
+   vbo_exec_vtx_init( exec );
+   vbo_exec_array_init( exec );
+
+   init_legacy_currval( ctx );
+   init_generic_currval( ctx );
+   init_mat_currval( ctx );
+
+   ctx->Driver.NeedFlush = 0;
+   ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+   ctx->Driver.FlushVertices = vbo_exec_FlushVertices;
+
+   exec->eval.recalculate_maps = 1;
+}
+
+
+void vbo_exec_destroy( GLcontext *ctx )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   if (ctx->aelt_context) {
+      _ae_destroy_context( ctx );
+      ctx->aelt_context = NULL;
+   }
+
+   vbo_exec_vtx_destroy( exec );
+   vbo_exec_array_destroy( exec );
+}
+
+/* Really want to install these callbacks to a central facility to be
+ * invoked according to the state flags.  That will have to wait for a
+ * mesa rework:
+ */ 
+void vbo_exec_invalidate_state( GLcontext *ctx, GLuint new_state )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   if (new_state & (_NEW_PROGRAM|_NEW_EVAL))
+      exec->eval.recalculate_maps = 1;
+
+   _ae_invalidate_state(ctx, new_state);
+}
+
+
+void vbo_exec_wakeup( GLcontext *ctx )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   ctx->Driver.FlushVertices = vbo_exec_FlushVertices;
+   ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+
+   /* Hook our functions into exec and compile dispatch tables.
+    */
+   _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
+
+   /* Assume we haven't been getting state updates either:
+    */
+   vbo_exec_invalidate_state( ctx, ~0 );
+}
+
+
+
diff --git a/src/mesa/vbo/vbo_exec.h b/src/mesa/vbo/vbo_exec.h
new file mode 100644 (file)
index 0000000..4542d28
--- /dev/null
@@ -0,0 +1,175 @@
+/**************************************************************************
+
+Copyright 2002 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
+on 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 THEIR 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __VBO_EXEC_H__
+#define __VBO_EXEC_H__
+
+#include "mtypes.h"
+#include "vbo_attrib.h"
+
+
+#define VBO_MAX_PRIM 64
+
+/* Wierd implementation stuff:
+ */
+#define VBO_VERT_BUFFER_SIZE (1024*16) /* dwords == 64k */
+#define VBO_MAX_ATTR_CODEGEN 16 
+#define ERROR_ATTRIB 16
+
+
+
+
+struct vbo_exec_eval1_map {
+   struct gl_1d_map *map;
+   GLuint sz;
+};
+
+struct vbo_exec_eval2_map {
+   struct gl_2d_map *map;
+   GLuint sz;
+};
+
+
+
+struct vbo_exec_copied_vtx {
+   GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
+   GLuint nr;
+};
+
+
+typedef void (*vbo_attrfv_func)( const GLfloat * );
+
+
+struct vbo_exec_context
+{
+   GLcontext *ctx;   
+   GLvertexformat vtxfmt;
+
+   struct gl_client_array legacy_currval[16];
+   struct gl_client_array generic_currval[16];
+   struct gl_client_array mat_currval[16];
+
+   struct {
+      struct gl_buffer_object *bufferobj;
+      GLubyte *buffer_map;
+
+      GLuint vertex_size;
+
+      struct _mesa_prim prim[VBO_MAX_PRIM];
+      GLuint prim_count;
+
+      GLfloat *vbptr;               /* cursor, points into buffer */
+      GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */
+
+      GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->Current, ctx->Light.Material */
+      GLfloat CurrentFloatEdgeFlag;
+
+      GLuint vert_count;
+      GLuint max_vert;
+      struct vbo_exec_copied_vtx copied;
+
+      GLubyte attrsz[VBO_ATTRIB_MAX];
+      GLubyte active_sz[VBO_ATTRIB_MAX];
+
+      GLfloat *attrptr[VBO_ATTRIB_MAX]; 
+      struct gl_client_array arrays[VBO_ATTRIB_MAX];
+
+      /* According to program mode, the values above plus current
+       * values are squashed down to the 32 attributes passed to the
+       * vertex program below:
+       */
+      GLuint program_mode;
+      GLuint enabled_flags;
+      const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+   } vtx;
+
+   
+   struct {
+      GLboolean recalculate_maps;
+      struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX];
+      struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX];
+   } eval;
+
+   struct {
+      GLuint program_mode;
+      GLuint enabled_flags;
+      GLuint array_obj;
+
+      /* These just mirror the current arrayobj (todo: make arrayobj
+       * look like this and remove the mirror):
+       */
+      const struct gl_client_array *legacy_array[16];
+      const struct gl_client_array *generic_array[16];
+
+      /* Arrays and current values manipulated according to program
+       * mode, etc.  These are the attributes as seen by vertex
+       * programs:
+       */
+      const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+
+
+      struct gl_buffer_object *index_obj;
+   } array;
+};
+
+
+
+/* External API:
+ */
+void vbo_exec_init( GLcontext *ctx );
+void vbo_exec_destroy( GLcontext *ctx );
+void vbo_exec_invalidate_state( GLcontext *ctx, GLuint new_state );
+void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags );
+void vbo_exec_wakeup( GLcontext *ctx );
+
+
+/* Internal functions:
+ */
+void vbo_exec_array_init( struct vbo_exec_context *exec );
+void vbo_exec_array_destroy( struct vbo_exec_context *exec );
+
+
+void vbo_exec_vtx_init( struct vbo_exec_context *exec );
+void vbo_exec_vtx_destroy( struct vbo_exec_context *exec );
+void vbo_exec_vtx_flush( struct vbo_exec_context *exec );
+void vbo_exec_vtx_wrap( struct vbo_exec_context *exec );
+
+void vbo_exec_eval_update( struct vbo_exec_context *exec );
+
+void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec, 
+                                    GLfloat u, GLfloat v );
+
+void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec,
+                                    GLfloat u);
+
+#endif
diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
new file mode 100644 (file)
index 0000000..c764c4d
--- /dev/null
@@ -0,0 +1,716 @@
+/**************************************************************************
+
+Copyright 2002 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
+on 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 THEIR 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "vtxfmt.h"
+#include "dlist.h"
+#include "state.h"
+#include "light.h"
+#include "api_arrayelt.h"
+#include "api_noop.h"
+#include "dispatch.h"
+
+#include "vbo_context.h"
+
+static void reset_attrfv( struct vbo_exec_context *exec );
+
+
+/* Close off the last primitive, execute the buffer, restart the
+ * primitive.  
+ */
+static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
+{
+   if (exec->vtx.prim_count == 0) {
+      exec->vtx.copied.nr = 0;
+      exec->vtx.vert_count = 0;
+      exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
+   }
+   else {
+      GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
+      GLuint last_count;
+
+      if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+        GLint i = exec->vtx.prim_count - 1;
+        assert(i >= 0);
+        exec->vtx.prim[i].count = (exec->vtx.vert_count - 
+                                   exec->vtx.prim[i].start);
+      }
+
+      last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
+
+      /* Execute the buffer and save copied vertices.
+       */
+      if (exec->vtx.vert_count)
+        vbo_exec_vtx_flush( exec );
+      else {
+        exec->vtx.prim_count = 0;
+        exec->vtx.copied.nr = 0;
+      }
+
+      /* Emit a glBegin to start the new list.
+       */
+      assert(exec->vtx.prim_count == 0);
+
+      if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+        exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
+        exec->vtx.prim[0].start = 0;
+        exec->vtx.prim[0].count = 0;
+        exec->vtx.prim_count++;
+      
+        if (exec->vtx.copied.nr == last_count)
+           exec->vtx.prim[0].begin = last_begin;
+      }
+   }
+}
+
+
+/* Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
+ */
+void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
+{
+   GLfloat *data = exec->vtx.copied.buffer;
+   GLuint i;
+
+   /* Run pipeline on current vertices, copy wrapped vertices
+    * to exec->vtx.copied.
+    */
+   vbo_exec_wrap_buffers( exec );
+   
+   /* Copy stored stored vertices to start of new list. 
+    */
+   assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
+
+   for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+      _mesa_memcpy( exec->vtx.vbptr, data, 
+                   exec->vtx.vertex_size * sizeof(GLfloat));
+      exec->vtx.vbptr += exec->vtx.vertex_size;
+      data += exec->vtx.vertex_size;
+      exec->vtx.vert_count++;
+   }
+
+   exec->vtx.copied.nr = 0;
+}
+
+
+/*
+ * Copy the active vertex's values to the ctx->Current fields.
+ */
+static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
+{
+   GLcontext *ctx = exec->ctx;
+   GLuint i;
+
+   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
+      if (exec->vtx.attrsz[i]) {
+         /* Note: the exec->vtx.current[i] pointers point into the
+          * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
+          */
+        COPY_CLEAN_4V(exec->vtx.current[i], 
+                      exec->vtx.attrsz[i], 
+                      exec->vtx.attrptr[i]);
+
+        /* This triggers rather too much recalculation of Mesa state
+         * that doesn't get used (eg light positions).
+         */
+        if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
+            i <= VBO_ATTRIB_MAT_BACK_INDEXES)
+           ctx->NewState |= _NEW_LIGHT;
+      }
+   }
+
+   /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
+    * will trash adjacent memory!)
+    */
+   if (exec->vtx.attrsz[VBO_ATTRIB_INDEX]) {
+      ctx->Current.Index = exec->vtx.attrptr[VBO_ATTRIB_INDEX][0];
+   }
+
+   /* Edgeflag requires additional treatment:
+    */
+   if (exec->vtx.attrsz[VBO_ATTRIB_EDGEFLAG]) {
+      ctx->Current.EdgeFlag = (exec->vtx.CurrentFloatEdgeFlag == 1.0);
+   }
+
+   /* Colormaterial -- this kindof sucks.
+    */
+   if (ctx->Light.ColorMaterialEnabled &&
+       exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
+      _mesa_update_color_material(ctx, 
+                                 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
+   }
+
+   ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+}
+
+
+static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
+{
+   GLcontext *ctx = exec->ctx;
+   GLint i;
+
+   /* Edgeflag requires additional treatment:
+    */
+   exec->vtx.CurrentFloatEdgeFlag = 
+      (GLfloat)ctx->Current.EdgeFlag;
+   
+   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) 
+      switch (exec->vtx.attrsz[i]) {
+      case 4: exec->vtx.attrptr[i][3] = exec->vtx.current[i][3];
+      case 3: exec->vtx.attrptr[i][2] = exec->vtx.current[i][2];
+      case 2: exec->vtx.attrptr[i][1] = exec->vtx.current[i][1];
+      case 1: exec->vtx.attrptr[i][0] = exec->vtx.current[i][0];
+        break;
+      }
+
+   ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */ 
+static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
+                                         GLuint attr,
+                                         GLuint newsz )
+{
+   GLcontext *ctx = exec->ctx;
+   GLint lastcount = exec->vtx.vert_count;
+   GLfloat *tmp;
+   GLuint oldsz;
+   GLuint i;
+
+   /* Run pipeline on current vertices, copy wrapped vertices
+    * to exec->vtx.copied.
+    */
+   vbo_exec_wrap_buffers( exec );
+
+
+   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
+    * when the attribute already exists in the vertex and is having
+    * its size increased.  
+    */
+   vbo_exec_copy_to_current( exec );
+
+
+   /* Heuristic: Attempt to isolate attributes received outside
+    * begin/end so that they don't bloat the vertices.
+    */
+   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
+       exec->vtx.attrsz[attr] == 0 && 
+       lastcount > 8 &&
+       exec->vtx.vertex_size) {
+      reset_attrfv( exec );
+   }
+
+   /* Fix up sizes:
+    */
+   oldsz = exec->vtx.attrsz[attr];
+   exec->vtx.attrsz[attr] = newsz;
+
+   exec->vtx.vertex_size += newsz - oldsz;
+   exec->vtx.max_vert = VBO_VERT_BUFFER_SIZE / exec->vtx.vertex_size;
+   exec->vtx.vert_count = 0;
+   exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
+   
+
+   /* Recalculate all the attrptr[] values
+    */
+   for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) {
+      if (exec->vtx.attrsz[i]) {
+        exec->vtx.attrptr[i] = tmp;
+        tmp += exec->vtx.attrsz[i];
+      }
+      else 
+        exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
+   }
+
+   /* Copy from current to repopulate the vertex with correct values.
+    */
+   vbo_exec_copy_from_current( exec );
+
+   /* Replay stored vertices to translate them
+    * to new format here.
+    *
+    * -- No need to replay - just copy piecewise
+    */
+   if (exec->vtx.copied.nr)
+   {
+      GLfloat *data = exec->vtx.copied.buffer;
+      GLfloat *dest = exec->vtx.vbptr;
+      GLuint j;
+
+      assert(exec->vtx.vbptr == (GLfloat *)exec->vtx.buffer_map);
+      
+      for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+        for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
+           if (exec->vtx.attrsz[j]) {
+              if (j == attr) {
+                 if (oldsz) {
+                    COPY_CLEAN_4V( dest, oldsz, data );
+                    data += oldsz;
+                    dest += newsz;
+                 } else {
+                    COPY_SZ_4V( dest, newsz, exec->vtx.current[j] );
+                    dest += newsz;
+                 }
+              }
+              else {
+                 GLuint sz = exec->vtx.attrsz[j];
+                 COPY_SZ_4V( dest, sz, data );
+                 dest += sz;
+                 data += sz;
+              }
+           }
+        }
+      }
+
+      exec->vtx.vbptr = dest;
+      exec->vtx.vert_count += exec->vtx.copied.nr;
+      exec->vtx.copied.nr = 0;
+   }
+}
+
+
+static void vbo_exec_fixup_vertex( GLcontext *ctx,
+                                  GLuint attr, GLuint sz )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   int i;
+
+   if (sz > exec->vtx.attrsz[attr]) {
+      /* New size is larger.  Need to flush existing vertices and get
+       * an enlarged vertex format.
+       */
+      vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
+   }
+   else if (sz < exec->vtx.active_sz[attr]) {
+      static const GLfloat id[4] = { 0, 0, 0, 1 };
+
+      /* New size is smaller - just need to fill in some
+       * zeros.  Don't need to flush or wrap.
+       */
+      for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
+        exec->vtx.attrptr[attr][i-1] = id[i-1];
+   }
+
+   exec->vtx.active_sz[attr] = sz;
+
+   /* Does setting NeedFlush belong here?  Necessitates resetting
+    * vtxfmt on each flush (otherwise flags won't get reset
+    * afterwards).
+    */
+   if (attr == 0) 
+      exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+   else 
+      exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+
+
+
+/* 
+ */
+#define ATTR( A, N, V0, V1, V2, V3 )                           \
+do {                                                           \
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;    \
+                                                               \
+   if (exec->vtx.active_sz[A] != N)                            \
+      vbo_exec_fixup_vertex(ctx, A, N);                        \
+                                                               \
+   {                                                           \
+      GLfloat *dest = exec->vtx.attrptr[A];                    \
+      if (N>0) dest[0] = V0;                                   \
+      if (N>1) dest[1] = V1;                                   \
+      if (N>2) dest[2] = V2;                                   \
+      if (N>3) dest[3] = V3;                                   \
+   }                                                           \
+                                                               \
+   if ((A) == 0) {                                             \
+      GLuint i;                                                        \
+                                                               \
+      for (i = 0; i < exec->vtx.vertex_size; i++)              \
+        exec->vtx.vbptr[i] = exec->vtx.vertex[i];              \
+                                                               \
+      exec->vtx.vbptr += exec->vtx.vertex_size;                        \
+      exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;    \
+                                                               \
+      if (++exec->vtx.vert_count >= exec->vtx.max_vert)                \
+        vbo_exec_vtx_wrap( exec );                             \
+   }                                                           \
+} while (0)
+
+
+#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
+#define TAG(x) vbo_##x
+
+#include "vbo_attrib_tmp.h"
+
+
+
+
+
+/* Eval
+ */
+static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   {
+      GLint i;
+      if (exec->eval.recalculate_maps) 
+        vbo_exec_eval_update( exec );
+
+      for (i = 0 ; i <= VBO_ATTRIB_INDEX ; i++) {
+        if (exec->eval.map1[i].map) 
+           if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
+              vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
+      }
+   }
+
+
+   _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 
+                 exec->vtx.vertex_size * sizeof(GLfloat));
+
+   vbo_exec_do_EvalCoord1f( exec, u );
+
+   _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+                 exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   {
+      GLint i;
+      if (exec->eval.recalculate_maps) 
+        vbo_exec_eval_update( exec );
+
+      for (i = 0 ; i <= VBO_ATTRIB_INDEX ; i++) {
+        if (exec->eval.map2[i].map) 
+           if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
+              vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
+      }
+
+      if (ctx->Eval.AutoNormal) 
+        if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
+           vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
+   }
+
+   _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 
+                 exec->vtx.vertex_size * sizeof(GLfloat));
+
+   vbo_exec_do_EvalCoord2f( exec, u, v );
+
+   _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 
+                 exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
+{
+   vbo_exec_EvalCoord1f( u[0] );
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
+{
+   vbo_exec_EvalCoord2f( u[0], u[1] );
+}
+
+static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
+                (GLfloat) ctx->Eval.MapGrid1un);
+   GLfloat u = i * du + ctx->Eval.MapGrid1u1;
+
+   vbo_exec_EvalCoord1f( u );
+}
+
+
+static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 
+                (GLfloat) ctx->Eval.MapGrid2un);
+   GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 
+                (GLfloat) ctx->Eval.MapGrid2vn);
+   GLfloat u = i * du + ctx->Eval.MapGrid2u1;
+   GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
+
+   vbo_exec_EvalCoord2f( u, v );
+}
+
+
+/* Build a list of primitives on the fly.  Keep
+ * ctx->Driver.CurrentExecPrimitive uptodate as well.
+ */
+static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
+{
+   GET_CURRENT_CONTEXT( ctx ); 
+
+   if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+      int i;
+
+      if (ctx->NewState) {
+        _mesa_update_state( ctx );
+
+         if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+            (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBegin (invalid vertex/fragment program)");
+            return;
+         }
+
+        CALL_Begin(ctx->Exec, (mode));
+        return;
+      }
+
+      /* Heuristic: attempt to isolate attributes occuring outside
+       * begin/end pairs.
+       */
+      if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 
+        vbo_exec_FlushVertices( ctx, ~0 );
+
+      i = exec->vtx.prim_count++;
+      exec->vtx.prim[i].mode = mode;
+      exec->vtx.prim[i].begin = 1;
+      exec->vtx.prim[i].end = 0;
+      exec->vtx.prim[i].indexed = 0;
+      exec->vtx.prim[i].weak = 0;
+      exec->vtx.prim[i].pad = 0;
+      exec->vtx.prim[i].start = exec->vtx.vert_count;
+      exec->vtx.prim[i].count = 0;
+
+      ctx->Driver.CurrentExecPrimitive = mode;
+   }
+   else 
+      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+      
+}
+
+static void GLAPIENTRY vbo_exec_End( void )
+{
+   GET_CURRENT_CONTEXT( ctx ); 
+
+   if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+      int idx = exec->vtx.vert_count;
+      int i = exec->vtx.prim_count - 1;
+
+      exec->vtx.prim[i].end = 1; 
+      exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
+
+      ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+
+      if (exec->vtx.prim_count == VBO_MAX_PRIM)
+        vbo_exec_vtx_flush( exec );    
+   }
+   else 
+      _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+}
+
+
+static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
+{
+   GLvertexformat *vfmt = &exec->vtxfmt;
+
+   vfmt->ArrayElement = _ae_loopback_array_elt;                /* generic helper */
+   vfmt->Begin = vbo_exec_Begin;
+   vfmt->CallList = _mesa_CallList;
+   vfmt->CallLists = _mesa_CallLists;
+   vfmt->End = vbo_exec_End;
+   vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
+   vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
+   vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
+   vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
+   vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
+   vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
+
+   vfmt->Rectf = _mesa_noop_Rectf;
+   vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
+   vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
+
+
+   /* from attrib_tmp.h:
+    */
+   vfmt->Color3f = vbo_Color3f;
+   vfmt->Color3fv = vbo_Color3fv;
+   vfmt->Color4f = vbo_Color4f;
+   vfmt->Color4fv = vbo_Color4fv;
+   vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
+   vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
+   vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
+   vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
+   vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
+   vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
+   vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
+   vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
+   vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
+   vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
+   vfmt->Normal3f = vbo_Normal3f;
+   vfmt->Normal3fv = vbo_Normal3fv;
+   vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
+   vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
+   vfmt->TexCoord1f = vbo_TexCoord1f;
+   vfmt->TexCoord1fv = vbo_TexCoord1fv;
+   vfmt->TexCoord2f = vbo_TexCoord2f;
+   vfmt->TexCoord2fv = vbo_TexCoord2fv;
+   vfmt->TexCoord3f = vbo_TexCoord3f;
+   vfmt->TexCoord3fv = vbo_TexCoord3fv;
+   vfmt->TexCoord4f = vbo_TexCoord4f;
+   vfmt->TexCoord4fv = vbo_TexCoord4fv;
+   vfmt->Vertex2f = vbo_Vertex2f;
+   vfmt->Vertex2fv = vbo_Vertex2fv;
+   vfmt->Vertex3f = vbo_Vertex3f;
+   vfmt->Vertex3fv = vbo_Vertex3fv;
+   vfmt->Vertex4f = vbo_Vertex4f;
+   vfmt->Vertex4fv = vbo_Vertex4fv;
+   
+   vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
+   vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
+   vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
+   vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
+   vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
+   vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
+   vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
+   vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
+
+   vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
+   vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
+   vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
+   vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
+   vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
+   vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
+   vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
+   vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
+
+   vfmt->Materialfv = vbo_Materialfv;
+
+   vfmt->EdgeFlag = vbo_EdgeFlag;
+   vfmt->Indexf = vbo_Indexf;
+   vfmt->Indexfv = vbo_Indexfv;
+
+}
+
+
+static void vbo_exec_current_init( struct vbo_exec_context *exec ) 
+{
+   GLcontext *ctx = exec->ctx;
+   GLint i;
+
+   /* setup the pointers for the typical 16 vertex attributes */
+   for (i = 0; i < VBO_ATTRIB_FIRST_MATERIAL; i++) 
+      exec->vtx.current[i] = ctx->Current.Attrib[i];
+
+   /* setup pointers for the 12 material attributes */
+   for (i = 0; i < MAT_ATTRIB_MAX; i++)
+      exec->vtx.current[VBO_ATTRIB_FIRST_MATERIAL + i] = 
+        ctx->Light.Material.Attrib[i];
+
+   exec->vtx.current[VBO_ATTRIB_INDEX] = &ctx->Current.Index;
+   exec->vtx.current[VBO_ATTRIB_EDGEFLAG] = &exec->vtx.CurrentFloatEdgeFlag;
+}
+
+void vbo_exec_vtx_init( struct vbo_exec_context *exec )
+{
+   GLcontext *ctx = exec->ctx;
+   GLuint i;
+
+   /* Allocate a buffer object.  Will just reuse this object
+    * continuously.
+    */
+   exec->vtx.bufferobj = ctx->Array.NullBufferObj;
+   exec->vtx.buffer_map = ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE * sizeof(GLfloat), 64);
+
+   vbo_exec_current_init( exec );
+   vbo_exec_vtxfmt_init( exec );
+
+   /* Hook our functions into the dispatch table.
+    */
+   _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
+
+   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+      exec->vtx.attrsz[i] = 0;
+      exec->vtx.active_sz[i] = 0;
+      exec->vtx.inputs[i] = &exec->vtx.arrays[i];
+   }
+   exec->vtx.vertex_size = 0;
+}
+
+
+void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
+{
+   if (exec->vtx.buffer_map) {
+      ALIGN_FREE(exec->vtx.buffer_map);
+      exec->vtx.buffer_map = NULL;
+   }
+}
+
+
+void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+   if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
+      return;
+
+   if (exec->vtx.vert_count) {
+      vbo_exec_vtx_flush( exec );
+   }
+
+   if (exec->vtx.vertex_size) {
+      vbo_exec_copy_to_current( exec );
+      reset_attrfv( exec );
+   }
+
+   exec->ctx->Driver.NeedFlush = 0;
+}
+
+
+static void reset_attrfv( struct vbo_exec_context *exec )
+{   
+   GLuint i;
+
+   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+      exec->vtx.attrsz[i] = 0;
+      exec->vtx.active_sz[i] = 0;
+   }
+
+   exec->vtx.vertex_size = 0;
+}
+      
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
new file mode 100644 (file)
index 0000000..5cfa7a0
--- /dev/null
@@ -0,0 +1,367 @@
+/**************************************************************************
+ * 
+ * Copyright 2003 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.
+ * 
+ **************************************************************************/
+
+#include "glheader.h"
+#include "context.h"
+#include "state.h"
+#include "api_validate.h"
+#include "api_noop.h"
+#include "dispatch.h"
+
+#include "vbo_context.h"
+
+static GLuint get_max_index( GLuint count, GLuint type, 
+                            const GLvoid *indices )
+{
+   GLint i;
+
+   /* Compute max element.  This is only needed for upload of non-VBO,
+    * non-constant data elements.
+    *
+    * XXX: Postpone this calculation until it is known that it is
+    * needed.  Otherwise could scan this pointlessly in the all-vbo
+    * case.
+    */
+   switch(type) {
+   case GL_UNSIGNED_INT: {
+      const GLuint *ui_indices = (const GLuint *)indices;
+      GLuint max_ui = 0;
+      for (i = 0; i < count; i++)
+        if (ui_indices[i] > max_ui)
+           max_ui = ui_indices[i];
+      return max_ui;
+   }
+   case GL_UNSIGNED_SHORT: {
+      const GLushort *us_indices = (const GLushort *)indices;
+      GLuint max_us = 0;
+      for (i = 0; i < count; i++)
+        if (us_indices[i] > max_us)
+           max_us = us_indices[i];
+      return max_us;
+   }
+   case GL_UNSIGNED_BYTE: {
+      const GLubyte *ub_indices = (const GLubyte *)indices;
+      GLuint max_ub = 0;
+      for (i = 0; i < count; i++)
+        if (ub_indices[i] > max_ub)
+           max_ub = ub_indices[i];
+      return max_ub;
+   }
+   default:
+      return 0;
+   }
+}
+
+
+/* Just translate the arrayobj into a sane layout.
+ */
+static void bind_array_obj( GLcontext *ctx )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   GLuint i;
+
+   /* TODO: Fix the ArrayObj struct to keep legacy arrays in an array
+    * rather than as individual named arrays.  Then this function can
+    * go away.
+    */
+   exec->array.legacy_array[VERT_ATTRIB_POS] = &ctx->Array.ArrayObj->Vertex;
+   exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &ctx->Array.ArrayObj->Normal;
+   exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &ctx->Array.ArrayObj->Color;
+   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;
+
+   for (i = 0; i < 8; i++)
+      exec->array.legacy_array[VBO_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];
+   
+   exec->array.array_obj = ctx->Array.ArrayObj->Name;
+}
+
+static void recalculate_input_bindings( GLcontext *ctx )
+{
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   const struct gl_client_array **inputs = &exec->array.inputs[0];
+   GLuint i;
+
+   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
+       * into the generic slots.  This is the only situation where
+       * material values are available as per-vertex attributes.
+       */
+      for (i = 0; i <= VERT_ATTRIB_TEX7; i++) {
+        if (exec->array.legacy_array[i]->Enabled)
+           inputs[i] = exec->array.legacy_array[i];
+        else
+           inputs[i] = &exec->legacy_currval[i];
+      }
+
+      for (i = 0; i < MAT_ATTRIB_MAX; i++) {
+        inputs[VERT_ATTRIB_GENERIC0 + i] = &exec->mat_currval[i];
+      }
+      break;
+   case VP_NV:
+      /* NV_vertex_program - attribute arrays alias and override
+       * conventional, legacy arrays.  No materials, and the generic
+       * slots are vacant.
+       */
+      for (i = 0; i <= VERT_ATTRIB_TEX7; i++) {
+        if (exec->array.generic_array[i]->Enabled)
+           inputs[i] = exec->array.generic_array[i];
+        else if (exec->array.legacy_array[i]->Enabled)
+           inputs[i] = exec->array.legacy_array[i];
+        else
+           inputs[i] = &exec->legacy_currval[i];
+      }
+      break;
+   case VP_ARB:
+      /* ARB_vertex_program - Only the attribute zero (position) array
+       * aliases and overrides the legacy position array.  
+       *
+       * Otherwise, legacy attributes available in the legacy slots,
+       * generic attributes in the generic slots and materials are not
+       * available as per-vertex attributes.
+       */
+      if (exec->array.generic_array[0]->Enabled)
+        inputs[0] = exec->array.generic_array[0];
+      else if (exec->array.legacy_array[0]->Enabled)
+        inputs[0] = exec->array.legacy_array[0];
+      else
+        inputs[0] = &exec->legacy_currval[0];
+
+
+      for (i = 1; i <= VERT_ATTRIB_TEX7; i++) {
+        if (exec->array.legacy_array[i]->Enabled)
+           inputs[i] = exec->array.legacy_array[i];
+        else
+           inputs[i] = &exec->legacy_currval[i];
+      }
+
+      for (i = 0; i < 16; i++) {
+        if (exec->array.generic_array[0]->Enabled)
+           inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i];
+        else
+           inputs[VERT_ATTRIB_GENERIC0 + i] = &exec->generic_currval[i];
+      }
+      break;
+   }
+}
+
+static void bind_arrays( GLcontext *ctx )
+{
+#if 0
+   if (ctx->Array.ArrayObj.Name != exec->array.array_obj) {
+      bind_array_obj(ctx);
+      recalculate_input_bindings(ctx);
+   }
+   else if (exec->array.program_mode != get_program_mode(ctx) ||
+           exec->array.enabled_flags != ctx->Array.ArrayObj->_Enabled) {
+      
+      recalculate_input_bindings(ctx);
+   }
+#else
+   bind_array_obj(ctx);
+   recalculate_input_bindings(ctx);
+#endif
+}
+
+
+
+/***********************************************************************
+ * API functions.
+ */
+
+static void GLAPIENTRY
+vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
+   struct _mesa_prim prim[1];
+
+   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+      return;
+
+   FLUSH_CURRENT( ctx, 0 );
+
+   if (ctx->NewState)
+      _mesa_update_state( ctx );
+      
+   bind_arrays( ctx );
+
+   prim[0].begin = 1;
+   prim[0].end = 1;
+   prim[0].weak = 0;
+   prim[0].pad = 0;
+
+   if (exec->array.inputs[0]->BufferObj->Name) {
+      /* Use vertex attribute as a hint to tell us if we expect all
+       * arrays to be in VBO's and if so, don't worry about avoiding
+       * the upload of elements < start.
+       */
+      prim[0].mode = mode;
+      prim[0].start = start;
+      prim[0].count = count;
+      prim[0].indexed = 0;
+
+      vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, 0, start + count );
+   }
+   else {
+      /* If not using VBO's, we don't want to upload any more elements
+       * than necessary from the arrays as they will not be valid next
+       * time the application tries to draw with them.
+       */
+      prim[0].mode = mode;
+      prim[0].start = 0;
+      prim[0].count = count;
+      prim[0].indexed = 0;
+
+      vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count );
+   }
+}
+
+
+
+static void GLAPIENTRY
+vbo_exec_DrawRangeElements(GLenum mode,
+                          GLuint start, GLuint end,
+                          GLsizei count, GLenum type, const GLvoid *indices)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
+   struct _mesa_index_buffer ib;
+   struct _mesa_prim prim[1];
+
+   if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, type, indices ))
+      return;
+
+   FLUSH_CURRENT( ctx, 0 );
+
+   if (ctx->NewState)
+      _mesa_update_state( ctx );
+      
+   ib.count = count;
+   ib.type = type; 
+   ib.obj = ctx->Array.ElementArrayBufferObj;
+   ib.ptr = indices;
+
+   if (ctx->Array.ElementArrayBufferObj->Name) {
+      /* Use the fact that indices are in a VBO as a hint that the
+       * program has put all the arrays in VBO's and we don't have to
+       * worry about performance implications of start > 0.
+       *
+       * XXX: consider passing start as min_index to draw_prims instead.
+       */
+      ib.rebase = 0;
+   }
+   else {
+      ib.rebase = start;
+   }
+
+   prim[0].begin = 1;
+   prim[0].end = 1;
+   prim[0].weak = 0;
+   prim[0].pad = 0;
+   prim[0].mode = mode;
+   prim[0].start = 0;
+   prim[0].count = count;
+   prim[0].indexed = 1;
+
+   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, ib.rebase, end+1 );
+}
+
+
+static void GLAPIENTRY
+vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLuint max_index;
+
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+      return;
+
+   if (ctx->Array.ElementArrayBufferObj->Name) {
+      const GLvoid *map = ctx->Driver.MapBuffer(ctx,
+                                                GL_ELEMENT_ARRAY_BUFFER_ARB,
+                                                GL_DYNAMIC_READ_ARB,
+                                                ctx->Array.ElementArrayBufferObj);
+
+      max_index = get_max_index(count, type, ADD_POINTERS(map, indices));
+
+      ctx->Driver.UnmapBuffer(ctx,
+                             GL_ELEMENT_ARRAY_BUFFER_ARB,
+                             ctx->Array.ElementArrayBufferObj);
+   }
+   else {
+      max_index = get_max_index(count, type, indices);
+   }
+
+   vbo_exec_DrawRangeElements(mode, 0, max_index, count, type, indices);
+}
+
+
+/***********************************************************************
+ * Initialization
+ */
+
+
+
+
+void vbo_exec_array_init( struct vbo_exec_context *exec )
+{
+   GLcontext *ctx = exec->ctx;
+
+#if 1
+   exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays;
+   exec->vtxfmt.DrawElements = vbo_exec_DrawElements;
+   exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements;
+#else
+   exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays;
+   exec->vtxfmt.DrawElements = _mesa_noop_DrawElements;
+   exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements;
+#endif
+
+   exec->array.index_obj = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
+}
+
+
+void vbo_exec_array_destroy( struct vbo_exec_context *exec )
+{
+   GLcontext *ctx = exec->ctx;
+
+   ctx->Driver.DeleteBuffer(ctx, exec->array.index_obj);
+}
diff --git a/src/mesa/vbo/vbo_exec_draw.c b/src/mesa/vbo/vbo_exec_draw.c
new file mode 100644 (file)
index 0000000..f665c64
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  5.1
+ *
+ * Copyright (C) 1999-2003  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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "enums.h"
+#include "state.h"
+#include "macros.h"
+
+#include "vbo_context.h"
+
+
+static void vbo_exec_debug_verts( struct vbo_exec_context *exec )
+{
+   GLuint count = exec->vtx.vert_count;
+   GLuint i;
+
+   _mesa_printf("%s: %u vertices %d primitives, %d vertsize\n",
+               __FUNCTION__,
+               count,
+               exec->vtx.prim_count,
+               exec->vtx.vertex_size);
+
+   for (i = 0 ; i < exec->vtx.prim_count ; i++) {
+      struct _mesa_prim *prim = &exec->vtx.prim[i];
+      _mesa_printf("   prim %d: %s%s %d..%d %s %s\n",
+                  i, 
+                  _mesa_lookup_enum_by_nr(prim->mode),
+                  prim->weak ? " (weak)" : "",
+                  prim->start, 
+                  prim->start + prim->count,
+                  prim->begin ? "BEGIN" : "(wrap)",
+                  prim->end ? "END" : "(wrap)");
+   }
+}
+
+
+/*
+ * NOTE: Need to have calculated primitives by this point -- do it on the fly.
+ * NOTE: Old 'parity' issue is gone.
+ */
+static GLuint vbo_copy_vertices( struct vbo_exec_context *exec )
+{
+   GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
+   GLuint ovf, i;
+   GLuint sz = exec->vtx.vertex_size;
+   GLfloat *dst = exec->vtx.copied.buffer;
+   GLfloat *src = ((GLfloat *)exec->vtx.buffer_map + 
+                  exec->vtx.prim[exec->vtx.prim_count-1].start * 
+                  exec->vtx.vertex_size);
+
+
+   switch( exec->ctx->Driver.CurrentExecPrimitive )
+   {
+   case GL_POINTS:
+      return 0;
+   case GL_LINES:
+      ovf = nr&1;
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+      return i;
+   case GL_TRIANGLES:
+      ovf = nr%3;
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+      return i;
+   case GL_QUADS:
+      ovf = nr&3;
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+      return i;
+   case GL_LINE_STRIP:
+      if (nr == 0) 
+        return 0;
+      else {
+        _mesa_memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
+        return 1;
+      }
+   case GL_LINE_LOOP:
+   case GL_TRIANGLE_FAN:
+   case GL_POLYGON:
+      if (nr == 0) 
+        return 0;
+      else if (nr == 1) {
+        _mesa_memcpy( dst, src+0, sz * sizeof(GLfloat) );
+        return 1;
+      } else {
+        _mesa_memcpy( dst, src+0, sz * sizeof(GLfloat) );
+        _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
+        return 2;
+      }
+   case GL_TRIANGLE_STRIP:
+   case GL_QUAD_STRIP:
+      switch (nr) {
+      case 0: ovf = 0; break;
+      case 1: ovf = 1; break;
+      default: ovf = 2 + (nr&1); break;
+      }
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+      return i;
+   case GL_POLYGON+1:
+      return 0;
+   default:
+      assert(0);
+      return 0;
+   }
+}
+
+
+/* TODO: populate these as the vertex is defined:
+ */
+static void vbo_exec_bind_arrays( struct vbo_exec_context *exec )
+{
+   struct gl_client_array *arrays = exec->vtx.arrays;
+   GLuint count = exec->vtx.vert_count;
+   GLubyte *data = exec->vtx.buffer_map;
+   GLuint attr;
+
+   memcpy(arrays,      exec->legacy_currval, 16 * sizeof(arrays[0]));
+   memcpy(arrays + 16, exec->mat_currval,    16 * sizeof(arrays[0]));
+
+   /* Make all active attributes (including edgeflag) available as
+    * arrays of floats.
+    */
+   for (attr = 0; attr < VBO_ATTRIB_MAX ; attr++) {
+      if (exec->vtx.attrsz[attr]) {
+        arrays[attr].Ptr = (void *)data;
+        arrays[attr].Size = exec->vtx.attrsz[attr];
+        arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
+        arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
+        arrays[attr].Type = GL_FLOAT;
+        arrays[attr].Enabled = 1;
+        arrays[attr].BufferObj = exec->vtx.bufferobj; /* NullBufferObj */
+        arrays[attr]._MaxElement = count; /* ??? */
+
+        data += exec->vtx.attrsz[attr] * sizeof(GLfloat);
+      }
+   }
+}
+
+
+/**
+ * Execute the buffer and save copied verts.
+ */
+void vbo_exec_vtx_flush( struct vbo_exec_context *exec )
+{
+   if (0)
+      vbo_exec_debug_verts( exec );
+
+
+   if (exec->vtx.prim_count && 
+       exec->vtx.vert_count) {
+
+      exec->vtx.copied.nr = vbo_copy_vertices( exec ); 
+
+      if (exec->vtx.copied.nr != exec->vtx.vert_count) {
+        GLcontext *ctx = exec->ctx;
+
+        vbo_exec_bind_arrays( exec );
+
+        vbo_context(ctx)->draw_prims( ctx, 
+                                      exec->vtx.inputs, 
+                                      exec->vtx.prim, 
+                                      exec->vtx.prim_count,
+                                      NULL,
+                                      0,
+                                      exec->vtx.vert_count );
+      }
+   }
+
+   exec->vtx.prim_count = 0;
+   exec->vtx.vert_count = 0;
+   exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
+}
diff --git a/src/mesa/vbo/vbo_exec_eval.c b/src/mesa/vbo/vbo_exec_eval.c
new file mode 100644 (file)
index 0000000..99a8044
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * Copyright (C) 1999-2004  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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "api_eval.h"
+#include "context.h"
+#include "macros.h"
+#include "math/m_eval.h"
+#include "vbo_exec.h"
+#include "dispatch.h"
+
+
+static void clear_active_eval1( struct vbo_exec_context *exec, GLuint attr ) 
+{
+   exec->eval.map1[attr].map = NULL;
+}
+
+static void clear_active_eval2( struct vbo_exec_context *exec, GLuint attr ) 
+{
+   exec->eval.map2[attr].map = NULL;
+}
+
+static void set_active_eval1( struct vbo_exec_context *exec, GLuint attr, GLuint dim, 
+                             struct gl_1d_map *map )
+{
+   if (!exec->eval.map1[attr].map) {
+      exec->eval.map1[attr].map = map;
+      exec->eval.map1[attr].sz = dim;
+   }
+} 
+
+static void set_active_eval2( struct vbo_exec_context *exec, GLuint attr, GLuint dim, 
+                             struct gl_2d_map *map )
+{
+   if (!exec->eval.map2[attr].map) {
+      exec->eval.map2[attr].map = map;
+      exec->eval.map2[attr].sz = dim;
+   }
+} 
+
+void vbo_exec_eval_update( struct vbo_exec_context *exec )
+{
+   GLcontext *ctx = exec->ctx;
+   GLuint attr;
+
+   /* Vertex program maps have priority over conventional attribs */
+
+   for (attr = 0; attr < VBO_ATTRIB_FIRST_MATERIAL; attr++) {
+      clear_active_eval1( exec, attr );
+      clear_active_eval2( exec, attr );
+   }
+
+   /* _NEW_PROGRAM */
+   if (ctx->VertexProgram._Enabled) {
+      for (attr = 0; attr < VBO_ATTRIB_FIRST_MATERIAL; attr++) {
+        /* _NEW_EVAL */
+        if (ctx->Eval.Map1Attrib[attr]) 
+           set_active_eval1( exec, attr, 4, &ctx->EvalMap.Map1Attrib[attr] );
+
+        if (ctx->Eval.Map2Attrib[attr]) 
+           set_active_eval2( exec, attr, 4, &ctx->EvalMap.Map2Attrib[attr] );
+      }
+   }
+
+   if (ctx->Eval.Map1Color4) 
+      set_active_eval1( exec, VBO_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map1Color4 );
+      
+   if (ctx->Eval.Map2Color4) 
+      set_active_eval2( exec, VBO_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map2Color4 );
+
+   if (ctx->Eval.Map1TextureCoord4) 
+      set_active_eval1( exec, VBO_ATTRIB_TEX0, 4, &ctx->EvalMap.Map1Texture4 );
+   else if (ctx->Eval.Map1TextureCoord3) 
+      set_active_eval1( exec, VBO_ATTRIB_TEX0, 3, &ctx->EvalMap.Map1Texture3 );
+   else if (ctx->Eval.Map1TextureCoord2) 
+      set_active_eval1( exec, VBO_ATTRIB_TEX0, 2, &ctx->EvalMap.Map1Texture2 );
+   else if (ctx->Eval.Map1TextureCoord1) 
+      set_active_eval1( exec, VBO_ATTRIB_TEX0, 1, &ctx->EvalMap.Map1Texture1 );
+
+   if (ctx->Eval.Map2TextureCoord4) 
+      set_active_eval2( exec, VBO_ATTRIB_TEX0, 4, &ctx->EvalMap.Map2Texture4 );
+   else if (ctx->Eval.Map2TextureCoord3) 
+      set_active_eval2( exec, VBO_ATTRIB_TEX0, 3, &ctx->EvalMap.Map2Texture3 );
+   else if (ctx->Eval.Map2TextureCoord2) 
+      set_active_eval2( exec, VBO_ATTRIB_TEX0, 2, &ctx->EvalMap.Map2Texture2 );
+   else if (ctx->Eval.Map2TextureCoord1) 
+      set_active_eval2( exec, VBO_ATTRIB_TEX0, 1, &ctx->EvalMap.Map2Texture1 );
+
+   if (ctx->Eval.Map1Normal) 
+      set_active_eval1( exec, VBO_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map1Normal );
+
+   if (ctx->Eval.Map2Normal) 
+      set_active_eval2( exec, VBO_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map2Normal );
+
+   if (ctx->Eval.Map1Vertex4) 
+      set_active_eval1( exec, VBO_ATTRIB_POS, 4, &ctx->EvalMap.Map1Vertex4 );
+   else if (ctx->Eval.Map1Vertex3) 
+      set_active_eval1( exec, VBO_ATTRIB_POS, 3, &ctx->EvalMap.Map1Vertex3 );
+
+   if (ctx->Eval.Map2Vertex4) 
+      set_active_eval2( exec, VBO_ATTRIB_POS, 4, &ctx->EvalMap.Map2Vertex4 );
+   else if (ctx->Eval.Map2Vertex3) 
+      set_active_eval2( exec, VBO_ATTRIB_POS, 3, &ctx->EvalMap.Map2Vertex3 );
+
+   exec->eval.recalculate_maps = 0;
+}
+
+
+
+void vbo_exec_do_EvalCoord1f(struct vbo_exec_context *exec, GLfloat u)
+{
+   GLuint attr;
+
+   for (attr = 1; attr <= VBO_ATTRIB_INDEX; attr++) {
+      struct gl_1d_map *map = exec->eval.map1[attr].map;
+      if (map) {
+        GLfloat uu = (u - map->u1) * map->du;
+        GLfloat data[4];
+
+        ASSIGN_4V(data, 0, 0, 0, 1);
+
+        _math_horner_bezier_curve(map->Points, data, uu, 
+                                  exec->eval.map1[attr].sz, 
+                                  map->Order);
+
+        COPY_SZ_4V( exec->vtx.attrptr[attr],
+                    exec->vtx.attrsz[attr],
+                    data );
+      }
+   }
+
+   /** Vertex -- EvalCoord1f is a noop if this map not enabled:
+    **/
+   if (exec->eval.map1[0].map) {
+      struct gl_1d_map *map = exec->eval.map1[0].map;
+      GLfloat uu = (u - map->u1) * map->du;
+      GLfloat vertex[4];
+
+      ASSIGN_4V(vertex, 0, 0, 0, 1);
+
+      _math_horner_bezier_curve(map->Points, vertex, uu, 
+                               exec->eval.map1[0].sz, 
+                               map->Order);
+
+      if (exec->eval.map1[0].sz == 4) 
+        CALL_Vertex4fv(GET_DISPATCH(), ( vertex ));
+      else
+        CALL_Vertex3fv(GET_DISPATCH(), ( vertex )); 
+   }
+}
+
+
+
+void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec, 
+                             GLfloat u, GLfloat v )
+{   
+   GLuint attr;
+
+   for (attr = 1; attr <= VBO_ATTRIB_INDEX; attr++) {
+      struct gl_2d_map *map = exec->eval.map2[attr].map;
+      if (map) {
+        GLfloat uu = (u - map->u1) * map->du;
+        GLfloat vv = (v - map->v1) * map->dv;
+        GLfloat data[4];
+
+        ASSIGN_4V(data, 0, 0, 0, 1);
+
+        _math_horner_bezier_surf(map->Points, 
+                                 data, 
+                                 uu, vv, 
+                                 exec->eval.map2[attr].sz, 
+                                 map->Uorder, map->Vorder);
+
+        COPY_SZ_4V( exec->vtx.attrptr[attr],
+                    exec->vtx.attrsz[attr],
+                    data );
+      }
+   }
+
+   /** Vertex -- EvalCoord2f is a noop if this map not enabled:
+    **/
+   if (exec->eval.map2[0].map) {
+      struct gl_2d_map *map = exec->eval.map2[0].map;
+      GLfloat uu = (u - map->u1) * map->du;
+      GLfloat vv = (v - map->v1) * map->dv;
+      GLfloat vertex[4];
+
+      ASSIGN_4V(vertex, 0, 0, 0, 1);
+
+      if (exec->ctx->Eval.AutoNormal) {
+        GLfloat normal[4];
+         GLfloat du[4], dv[4];
+
+         _math_de_casteljau_surf(map->Points, vertex, du, dv, uu, vv, 
+                                exec->eval.map2[0].sz,
+                                map->Uorder, map->Vorder);
+
+        if (exec->eval.map2[0].sz == 4) {
+           du[0] = du[0]*vertex[3] - du[3]*vertex[0];
+           du[1] = du[1]*vertex[3] - du[3]*vertex[1];
+           du[2] = du[2]*vertex[3] - du[3]*vertex[2];
+        
+           dv[0] = dv[0]*vertex[3] - dv[3]*vertex[0];
+           dv[1] = dv[1]*vertex[3] - dv[3]*vertex[1];
+           dv[2] = dv[2]*vertex[3] - dv[3]*vertex[2];
+        }
+
+
+         CROSS3(normal, du, dv);
+         NORMALIZE_3FV(normal);
+        normal[3] = 1.0;
+
+        COPY_SZ_4V( exec->vtx.attrptr[VBO_ATTRIB_NORMAL],
+                    exec->vtx.attrsz[VBO_ATTRIB_NORMAL],
+                    normal );
+
+      }
+      else {
+         _math_horner_bezier_surf(map->Points, vertex, uu, vv, 
+                                 exec->eval.map2[0].sz,
+                                 map->Uorder, map->Vorder);
+      }
+
+      if (exec->vtx.attrsz[0] == 4) 
+        CALL_Vertex4fv(GET_DISPATCH(), ( vertex ));
+      else
+        CALL_Vertex3fv(GET_DISPATCH(), ( vertex )); 
+   }
+}
+
+
diff --git a/src/mesa/vbo/vbo_save.c b/src/mesa/vbo/vbo_save.c
new file mode 100644 (file)
index 0000000..0a5b705
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.3
+ *
+ * Copyright (C) 1999-2005  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@tungstengraphics.com>
+ */
+
+
+#include "mtypes.h"
+#include "dlist.h"
+#include "vtxfmt.h"
+#include "imports.h"
+
+#include "vbo_context.h"
+
+
+
+void vbo_save_init( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+   save->ctx = ctx;
+
+   vbo_save_api_init( save );
+   vbo_save_wakeup(ctx);
+
+   ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
+}
+
+
+void vbo_save_destroy( GLcontext *ctx )
+{
+}
+
+
+
+
+/* Note that this can occur during the playback of a display list:
+ */
+void vbo_save_fallback( GLcontext *ctx, GLboolean fallback )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+   if (fallback)
+      save->replay_flags |= VBO_SAVE_FALLBACK;
+   else
+      save->replay_flags &= ~VBO_SAVE_FALLBACK;
+}
+
+
+/* I don't see any reason to swap this code out on fallbacks.  It
+ * wouldn't really mean anything to do so anyway as the old lists are
+ * still around from pre-fallback.  Instead, the above code ensures
+ * that vertices are routed back through immediate mode dispatch on
+ * fallback.
+ *
+ * The below can be moved into init or removed:
+ */
+void vbo_save_wakeup( GLcontext *ctx )
+{
+   ctx->Driver.NewList = vbo_save_NewList;
+   ctx->Driver.EndList = vbo_save_EndList;
+   ctx->Driver.SaveFlushVertices = vbo_save_SaveFlushVertices;
+   ctx->Driver.BeginCallList = vbo_save_BeginCallList;
+   ctx->Driver.EndCallList = vbo_save_EndCallList;
+   ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
+
+   /* Assume we haven't been getting state updates either:
+    */
+   vbo_save_invalidate_state( ctx, ~0 );
+}
+
+
+
diff --git a/src/mesa/vbo/vbo_save.h b/src/mesa/vbo/vbo_save.h
new file mode 100644 (file)
index 0000000..dbe5caf
--- /dev/null
@@ -0,0 +1,180 @@
+/**************************************************************************
+
+Copyright 2002 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
+on 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 THEIR 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef VBO_SAVE_H
+#define VBO_SAVE_H
+
+#include "mtypes.h"
+#include "vbo_attrib.h"
+
+
+struct vbo_save_copied_vtx {
+   GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
+   GLuint nr;
+};
+
+
+/* For display lists, this structure holds a run of vertices of the
+ * same format, and a strictly well-formed set of begin/end pairs,
+ * starting on the first vertex and ending at the last.  Vertex
+ * copying on buffer breaks is precomputed according to these
+ * primitives, though there are situations where the copying will need
+ * correction at execute-time, perhaps by replaying the list as
+ * immediate mode commands.
+ *
+ * On executing this list, the 'current' values may be updated with
+ * the values of the final vertex, and often no fixup of the start of
+ * the vertex list is required.
+ *
+ * Eval and other commands that don't fit into these vertex lists are
+ * compiled using the fallback opcode mechanism provided by dlist.c.
+ */
+struct vbo_save_vertex_list {
+   GLubyte attrsz[VBO_ATTRIB_MAX];
+   GLuint vertex_size;
+
+   GLuint buffer_offset;
+   GLuint count;
+   GLuint wrap_count;          /* number of copied vertices at start */
+   GLboolean dangling_attr_ref;        /* current attr implicitly referenced 
+                                  outside the list */
+
+   struct _mesa_prim *prim;
+   GLuint prim_count;
+
+   struct vbo_save_vertex_store *vertex_store;
+   struct vbo_save_primitive_store *prim_store;
+};
+
+/* These buffers should be a reasonable size to support upload to
+ * hardware.  Current vbo implementation will re-upload on any
+ * changes, so don't make too big or apps which dynamically create
+ * dlists and use only a few times will suffer.
+ *
+ * Consider stategy of uploading regions from the VBO on demand in the
+ * case of dynamic vbos.  Then make the dlist code signal that
+ * likelyhood as it occurs.  No reason we couldn't change usage
+ * internally even though this probably isn't allowed for client VBOs?
+ */
+#define VBO_SAVE_BUFFER_SIZE (8*1024) /* dwords */
+#define VBO_SAVE_PRIM_SIZE   128
+#define VBO_SAVE_PRIM_WEAK 0x40
+
+#define VBO_SAVE_FALLBACK    0x10000000
+
+/* Storage to be shared among several vertex_lists.
+ */
+struct vbo_save_vertex_store {
+   struct gl_buffer_object *bufferobj;
+   GLfloat *buffer;
+   GLuint used;
+   GLuint refcount;
+};
+
+struct vbo_save_primitive_store {
+   struct _mesa_prim buffer[VBO_SAVE_PRIM_SIZE];
+   GLuint used;
+   GLuint refcount;
+};
+
+
+struct vbo_save_context {
+   GLcontext *ctx;
+   GLvertexformat vtxfmt;
+   struct gl_client_array arrays[VBO_ATTRIB_MAX];
+   const struct gl_client_array *inputs[VBO_ATTRIB_MAX];
+
+   GLubyte attrsz[VBO_ATTRIB_MAX];
+   GLubyte active_sz[VBO_ATTRIB_MAX];
+   GLuint vertex_size;
+
+   GLfloat *buffer;
+   GLuint count;
+   GLuint wrap_count;
+   GLuint replay_flags;
+
+   struct _mesa_prim *prim;
+   GLuint prim_count, prim_max;
+
+   struct vbo_save_vertex_store *vertex_store;
+   struct vbo_save_primitive_store *prim_store;
+
+   GLfloat *vbptr;                /* cursor, points into buffer */
+   GLfloat vertex[VBO_ATTRIB_MAX*4];      /* current values */
+   GLfloat *attrptr[VBO_ATTRIB_MAX];
+   GLuint vert_count;
+   GLuint max_vert;
+   GLboolean dangling_attr_ref;
+   GLboolean have_materials;
+
+   GLuint opcode_vertex_list;
+
+   struct vbo_save_copied_vtx copied;
+   
+   GLfloat CurrentFloatEdgeFlag;
+
+   GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->ListState */
+   GLubyte *currentsz[VBO_ATTRIB_MAX];
+};
+
+
+void vbo_save_init( GLcontext *ctx );
+void vbo_save_destroy( GLcontext *ctx );
+void vbo_save_wakeup( GLcontext *ctx );
+void vbo_save_invalidate_state( GLcontext *ctx, GLuint new_state );
+void vbo_save_fallback( GLcontext *ctx, GLboolean fallback );
+
+/* save_loopback.c:
+ */
+void vbo_loopback_vertex_list( GLcontext *ctx,
+                              const GLfloat *buffer,
+                              const GLubyte *attrsz,
+                              const struct _mesa_prim *prim,
+                              GLuint prim_count,
+                              GLuint wrap_count,
+                              GLuint vertex_size);
+
+/* Callbacks:
+ */
+void vbo_save_EndList( GLcontext *ctx );
+void vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode );
+void vbo_save_EndCallList( GLcontext *ctx );
+void vbo_save_BeginCallList( GLcontext *ctx, struct mesa_display_list *list );
+void vbo_save_SaveFlushVertices( GLcontext *ctx );
+GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode );
+
+void vbo_save_playback_vertex_list( GLcontext *ctx, void *data );
+
+void vbo_save_api_init( struct vbo_save_context *save );
+
+#endif
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
new file mode 100644 (file)
index 0000000..8ceba2b
--- /dev/null
@@ -0,0 +1,1160 @@
+/**************************************************************************
+
+Copyright 2002 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
+on 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 THEIR 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.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+
+/* Display list compiler attempts to store lists of vertices with the
+ * same vertex layout.  Additionally it attempts to minimize the need
+ * for execute-time fixup of these vertex lists, allowing them to be
+ * cached on hardware.
+ *
+ * There are still some circumstances where this can be thwarted, for
+ * example by building a list that consists of one very long primitive
+ * (eg Begin(Triangles), 1000 vertices, End), and calling that list
+ * from inside a different begin/end object (Begin(Lines), CallList,
+ * End).  
+ *
+ * In that case the code will have to replay the list as individual
+ * commands through the Exec dispatch table, or fix up the copied
+ * vertices at execute-time.
+ *
+ * The other case where fixup is required is when a vertex attribute
+ * is introduced in the middle of a primitive.  Eg:
+ *  Begin(Lines)
+ *  TexCoord1f()           Vertex2f()
+ *  TexCoord1f() Color3f() Vertex2f()
+ *  End()
+ *
+ *  If the current value of Color isn't known at compile-time, this
+ *  primitive will require fixup.
+ *
+ *
+ * The list compiler currently doesn't attempt to compile lists
+ * containing EvalCoord or EvalPoint commands.  On encountering one of
+ * these, compilation falls back to opcodes.  
+ *
+ * This could be improved to fallback only when a mix of EvalCoord and
+ * Vertex commands are issued within a single primitive.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "dlist.h"
+#include "enums.h"
+#include "macros.h"
+#include "api_validate.h"
+#include "api_arrayelt.h"
+#include "vtxfmt.h"
+#include "dispatch.h"
+
+#include "vbo_context.h"
+
+
+
+/*
+ * NOTE: Old 'parity' issue is gone, but copying can still be
+ * wrong-footed on replay.
+ */
+static GLuint _save_copy_vertices( GLcontext *ctx, 
+                                  const struct vbo_save_vertex_list *node,
+                                  const GLfloat *src_buffer)
+{
+   struct vbo_save_context *save = &vbo_context( ctx )->save;
+   const struct _mesa_prim *prim = &node->prim[node->prim_count-1];
+   GLuint nr = prim->count;
+   GLuint sz = save->vertex_size;
+   const GLfloat *src = src_buffer + prim->start * sz;
+   GLfloat *dst = save->copied.buffer;
+   GLuint ovf, i;
+
+   if (prim->end)
+      return 0;
+        
+   switch( prim->mode )
+   {
+   case GL_POINTS:
+      return 0;
+   case GL_LINES:
+      ovf = nr&1;
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+      return i;
+   case GL_TRIANGLES:
+      ovf = nr%3;
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+      return i;
+   case GL_QUADS:
+      ovf = nr&3;
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+      return i;
+   case GL_LINE_STRIP:
+      if (nr == 0) 
+        return 0;
+      else {
+        _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
+        return 1;
+      }
+   case GL_LINE_LOOP:
+   case GL_TRIANGLE_FAN:
+   case GL_POLYGON:
+      if (nr == 0) 
+        return 0;
+      else if (nr == 1) {
+        _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
+        return 1;
+      } else {
+        _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
+        _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
+        return 2;
+      }
+   case GL_TRIANGLE_STRIP:
+   case GL_QUAD_STRIP:
+      switch (nr) {
+      case 0: ovf = 0; break;
+      case 1: ovf = 1; break;
+      default: ovf = 2 + (nr&1); break;
+      }
+      for (i = 0 ; i < ovf ; i++)
+        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+      return i;
+   default:
+      assert(0);
+      return 0;
+   }
+}
+
+
+static struct vbo_save_vertex_store *alloc_vertex_store( GLcontext *ctx )
+{
+   struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
+
+   /* obj->Name needs to be non-zero, but won't ever be examined more
+    * closely than that.  In particular these buffers won't be entered
+    * into the hash and can never be confused with ones visible to the
+    * user.  Perhaps there could be a special number for internal
+    * buffers:
+    */
+   vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
+
+   ctx->Driver.BufferData( ctx, 
+                          GL_ARRAY_BUFFER_ARB, 
+                          VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
+                          NULL,
+                          GL_STATIC_DRAW_ARB,
+                          vertex_store->bufferobj);
+
+   vertex_store->buffer = NULL;
+   vertex_store->used = 0;
+   vertex_store->refcount = 1;
+
+   return vertex_store;
+}
+
+static void free_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
+{
+   assert(!vertex_store->buffer);
+
+   if (vertex_store->bufferobj)
+      ctx->Driver.DeleteBuffer( ctx, vertex_store->bufferobj );
+
+   FREE( vertex_store );
+}
+
+static GLfloat *map_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
+{
+   assert(vertex_store->bufferobj);
+   assert(!vertex_store->buffer);
+   vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx, 
+                                                          GL_ARRAY_BUFFER_ARB, /* not used */
+                                                          GL_STATIC_DRAW_ARB, /* not used */
+                                                          vertex_store->bufferobj); 
+
+   assert(vertex_store->buffer);
+   return vertex_store->buffer + vertex_store->used;
+}
+
+static void unmap_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
+{
+   ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj );
+   vertex_store->buffer = NULL;
+}
+
+
+static struct vbo_save_primitive_store *alloc_prim_store( GLcontext *ctx )
+{
+   struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store);
+   (void) ctx;
+   store->used = 0;
+   store->refcount = 1;
+   return store;
+}
+
+static void _save_reset_counters( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+   save->prim = save->prim_store->buffer + save->prim_store->used;
+   save->buffer = (save->vertex_store->buffer + 
+                  save->vertex_store->used);
+
+   assert(save->buffer == save->vbptr);
+
+   if (save->vertex_size)
+      save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 
+                        save->vertex_size);
+   else
+      save->max_vert = 0;
+
+   save->vert_count = 0;
+   save->prim_count = 0;
+   save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
+   save->dangling_attr_ref = 0;
+}
+
+
+/* Insert the active immediate struct onto the display list currently
+ * being built.
+ */
+static void _save_compile_vertex_list( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   struct vbo_save_vertex_list *node;
+
+   /* Allocate space for this structure in the display list currently
+    * being compiled.
+    */
+   node = (struct vbo_save_vertex_list *)
+      _mesa_alloc_instruction(ctx, save->opcode_vertex_list, sizeof(*node));
+
+   if (!node)
+      return;
+
+   /* Duplicate our template, increment refcounts to the storage structs:
+    */
+   _mesa_memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); 
+   node->vertex_size = save->vertex_size;
+   node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); 
+   node->count = save->vert_count;
+   node->wrap_count = save->copied.nr;
+   node->dangling_attr_ref = save->dangling_attr_ref;
+   node->prim = save->prim;
+   node->prim_count = save->prim_count;
+   node->vertex_store = save->vertex_store;
+   node->prim_store = save->prim_store;
+
+   node->vertex_store->refcount++;
+   node->prim_store->refcount++;
+
+   assert(node->attrsz[VBO_ATTRIB_POS] != 0 ||
+         node->count == 0);
+
+   if (save->dangling_attr_ref)
+      ctx->ListState.CurrentList->flags |= MESA_DLIST_DANGLING_REFS;
+
+   save->vertex_store->used += save->vertex_size * node->count;
+   save->prim_store->used += node->prim_count;
+
+
+   /* Copy duplicated vertices 
+    */
+   save->copied.nr = _save_copy_vertices( ctx, node, save->buffer );
+
+
+   /* Deal with GL_COMPILE_AND_EXECUTE:
+    */
+   if (ctx->ExecuteFlag) {
+      struct _glapi_table *dispatch = GET_DISPATCH();
+
+      _glapi_set_dispatch(ctx->Exec);
+
+      vbo_loopback_vertex_list( ctx,
+                               (const GLfloat *)((const char *)save->vertex_store->buffer + 
+                                                 node->buffer_offset),
+                               node->attrsz,
+                               node->prim,
+                               node->prim_count,
+                               node->wrap_count,
+                               node->vertex_size);
+
+      _glapi_set_dispatch(dispatch);
+   }
+
+
+   /* Decide whether the storage structs are full, or can be used for
+    * the next vertex lists as well.
+    */
+   if (save->vertex_store->used > 
+       VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
+
+      /* Unmap old store:
+       */
+      unmap_vertex_store( ctx, save->vertex_store );
+
+      /* Release old reference:
+       */
+      save->vertex_store->refcount--; 
+      assert(save->vertex_store->refcount != 0);
+      save->vertex_store = NULL;
+
+      /* Allocate and map new store:
+       */
+      save->vertex_store = alloc_vertex_store( ctx );
+      save->vbptr = map_vertex_store( ctx, save->vertex_store );
+   } 
+
+   if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
+      save->prim_store->refcount--; 
+      assert(save->prim_store->refcount != 0);
+      save->prim_store = alloc_prim_store( ctx );
+   } 
+
+   /* Reset our structures for the next run of vertices:
+    */
+   _save_reset_counters( ctx );
+}
+
+
+/* TODO -- If no new vertices have been stored, don't bother saving
+ * it.
+ */
+static void _save_wrap_buffers( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   GLint i = save->prim_count - 1;
+   GLenum mode;
+   GLboolean weak;
+
+   assert(i < (GLint) save->prim_max);
+   assert(i >= 0);
+
+   /* Close off in-progress primitive.
+    */
+   save->prim[i].count = (save->vert_count - 
+                         save->prim[i].start);
+   mode = save->prim[i].mode;
+   weak = save->prim[i].weak;
+   
+   /* store the copied vertices, and allocate a new list.
+    */
+   _save_compile_vertex_list( ctx );
+
+   /* Restart interrupted primitive
+    */
+   save->prim[0].mode = mode;
+   save->prim[0].weak = weak;
+   save->prim[0].begin = 0;
+   save->prim[0].end = 0;
+   save->prim[0].pad = 0;
+   save->prim[0].start = 0;
+   save->prim[0].count = 0;
+   save->prim_count = 1;
+}
+
+
+
+/* Called only when buffers are wrapped as the result of filling the
+ * vertex_store struct.  
+ */
+static void _save_wrap_filled_vertex( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   GLfloat *data = save->copied.buffer;
+   GLuint i;
+
+   /* Emit a glEnd to close off the last vertex list.
+    */
+   _save_wrap_buffers( ctx );
+   
+    /* Copy stored stored vertices to start of new list.
+    */
+   assert(save->max_vert - save->vert_count > save->copied.nr);
+
+   for (i = 0 ; i < save->copied.nr ; i++) {
+      _mesa_memcpy( save->vbptr, data, save->vertex_size * sizeof(GLfloat));
+      data += save->vertex_size;
+      save->vbptr += save->vertex_size;
+      save->vert_count++;
+   }
+}
+
+
+static void _save_copy_to_current( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save; 
+   GLuint i;
+
+   for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; i++) {
+      if (save->attrsz[i]) {
+        save->currentsz[i][0] = save->attrsz[i];
+        COPY_CLEAN_4V(save->current[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);
+   }
+}
+
+
+static void _save_copy_from_current( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save; 
+   GLint i;
+
+   for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; 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];
+      case 2: save->attrptr[i][1] = save->current[i][1];
+      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;
+   }
+}
+
+
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */ 
+static void _save_upgrade_vertex( GLcontext *ctx, 
+                                GLuint attr,
+                                GLuint newsz )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   GLuint oldsz;
+   GLuint i;
+   GLfloat *tmp;
+
+   /* Store the current run of vertices, and emit a GL_END.  Emit a
+    * BEGIN in the new buffer.
+    */
+   if (save->vert_count) 
+      _save_wrap_buffers( ctx );
+   else
+      assert( save->copied.nr == 0 );
+
+   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
+    * when the attribute already exists in the vertex and is having
+    * its size increased.  
+    */
+   _save_copy_to_current( ctx );
+
+   /* Fix up sizes:
+    */
+   oldsz = save->attrsz[attr];
+   save->attrsz[attr] = newsz;
+
+   save->vertex_size += newsz - oldsz;
+   save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 
+                     save->vertex_size);
+   save->vert_count = 0;
+
+   /* Recalculate all the attrptr[] values:
+    */
+   for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) {
+      if (save->attrsz[i]) {
+        save->attrptr[i] = tmp;
+        tmp += save->attrsz[i];
+      }
+      else 
+        save->attrptr[i] = NULL; /* will not be dereferenced. */
+   }
+
+   /* Copy from current to repopulate the vertex with correct values.
+    */
+   _save_copy_from_current( ctx );
+
+   /* Replay stored vertices to translate them to new format here.
+    *
+    * If there are copied vertices and the new (upgraded) attribute
+    * has not been defined before, this list is somewhat degenerate,
+    * and will need fixup at runtime.
+    */
+   if (save->copied.nr)
+   {
+      GLfloat *data = save->copied.buffer;
+      GLfloat *dest = save->buffer;
+      GLuint j;
+
+      /* Need to note this and fix up at runtime (or loopback):
+       */
+      if (save->currentsz[attr][0] == 0) {
+        assert(oldsz == 0);
+        save->dangling_attr_ref = GL_TRUE;
+      }
+
+      for (i = 0 ; i < save->copied.nr ; i++) {
+        for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
+           if (save->attrsz[j]) {
+              if (j == attr) {
+                 if (oldsz) {
+                    COPY_CLEAN_4V( dest, oldsz, data );
+                    data += oldsz;
+                    dest += newsz;
+                 }
+                 else {
+                    COPY_SZ_4V( dest, newsz, save->current[attr] );
+                    dest += newsz;
+                 }
+              }
+              else {
+                 GLint sz = save->attrsz[j];
+                 COPY_SZ_4V( dest, sz, data );
+                 data += sz;
+                 dest += sz;
+              }
+           }
+        }
+      }
+
+      save->vbptr = dest;
+      save->vert_count += save->copied.nr;
+   }
+}
+
+static void save_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save; 
+
+   if (sz > save->attrsz[attr]) {
+      /* New size is larger.  Need to flush existing vertices and get
+       * an enlarged vertex format.
+       */
+      _save_upgrade_vertex( ctx, attr, sz );
+   }
+   else if (sz < save->active_sz[attr]) {
+      static GLfloat id[4] = { 0, 0, 0, 1 };
+      GLuint i;
+
+      /* New size is equal or smaller - just need to fill in some
+       * zeros.
+       */
+      for (i = sz ; i <= save->attrsz[attr] ; i++)
+        save->attrptr[attr][i-1] = id[i-1];
+   }
+
+   save->active_sz[attr] = sz;
+}
+
+static void _save_reset_vertex( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   GLuint i;
+
+   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+      save->attrsz[i] = 0;
+      save->active_sz[i] = 0;
+   }
+      
+   save->vertex_size = 0;
+}
+
+
+
+#define ERROR()   _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
+
+
+/* Only one size for each attribute may be active at once.  Eg. if
+ * Color3f is installed/active, then Color4f may not be, even if the
+ * vertex actually contains 4 color coordinates.  This is because the
+ * 3f version won't otherwise set color[3] to 1.0 -- this is the job
+ * of the chooser function when switching between Color4f and Color3f.
+ */
+#define ATTR( A, N, V0, V1, V2, V3 )                           \
+do {                                                           \
+   struct vbo_save_context *save = &vbo_context(ctx)->save;    \
+                                                               \
+   if (save->active_sz[A] != N)                                \
+      save_fixup_vertex(ctx, A, N);                            \
+                                                               \
+   {                                                           \
+      GLfloat *dest = save->attrptr[A];                        \
+      if (N>0) dest[0] = V0;                                   \
+      if (N>1) dest[1] = V1;                                   \
+      if (N>2) dest[2] = V2;                                   \
+      if (N>3) dest[3] = V3;                                   \
+   }                                                           \
+                                                               \
+   if ((A) == 0) {                                             \
+      GLuint i;                                                        \
+                                                               \
+      for (i = 0; i < save->vertex_size; i++)                  \
+        save->vbptr[i] = save->vertex[i];                      \
+                                                               \
+      save->vbptr += save->vertex_size;                                \
+                                                               \
+      if (++save->vert_count >= save->max_vert)                        \
+        _save_wrap_filled_vertex( ctx );                       \
+   }                                                           \
+} while (0)
+
+#define TAG(x) _save_##x
+
+#include "vbo_attrib_tmp.h"
+
+
+
+
+/* Cope with EvalCoord/CallList called within a begin/end object:
+ *     -- Flush current buffer
+ *     -- Fallback to opcodes for the rest of the begin/end object.
+ */
+#define DO_FALLBACK(ctx)                                                       \
+do {                                                                   \
+   struct vbo_save_context *save = &vbo_context(ctx)->save;                                    \
+                                                                       \
+   if (save->vert_count || save->prim_count)                                           \
+      _save_compile_vertex_list( ctx );                                        \
+                                                                       \
+   _save_copy_to_current( ctx );                                       \
+   _save_reset_vertex( ctx );                                          \
+   _save_reset_counters( ctx );  \
+   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );       \
+   ctx->Driver.SaveNeedFlush = 0;                                      \
+} while (0)
+
+static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->EvalCoord1f( u );
+}
+
+static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->EvalCoord1fv( v );
+}
+
+static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->EvalCoord2f( u, v );
+}
+
+static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->EvalCoord2fv( v );
+}
+
+static void GLAPIENTRY _save_EvalPoint1( GLint i )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->EvalPoint1( i );
+}
+
+static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->EvalPoint2( i, j );
+}
+
+static void GLAPIENTRY _save_CallList( GLuint l )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->CallList( l );
+}
+
+static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   DO_FALLBACK(ctx);
+   ctx->Save->CallLists( n, type, v );
+}
+
+
+
+
+/* This begin is hooked into ...  Updating of
+ * ctx->Driver.CurrentSavePrimitive is already taken care of.
+ */
+GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save; 
+
+   GLuint i = save->prim_count++;
+
+   assert(i < save->prim_max);
+   save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK;
+   save->prim[i].begin = 1;
+   save->prim[i].end = 0;
+   save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
+   save->prim[i].pad = 0;
+   save->prim[i].start = save->vert_count;
+   save->prim[i].count = 0;   
+
+   _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );      
+   ctx->Driver.SaveNeedFlush = 1;
+   return GL_TRUE;
+}
+
+
+
+static void GLAPIENTRY _save_End( void )
+{
+   GET_CURRENT_CONTEXT( ctx ); 
+   struct vbo_save_context *save = &vbo_context(ctx)->save; 
+   GLint i = save->prim_count - 1;
+
+   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
+   save->prim[i].end = 1;
+   save->prim[i].count = (save->vert_count - 
+                         save->prim[i].start);
+
+   if (i == (GLint) save->prim_max - 1) {
+      _save_compile_vertex_list( ctx );
+      assert(save->copied.nr == 0);
+   }
+
+   /* Swap out this vertex format while outside begin/end.  Any color,
+    * etc. received between here and the next begin will be compiled
+    * as opcodes.
+    */   
+   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+}
+
+
+/* These are all errors as this vtxfmt is only installed inside
+ * begin/end pairs.
+ */
+static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
+                              const GLvoid *indices)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) count; (void) type; (void) indices;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
+}
+
+
+static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
+                                   GLuint start, GLuint end,
+                                   GLsizei count, GLenum type,
+                                   const GLvoid *indices)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
+}
+
+static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) start; (void) count;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
+}
+
+static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) x1; (void) y1; (void) x2; (void) y2;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
+}
+
+static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) i1; (void) i2;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
+}
+
+static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
+                                 GLint j1, GLint j2 )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
+}
+
+static void GLAPIENTRY _save_Begin( GLenum mode )
+{
+   GET_CURRENT_CONTEXT( ctx );
+   (void) mode;
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
+}
+
+
+/* Unlike the functions above, these are to be hooked into the vtxfmt
+ * maintained in ctx->ListState, active when the list is known or
+ * suspected to be outside any begin/end primitive.
+ */
+static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK );
+   CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
+   CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
+   CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
+   CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
+   CALL_End(GET_DISPATCH(), ());
+}
+
+
+static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+      return;
+
+   vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
+   for (i = 0; i < count; i++)
+       CALL_ArrayElement(GET_DISPATCH(), (start + i));
+   CALL_End(GET_DISPATCH(), ());
+}
+
+/* Could do better by copying the arrays and element list intact and
+ * then emitting an indexed prim at runtime.
+ */
+static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
+                                  const GLvoid *indices)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+      return;
+
+   vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
+
+   switch (type) {
+   case GL_UNSIGNED_BYTE:
+      for (i = 0 ; i < count ; i++)
+         CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
+      break;
+   case GL_UNSIGNED_SHORT:
+      for (i = 0 ; i < count ; i++)
+         CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
+      break;
+   case GL_UNSIGNED_INT:
+      for (i = 0 ; i < count ; i++)
+         CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
+      break;
+   default:
+      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
+      break;
+   }
+
+   CALL_End(GET_DISPATCH(), ());
+}
+
+static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
+                                       GLuint start, GLuint end,
+                                       GLsizei count, GLenum type,
+                                       const GLvoid *indices)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   if (_mesa_validate_DrawRangeElements( ctx, mode,
+                                        start, end,
+                                        count, type, indices ))
+      _save_OBE_DrawElements( mode, count, type, indices );
+}
+
+
+
+
+
+static void _save_vtxfmt_init( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   GLvertexformat *vfmt = &save->vtxfmt;
+
+   vfmt->ArrayElement = _ae_loopback_array_elt;                /* generic helper */
+   vfmt->Begin = _save_Begin;
+   vfmt->Color3f = _save_Color3f;
+   vfmt->Color3fv = _save_Color3fv;
+   vfmt->Color4f = _save_Color4f;
+   vfmt->Color4fv = _save_Color4fv;
+   vfmt->EdgeFlag = _save_EdgeFlag;
+   vfmt->End = _save_End;
+   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
+   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
+   vfmt->Indexf = _save_Indexf;
+   vfmt->Indexfv = _save_Indexfv;
+   vfmt->Materialfv = _save_Materialfv;
+   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
+   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
+   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
+   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
+   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
+   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
+   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
+   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
+   vfmt->Normal3f = _save_Normal3f;
+   vfmt->Normal3fv = _save_Normal3fv;
+   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
+   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
+   vfmt->TexCoord1f = _save_TexCoord1f;
+   vfmt->TexCoord1fv = _save_TexCoord1fv;
+   vfmt->TexCoord2f = _save_TexCoord2f;
+   vfmt->TexCoord2fv = _save_TexCoord2fv;
+   vfmt->TexCoord3f = _save_TexCoord3f;
+   vfmt->TexCoord3fv = _save_TexCoord3fv;
+   vfmt->TexCoord4f = _save_TexCoord4f;
+   vfmt->TexCoord4fv = _save_TexCoord4fv;
+   vfmt->Vertex2f = _save_Vertex2f;
+   vfmt->Vertex2fv = _save_Vertex2fv;
+   vfmt->Vertex3f = _save_Vertex3f;
+   vfmt->Vertex3fv = _save_Vertex3fv;
+   vfmt->Vertex4f = _save_Vertex4f;
+   vfmt->Vertex4fv = _save_Vertex4fv;
+   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
+   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
+   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
+   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
+   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
+   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
+   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
+   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
+
+   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
+   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
+   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
+   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
+   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
+   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
+   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
+   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
+   
+   /* This will all require us to fallback to saving the list as opcodes:
+    */ 
+   vfmt->CallList = _save_CallList; /* inside begin/end */
+   vfmt->CallLists = _save_CallLists; /* inside begin/end */
+   vfmt->EvalCoord1f = _save_EvalCoord1f;
+   vfmt->EvalCoord1fv = _save_EvalCoord1fv;
+   vfmt->EvalCoord2f = _save_EvalCoord2f;
+   vfmt->EvalCoord2fv = _save_EvalCoord2fv;
+   vfmt->EvalPoint1 = _save_EvalPoint1;
+   vfmt->EvalPoint2 = _save_EvalPoint2;
+
+   /* These are all errors as we at least know we are in some sort of
+    * begin/end pair:
+    */
+   vfmt->EvalMesh1 = _save_EvalMesh1;  
+   vfmt->EvalMesh2 = _save_EvalMesh2;
+   vfmt->Begin = _save_Begin;
+   vfmt->Rectf = _save_Rectf;
+   vfmt->DrawArrays = _save_DrawArrays;
+   vfmt->DrawElements = _save_DrawElements;
+   vfmt->DrawRangeElements = _save_DrawRangeElements;
+
+}
+
+
+void vbo_save_SaveFlushVertices( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+   /* Noop when we are actually active:
+    */
+   if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
+       ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
+      return;
+
+   if (save->vert_count ||
+       save->prim_count) 
+      _save_compile_vertex_list( ctx );
+   
+   _save_copy_to_current( ctx );
+   _save_reset_vertex( ctx );
+   _save_reset_counters( ctx );  
+   ctx->Driver.SaveNeedFlush = 0;
+}
+
+void vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+   (void) list; (void) mode;
+
+   if (!save->prim_store)
+      save->prim_store = alloc_prim_store( ctx );
+
+   if (!save->vertex_store) 
+      save->vertex_store = alloc_vertex_store( ctx );
+      
+   save->vbptr = map_vertex_store( ctx, save->vertex_store );
+   
+   _save_reset_vertex( ctx );
+   _save_reset_counters( ctx );  
+   ctx->Driver.SaveNeedFlush = 0;
+}
+
+void vbo_save_EndList( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   unmap_vertex_store( ctx, save->vertex_store );
+
+   assert(save->vertex_size == 0);
+}
+void vbo_save_BeginCallList( GLcontext *ctx, struct mesa_display_list *dlist )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   save->replay_flags |= dlist->flags;
+}
+
+void vbo_save_EndCallList( GLcontext *ctx )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+   
+   if (ctx->ListState.CallDepth == 1) {
+      /* This is correct: want to keep only the VBO_SAVE_FALLBACK
+       * flag, if it is set:
+       */
+      save->replay_flags &= VBO_SAVE_FALLBACK;
+   }
+}
+
+
+static void vbo_destroy_vertex_list( GLcontext *ctx, void *data )
+{
+   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
+   (void) ctx;
+
+   if ( --node->vertex_store->refcount == 0 ) 
+      free_vertex_store( ctx, node->vertex_store );
+
+   if ( --node->prim_store->refcount == 0 )
+      FREE( node->prim_store );
+}
+
+
+static void vbo_print_vertex_list( GLcontext *ctx, void *data )
+{
+   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
+   GLuint i;
+   (void) ctx;
+
+   _mesa_debug(NULL, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
+               node->count,
+              node->prim_count,
+              node->vertex_size);
+
+   for (i = 0 ; i < node->prim_count ; i++) {
+      struct _mesa_prim *prim = &node->prim[i];
+      _mesa_debug(NULL, "   prim %d: %s%s %d..%d %s %s\n",
+                 i, 
+                 _mesa_lookup_enum_by_nr(prim->mode),
+                 prim->weak ? " (weak)" : "",
+                 prim->start, 
+                 prim->start + prim->count,
+                 (prim->begin) ? "BEGIN" : "(wrap)",
+                 (prim->end) ? "END" : "(wrap)");
+   }
+}
+
+
+static void _save_current_init( GLcontext *ctx ) 
+{
+   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_FIRST_MATERIAL; i < VBO_ATTRIB_INDEX; 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;
+}
+
+/**
+ * Initialize the display list compiler
+ */
+void vbo_save_api_init( struct vbo_save_context *save )
+{
+   GLcontext *ctx = save->ctx;
+   GLuint i;
+
+   save->opcode_vertex_list =
+      _mesa_alloc_opcode( ctx,
+                         sizeof(struct vbo_save_vertex_list),
+                         vbo_save_playback_vertex_list,
+                         vbo_destroy_vertex_list,
+                         vbo_print_vertex_list );
+
+   ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
+
+   _save_vtxfmt_init( ctx );
+   _save_current_init( ctx );
+
+   for (i = 0; i < VBO_ATTRIB_MAX; i++)
+      save->inputs[i] = &save->arrays[i];
+
+   /* Hook our array functions into the outside-begin-end vtxfmt in 
+    * ctx->ListState.
+    */
+   ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
+   ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
+   ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
+   ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
+   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+}
+
diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c
new file mode 100644 (file)
index 0000000..44e0171
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * Copyright (C) 1999-2004  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.
+ */
+
+/* Author:
+ *    Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "macros.h"
+#include "light.h"
+#include "state.h"
+
+#include "vbo_context.h"
+
+
+
+static void _playback_copy_to_current( GLcontext *ctx,
+                                      const struct vbo_save_vertex_list *node )
+{
+   struct vbo_save_context *save = &vbo_context(ctx)->save; 
+   GLfloat vertex[VBO_ATTRIB_MAX * 4], *data = vertex;
+   GLuint i, offset;
+
+   if (node->count)
+      offset = node->buffer_offset + (node->count-1) * node->vertex_size;
+   else
+      offset = node->buffer_offset;
+
+   ctx->Driver.GetBufferSubData( ctx, 0, offset, node->vertex_size, 
+                                data, node->vertex_store->bufferobj );
+
+   for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; i++) {
+      if (node->attrsz[i]) {
+        COPY_CLEAN_4V(save->current[i], node->attrsz[i], data);
+        data += node->attrsz[i];
+
+        if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
+            i <= VBO_ATTRIB_MAT_BACK_INDEXES)
+           ctx->NewState |= _NEW_LIGHT;
+      }
+   }
+
+   /* Edgeflag requires special treatment:
+    */
+   if (node->attrsz[VBO_ATTRIB_EDGEFLAG]) {
+      ctx->Current.EdgeFlag = (data[0] == 1.0);
+   }
+
+
+#if 1
+   /* Colormaterial -- this kindof sucks.
+    */
+   if (ctx->Light.ColorMaterialEnabled) {
+      _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
+   }
+#endif
+
+   /* CurrentExecPrimitive
+    */
+   if (node->prim_count) {
+      const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
+      if (prim->end)
+        ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+      else
+        ctx->Driver.CurrentExecPrimitive = prim->mode;
+   }
+}
+
+
+
+/* Treat the vertex storage as a VBO, define vertex arrays pointing
+ * into it:
+ */
+static void vbo_bind_vertex_list( struct vbo_save_context *save,
+                                   const struct vbo_save_vertex_list *node )
+{
+   struct gl_client_array *arrays = save->arrays;
+   GLuint data = node->buffer_offset;
+   GLuint attr;
+
+   memset(arrays, 0, VBO_ATTRIB_MAX * sizeof(arrays[0]));
+
+   for (attr = 0; attr <= VBO_ATTRIB_INDEX; attr++) {
+      if (node->attrsz[attr]) {
+        arrays[attr].Ptr = (const GLubyte *)data;
+        arrays[attr].Size = node->attrsz[attr];
+        arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
+        arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
+        arrays[attr].Type = GL_FLOAT;
+        arrays[attr].Enabled = 1;
+        arrays[attr].BufferObj = node->vertex_store->bufferobj;
+        arrays[attr]._MaxElement = node->count; /* ??? */
+        
+        assert(arrays[attr].BufferObj->Name);
+
+        data += node->attrsz[attr] * sizeof(GLfloat);
+      }
+   }
+}
+
+static void vbo_save_loopback_vertex_list( GLcontext *ctx,
+                                          const struct vbo_save_vertex_list *list )
+{
+   const char *buffer = ctx->Driver.MapBuffer(ctx, 
+                                             GL_ARRAY_BUFFER_ARB, 
+                                             GL_DYNAMIC_READ_ARB, /* ? */
+                                              list->vertex_store->bufferobj);
+
+   vbo_loopback_vertex_list( ctx,
+                            (const GLfloat *)(buffer + list->buffer_offset),
+                            list->attrsz,
+                            list->prim,
+                            list->prim_count,
+                            list->wrap_count,
+                            list->vertex_size);
+
+   ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, 
+                          list->vertex_store->bufferobj);
+}
+
+
+/**
+ * Execute the buffer and save copied verts.
+ */
+void vbo_save_playback_vertex_list( GLcontext *ctx, void *data )
+{
+   const struct vbo_save_vertex_list *node = (const struct vbo_save_vertex_list *) data;
+   struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+   FLUSH_CURRENT(ctx, 0);
+
+   if (node->prim_count > 0 && node->count > 0) {
+
+      if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
+         node->prim[0].begin) {
+
+        /* Degenerate case: list is called inside begin/end pair and
+         * includes operations such as glBegin or glDrawArrays.
+         */
+        if (0)
+           _mesa_printf("displaylist recursive begin");
+
+        vbo_save_loopback_vertex_list( ctx, node );
+        return;
+      }
+      else if (save->replay_flags) {
+        /* Various degnerate cases: translate into immediate mode
+         * calls rather than trying to execute in place.
+         */
+        vbo_save_loopback_vertex_list( ctx, node );
+        return;
+      }
+      
+      if (ctx->NewState)
+        _mesa_update_state( ctx );
+
+      if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+          (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glBegin (invalid vertex/fragment program)");
+         return;
+      }
+
+      vbo_bind_vertex_list( save, node );
+
+      vbo_context(ctx)->draw_prims( ctx, 
+                                   save->inputs, 
+                                   node->prim, 
+                                   node->prim_count,
+                                   NULL,
+                                   0,  /* Node is a VBO, so this is ok */
+                                   node->count );
+   }
+
+   /* Copy to current?
+    */
+   _playback_copy_to_current( ctx, node );
+}
diff --git a/src/mesa/vbo/vbo_save_loopback.c b/src/mesa/vbo/vbo_save_loopback.c
new file mode 100644 (file)
index 0000000..941c4be
--- /dev/null
@@ -0,0 +1,327 @@
+/**************************************************************************
+ * 
+ * Copyright 2005 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.
+ * 
+ **************************************************************************/
+
+#include "swrast_setup/swrast_setup.h"
+#include "swrast/swrast.h"
+#include "tnl/tnl.h"
+#include "context.h"
+
+#include "vbo_context.h"
+
+#include "glheader.h"
+#include "enums.h"
+#include "glapi.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "dispatch.h"
+
+
+typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
+
+
+/* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
+static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+   CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
+}
+
+static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+   CALL_VertexAttrib2fvNV(ctx->Exec, (target, v));
+}
+
+static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+   CALL_VertexAttrib3fvNV(ctx->Exec, (target, v));
+}
+
+static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+   CALL_VertexAttrib4fvNV(ctx->Exec, (target, v));
+}
+
+static attr_func vert_attrfunc[4] = {
+   VertexAttrib1fvNV,
+   VertexAttrib2fvNV,
+   VertexAttrib3fvNV,
+   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;
+   attr_func func;
+};
+
+/* Don't emit ends and begins on wrapped primitives.  Don't replay
+ * wrapped vertices.  If we get here, it's probably because the the
+ * precalculated wrapping is wrong.
+ */
+static void loopback_prim( GLcontext *ctx,
+                          const GLfloat *buffer,
+                          const struct _mesa_prim *prim,
+                          GLuint wrap_count,
+                          GLuint vertex_size,
+                          const struct loopback_attr *la, GLuint nr )
+{
+   GLint start = prim->start;
+   GLint end = start + prim->count;
+   const GLfloat *data;
+   GLint j;
+   GLuint k;
+
+   if (0)
+      _mesa_printf("loopback prim %s(%s,%s) verts %d..%d\n",
+                  _mesa_lookup_enum_by_nr(prim->mode),
+                  prim->begin ? "begin" : "..",
+                  prim->end ? "end" : "..",
+                  start, 
+                  end);
+
+   if (prim->begin) {
+      CALL_Begin(GET_DISPATCH(), ( prim->mode ));
+   }
+   else {
+      assert(start == 0);
+      start += wrap_count;
+   }
+
+   data = buffer + start * vertex_size;
+
+   for (j = start ; j < end ; j++) {
+      const GLfloat *tmp = data + la[0].sz;
+
+      for (k = 1 ; k < nr ; k++) {
+        la[k].func( ctx, la[k].target, tmp );
+        tmp += la[k].sz;
+      }
+        
+      /* Fire the vertex
+       */
+      la[0].func( ctx, VBO_ATTRIB_POS, data );
+      data = tmp;
+   }
+
+   if (prim->end) {
+      CALL_End(GET_DISPATCH(), ());
+   }
+}
+
+/* Primitives generated by DrawArrays/DrawElements/Rectf may be
+ * caught here.  If there is no primitive in progress, execute them
+ * normally, otherwise need to track and discard the generated
+ * primitives.
+ */
+static void loopback_weak_prim( GLcontext *ctx,
+                               const struct _mesa_prim *prim )
+{
+   /* Use the prim_weak flag to ensure that if this primitive
+    * wraps, we don't mistake future vertex_lists for part of the
+    * surrounding primitive.
+    *
+    * While this flag is set, we are simply disposing of data
+    * generated by an operation now known to be a noop.
+    */
+   if (prim->begin)
+      ctx->Driver.CurrentExecPrimitive |= VBO_SAVE_PRIM_WEAK;
+   if (prim->end)
+      ctx->Driver.CurrentExecPrimitive &= ~VBO_SAVE_PRIM_WEAK;
+}
+
+
+void vbo_loopback_vertex_list( GLcontext *ctx,
+                              const GLfloat *buffer,
+                              const GLubyte *attrsz,
+                              const struct _mesa_prim *prim,
+                              GLuint prim_count,
+                              GLuint wrap_count,
+                              GLuint vertex_size)
+{
+   struct loopback_attr la[VBO_ATTRIB_MAX];
+   GLuint i, nr = 0;
+
+   for (i = 0 ; i <= VBO_ATTRIB_TEX7 ; i++) {
+      if (attrsz[i]) {
+        la[nr].target = i;
+        la[nr].sz = attrsz[i];
+        la[nr].func = vert_attrfunc[attrsz[i]-1];
+        nr++;
+      }
+   }
+
+   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))
+      {
+        loopback_weak_prim( ctx, &prim[i] );
+      }
+      else
+      {
+        loopback_prim( ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr );
+      }
+   }
+}