summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2006-10-29 09:46:11 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2006-10-29 09:46:11 +0000
commitfd12b37dbada6f945a94b93ecf332d0b6a8eef06 (patch)
tree008b6ac0cd96261d838f05db95f4d1521de523e4
parenta90ab5290c6364535ef1ba4f7c09065f177287e9 (diff)
Checkpoint of new vbo-building code. Currently builds regular arrays
rather than VBO's - VBOs are easy but need to look closer at the driver interface. The trivial/tri demo works.
-rw-r--r--src/mesa/vbo/vbo_attrib.h131
-rw-r--r--src/mesa/vbo/vbo_attrib_tmp.h485
-rw-r--r--src/mesa/vbo/vbo_context.c86
-rw-r--r--src/mesa/vbo/vbo_context.h101
-rw-r--r--src/mesa/vbo/vbo_exec.c227
-rw-r--r--src/mesa/vbo/vbo_exec.h175
-rw-r--r--src/mesa/vbo/vbo_exec_api.c716
-rw-r--r--src/mesa/vbo/vbo_exec_array.c367
-rw-r--r--src/mesa/vbo/vbo_exec_draw.c199
-rw-r--r--src/mesa/vbo/vbo_exec_eval.c255
-rw-r--r--src/mesa/vbo/vbo_save.c94
-rw-r--r--src/mesa/vbo/vbo_save.h180
-rw-r--r--src/mesa/vbo/vbo_save_api.c1160
-rw-r--r--src/mesa/vbo/vbo_save_draw.c202
-rw-r--r--src/mesa/vbo/vbo_save_loopback.c327
15 files changed, 4705 insertions, 0 deletions
diff --git a/src/mesa/vbo/vbo_attrib.h b/src/mesa/vbo/vbo_attrib.h
new file mode 100644
index 0000000000..caedbd5ea6
--- /dev/null
+++ b/src/mesa/vbo/vbo_attrib.h
@@ -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
index 0000000000..72a8b04aca
--- /dev/null
+++ b/src/mesa/vbo/vbo_attrib_tmp.h
@@ -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
index 0000000000..5f28e6b0e0
--- /dev/null
+++ b/src/mesa/vbo/vbo_context.c
@@ -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
index 0000000000..6b0f14d70e
--- /dev/null
+++ b/src/mesa/vbo/vbo_context.h
@@ -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
index 0000000000..4499803b8c
--- /dev/null
+++ b/src/mesa/vbo/vbo_exec.c
@@ -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
index 0000000000..4542d2807c
--- /dev/null
+++ b/src/mesa/vbo/vbo_exec.h
@@ -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
index 0000000000..c764c4d8b6
--- /dev/null
+++ b/src/mesa/vbo/vbo_exec_api.c
@@ -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
index 0000000000..5cfa7a01a9
--- /dev/null
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -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
index 0000000000..f665c64c7a
--- /dev/null
+++ b/src/mesa/vbo/vbo_exec_draw.c
@@ -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
index 0000000000..99a8044576
--- /dev/null
+++ b/src/mesa/vbo/vbo_exec_eval.c
@@ -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
index 0000000000..0a5b705400
--- /dev/null
+++ b/src/mesa/vbo/vbo_save.c
@@ -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
index 0000000000..dbe5cafb99
--- /dev/null
+++ b/src/mesa/vbo/vbo_save.h
@@ -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
index 0000000000..8ceba2b832
--- /dev/null
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -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
index 0000000000..44e0171233
--- /dev/null
+++ b/src/mesa/vbo/vbo_save_draw.c
@@ -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
index 0000000000..941c4beea9
--- /dev/null
+++ b/src/mesa/vbo/vbo_save_loopback.c
@@ -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 );
+ }
+ }
+}