Rename the various function types in t_context.h to include a tnl_ prefix.
[mesa.git] / src / mesa / tnl / t_vtx_api.c
index 36ba7b6dff6255d7c912625a35f7219bb9e75620..e75ac5b3397963456c3e87b0ada6f8a6a61d9ba1 100644 (file)
@@ -41,9 +41,12 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "api_arrayelt.h"
 #include "api_noop.h"
 #include "t_vtx_api.h"
+#include "simple_list.h"
 
+static void reset_attrfv( TNLcontext *tnl );
 
-static void init_attrfv( TNLcontext *tnl );
+static tnl_attrfv_func choose[_TNL_MAX_ATTR_CODEGEN+1][4]; /* +1 for ERROR_ATTRIB */
+static tnl_attrfv_func generic_attr_func[_TNL_MAX_ATTR_CODEGEN][4];
 
 
 /* Close off the last primitive, execute the buffer, restart the
@@ -52,37 +55,57 @@ static void init_attrfv( TNLcontext *tnl );
 static void _tnl_wrap_buffers( GLcontext *ctx )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLuint last_prim = tnl->vtx.prim[tnl->vtx.prim_count-1].mode;
-   GLuint last_count = tnl->vtx.prim[tnl->vtx.prim_count-1].count;
+   
 
-   if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
-      GLint i = tnl->vtx.prim_count - 1;
-      assert(i >= 0);
-      tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter - tnl->vtx.counter) - 
-                               tnl->vtx.prim[i].start);
+   if (tnl->vtx.prim_count == 0) {
+      tnl->vtx.copied.nr = 0;
+      tnl->vtx.counter = tnl->vtx.initial_counter;
+      tnl->vtx.vbptr = tnl->vtx.buffer;
    }
+   else {
+      GLuint last_prim = tnl->vtx.prim[tnl->vtx.prim_count-1].mode;
+      GLuint last_count = tnl->vtx.prim[tnl->vtx.prim_count-1].count;
+
+      if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+        GLint i = tnl->vtx.prim_count - 1;
+        assert(i >= 0);
+        tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter - 
+                                   tnl->vtx.counter) - 
+                                  tnl->vtx.prim[i].start);
+      }
 
-   /* Execute the buffer and save copied vertices.
-    */
-   _tnl_flush_vtx( ctx );
+      /* Execute the buffer and save copied vertices.
+       */
+      if (tnl->vtx.counter != tnl->vtx.initial_counter)
+        _tnl_flush_vtx( ctx );
+      else {
+        tnl->vtx.prim_count = 0;
+        tnl->vtx.copied.nr = 0;
+      }
 
-   /* Emit a glBegin to start the new list.
-    */
-   assert(tnl->vtx.prim_count == 0);
+      /* Emit a glBegin to start the new list.
+       */
+      assert(tnl->vtx.prim_count == 0);
 
-   if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
-      tnl->vtx.prim[0].mode = ctx->Driver.CurrentExecPrimitive;
-      tnl->vtx.prim[0].start = 0;
-      tnl->vtx.prim[0].count = 0;
-      tnl->vtx.prim_count++;
+      if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+        tnl->vtx.prim[0].mode = ctx->Driver.CurrentExecPrimitive;
+        tnl->vtx.prim[0].start = 0;
+        tnl->vtx.prim[0].count = 0;
+        tnl->vtx.prim_count++;
       
-      if (tnl->vtx.copied.nr == last_count)
-        tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
+        if (tnl->vtx.copied.nr == last_count)
+           tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
+      }
    }
 }
 
 
-static void _tnl_wrap_filled_vertex( GLcontext *ctx )
+/* Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
+ *
+ * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
+ */
+void GLAPIENTRY _tnl_wrap_filled_vertex( GLcontext *ctx )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    GLfloat *data = tnl->vtx.copied.buffer;
@@ -98,7 +121,8 @@ static void _tnl_wrap_filled_vertex( GLcontext *ctx )
    assert(tnl->vtx.counter > tnl->vtx.copied.nr);
 
    for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
-      memcpy( tnl->vtx.vbptr, data, tnl->vtx.vertex_size * sizeof(GLfloat));
+      _mesa_memcpy( tnl->vtx.vbptr, data, 
+                   tnl->vtx.vertex_size * sizeof(GLfloat));
       tnl->vtx.vbptr += tnl->vtx.vertex_size;
       data += tnl->vtx.vertex_size;
       tnl->vtx.counter--;
@@ -137,7 +161,8 @@ static void _tnl_copy_to_current( GLcontext *ctx )
    /* Colormaterial -- this kindof sucks.
     */
    if (ctx->Light.ColorMaterialEnabled) {
-      _mesa_update_color_material(ctx, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
+      _mesa_update_color_material(ctx, 
+                                 ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
    }
 
    if (tnl->vtx.have_materials) {
@@ -185,12 +210,12 @@ static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
    GLfloat *tmp;
    GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
 
-
    /* Run pipeline on current vertices, copy wrapped vertices
     * to tnl->vtx.copied.
     */
    _tnl_wrap_buffers( ctx );
 
+
    /* 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.  
@@ -202,10 +227,10 @@ static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
     * begin/end so that they don't bloat the vertices.
     */
    if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
-       tnl->vtx.attrsz[attr] == 0 
-       && lastcount > 8
-      ) {
-      init_attrfv( tnl );
+       tnl->vtx.attrsz[attr] == 0 && 
+       lastcount > 8 &&
+       tnl->vtx.vertex_size) {
+      reset_attrfv( tnl );
    }
 
    /* Fix up sizes:
@@ -250,10 +275,15 @@ static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
         for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
            if (tnl->vtx.attrsz[j]) {
               if (j == attr) {
-                 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
-                 COPY_SZ_4V( dest, oldsz, data );
-                 data += oldsz;
-                 dest += newsz;
+                 if (oldsz) {
+                    ASSIGN_4V( dest, 0, 0, 0, 1 );
+                    COPY_SZ_4V( dest, oldsz, data );
+                    data += oldsz;
+                    dest += newsz;
+                 } else {
+                    COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
+                    dest += newsz;
+                 }
               }
               else {
                  GLuint sz = tnl->vtx.attrsz[j];
@@ -269,13 +299,26 @@ static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
       tnl->vtx.counter -= tnl->vtx.copied.nr;
       tnl->vtx.copied.nr = 0;
    }
+
+   /* For codegen - attrptr's may have changed, so need to redo
+    * codegen.  Might be a reasonable place to try & detect attributes
+    * in the vertex which aren't being submitted any more.
+    */
+   for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) 
+      if (tnl->vtx.attrsz[i]) {
+        GLuint j = tnl->vtx.attrsz[i] - 1;
+
+        if (i < _TNL_MAX_ATTR_CODEGEN)
+           tnl->vtx.tabfv[i][j] = choose[i][j];
+      }
+
 }
 
 
 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
-   static float id[4] = { 0, 0, 0, 1 };
+   static const GLfloat id[4] = { 0, 0, 0, 1 };
    int i;
 
    if (tnl->vtx.attrsz[attr] < sz) {
@@ -291,458 +334,168 @@ static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
       for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
         tnl->vtx.attrptr[attr][i-1] = id[i-1];
    }
-}
 
-
-
-
-/* Helper function for 'CHOOSE' macro.  Do what's necessary when an
- * entrypoint is called for the first time.
- */
-static void do_choose( GLuint attr, GLuint sz, 
-                       void (*fallback_attr_func)( const GLfloat *),
-                       void (*choose1)( const GLfloat *),
-                       void (*choose2)( const GLfloat *),
-                       void (*choose3)( const GLfloat *),
-                       void (*choose4)( const GLfloat *),
-                       const GLfloat *v )
-{ 
-   GET_CURRENT_CONTEXT( ctx ); 
-   TNLcontext *tnl = TNL_CONTEXT(ctx); 
-
-   if (tnl->vtx.attrsz[attr] != sz)
-      _tnl_fixup_vertex( ctx, attr, sz );
-   /* Does this belong here?  Necessitates resetting vtxfmt on each
-    * flush (otherwise flags won't get reset afterwards).
+   /* Does setting NeedFlush belong here?  Necessitates resetting
+    * vtxfmt on each flush (otherwise flags won't get reset
+    * afterwards).
     */
-   if (attr == 0)
+   if (attr == 0) 
       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
-   else
+   else 
       ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
-
-   /* Reset any active pointers for this attribute 
-    */
-   tnl->vtx.tabfv[attr][0] = choose1;
-   tnl->vtx.tabfv[attr][1] = choose2;
-   tnl->vtx.tabfv[attr][2] = choose3;
-   tnl->vtx.tabfv[attr][3] = choose4;
-
-   /* Update the secondary dispatch table with the new function
-    */
-   tnl->vtx.tabfv[attr][sz-1] = fallback_attr_func;
-
-   (*fallback_attr_func)(v);
-}
-
-
-/* Versions of all the entrypoints for situations where codegen isn't
- * available.  
- *
- * Note: 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 ATTRFV( ATTR, N )                              \
-static void choose_##ATTR##_##N( const GLfloat *v );   \
-                                                       \
-static void attrib_##ATTR##_##N( const GLfloat *v )    \
-{                                                      \
-   GET_CURRENT_CONTEXT( ctx );                         \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
-                                                       \
-   if ((ATTR) == 0) {                                  \
-      GLuint i;                                                \
-                                                       \
-      if (N>0) tnl->vtx.vbptr[0] = v[0];               \
-      if (N>1) tnl->vtx.vbptr[1] = v[1];               \
-      if (N>2) tnl->vtx.vbptr[2] = v[2];               \
-      if (N>3) tnl->vtx.vbptr[3] = v[3];               \
-                                                       \
-      for (i = N; i < tnl->vtx.vertex_size; i++)       \
-        tnl->vtx.vbptr[i] = tnl->vtx.vertex[i];        \
-                                                       \
-      tnl->vtx.vbptr += tnl->vtx.vertex_size;          \
-                                                       \
-      if (--tnl->vtx.counter == 0)                     \
-        _tnl_wrap_filled_vertex( ctx );                \
-   }                                                   \
-   else {                                              \
-      GLfloat *dest = tnl->vtx.attrptr[ATTR];          \
-      if (N>0) dest[0] = v[0];                         \
-      if (N>1) dest[1] = v[1];                         \
-      if (N>2) dest[2] = v[2];                         \
-      if (N>3) dest[3] = v[3];                         \
-   }                                                   \
-}
-
-#define CHOOSE( ATTR, N )                              \
-static void choose_##ATTR##_##N( const GLfloat *v )    \
-{                                                      \
-   do_choose(ATTR, N,                                  \
-            attrib_##ATTR##_##N,                       \
-            choose_##ATTR##_1,                         \
-            choose_##ATTR##_2,                         \
-            choose_##ATTR##_3,                         \
-            choose_##ATTR##_4,                         \
-            v );                                       \
-}
-
-#define INIT(ATTR)                                     \
-static void init_##ATTR( TNLcontext *tnl )             \
-{                                                      \
-   tnl->vtx.tabfv[ATTR][0] = choose_##ATTR##_1;                \
-   tnl->vtx.tabfv[ATTR][1] = choose_##ATTR##_2;                \
-   tnl->vtx.tabfv[ATTR][2] = choose_##ATTR##_3;        \
-   tnl->vtx.tabfv[ATTR][3] = choose_##ATTR##_4;                \
-}
-   
-
-#define ATTRS( ATTRIB )                                \
-   ATTRFV( ATTRIB, 1 )                         \
-   ATTRFV( ATTRIB, 2 )                         \
-   ATTRFV( ATTRIB, 3 )                         \
-   ATTRFV( ATTRIB, 4 )                         \
-   CHOOSE( ATTRIB, 1 )                         \
-   CHOOSE( ATTRIB, 2 )                         \
-   CHOOSE( ATTRIB, 3 )                         \
-   CHOOSE( ATTRIB, 4 )                         \
-   INIT( ATTRIB )                              \
-
-
-/* Generate a lot of functions.  These are the actual worker
- * functions, which are equivalent to those generated via codegen
- * elsewhere.
- */
-ATTRS( 0 )
-ATTRS( 1 )
-ATTRS( 2 )
-ATTRS( 3 )
-ATTRS( 4 )
-ATTRS( 5 )
-ATTRS( 6 )
-ATTRS( 7 )
-ATTRS( 8 )
-ATTRS( 9 )
-ATTRS( 10 )
-ATTRS( 11 )
-ATTRS( 12 )
-ATTRS( 13 )
-ATTRS( 14 )
-ATTRS( 15 )
-
-static void init_attrfv( TNLcontext *tnl )
-{   
-   if (tnl->vtx.vertex_size) {
-      GLuint i;
-      
-      init_0( tnl );
-      init_1( tnl );
-      init_2( tnl );
-      init_3( tnl );
-      init_4( tnl );
-      init_5( tnl );
-      init_6( tnl );
-      init_7( tnl );
-      init_8( tnl );
-      init_9( tnl );
-      init_10( tnl );
-      init_11( tnl );
-      init_12( tnl );
-      init_13( tnl );
-      init_14( tnl );
-      init_15( tnl );
-
-      for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) 
-        tnl->vtx.attrsz[i] = 0;
-
-      tnl->vtx.vertex_size = 0;
-      tnl->vtx.have_materials = 0;
-   }
-}
-
-/* These can be made efficient with codegen.  Further, by adding more
- * logic to do_choose(), the double-dispatch for legacy entrypoints
- * like glVertex3f() can be removed.
- */
-#define DISPATCH_ATTRFV( ATTR, COUNT, P )      \
-do {                                           \
-   GET_CURRENT_CONTEXT( ctx );                         \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
-   tnl->vtx.tabfv[ATTR][COUNT-1]( P );         \
-} while (0)
-
-#define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
-#define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
-#define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
-#define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
-
-#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
-
-#define DISPATCH_ATTR2F( ATTR, S,T )           \
-do {                                           \
-   GLfloat v[2];                               \
-   v[0] = S; v[1] = T;                         \
-   DISPATCH_ATTR2FV( ATTR, v );                        \
-} while (0)
-#define DISPATCH_ATTR3F( ATTR, S,T,R )                 \
-do {                                           \
-   GLfloat v[3];                               \
-   v[0] = S; v[1] = T; v[2] = R;               \
-   DISPATCH_ATTR3FV( ATTR, v );                        \
-} while (0)
-#define DISPATCH_ATTR4F( ATTR, S,T,R,Q )       \
-do {                                           \
-   GLfloat v[4];                               \
-   v[0] = S; v[1] = T; v[2] = R; v[3] = Q;     \
-   DISPATCH_ATTR4FV( ATTR, v );                        \
-} while (0)
-
-
-static void enum_error( void )
-{
-   GET_CURRENT_CONTEXT( ctx );
-   _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
-}
-
-static void GLAPIENTRY _tnl_Vertex2f( GLfloat x, GLfloat y )
-{
-   DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
-}
-
-static void GLAPIENTRY _tnl_Vertex2fv( const GLfloat *v )
-{
-   DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
-}
-
-static void GLAPIENTRY _tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
 }
 
-static void GLAPIENTRY _tnl_Vertex3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
-}
 
-static void GLAPIENTRY _tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+static struct _tnl_dynfn *lookup( struct _tnl_dynfn *l, GLuint key )
 {
-   DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
-}
+   struct _tnl_dynfn *f;
 
-static void GLAPIENTRY _tnl_Vertex4fv( const GLfloat *v )
-{
-   DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
-}
-
-static void GLAPIENTRY _tnl_TexCoord1f( GLfloat x )
-{
-   DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
-}
-
-static void GLAPIENTRY _tnl_TexCoord1fv( const GLfloat *v )
-{
-   DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
-}
-
-static void GLAPIENTRY _tnl_TexCoord2f( GLfloat x, GLfloat y )
-{
-   DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
-}
-
-static void GLAPIENTRY _tnl_TexCoord2fv( const GLfloat *v )
-{
-   DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
-}
+   foreach( f, l ) {
+      if (f->key == key) 
+        return f;
+   }
 
-static void GLAPIENTRY _tnl_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
+   return 0;
 }
 
-static void GLAPIENTRY _tnl_TexCoord3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
-}
 
-static void GLAPIENTRY _tnl_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+static tnl_attrfv_func do_codegen( GLcontext *ctx, GLuint attr, GLuint sz )
 {
-   DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
-}
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   struct _tnl_dynfn *dfn = 0;
 
-static void GLAPIENTRY _tnl_TexCoord4fv( const GLfloat *v )
-{
-   DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
-}
+   if (attr == 0) {
+      GLuint key = tnl->vtx.vertex_size;
 
-static void GLAPIENTRY _tnl_Normal3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
-}
+      dfn = lookup( &tnl->vtx.cache.Vertex[sz-1], key );
 
-static void GLAPIENTRY _tnl_Normal3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
-}
+      if (!dfn)
+        dfn = tnl->vtx.gen.Vertex[sz-1]( ctx, key );
+   }
+   else {
+      GLuint key = (GLuint) tnl->vtx.attrptr[attr];
 
-static void GLAPIENTRY _tnl_FogCoordfEXT( GLfloat x )
-{
-   DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
-}
+      dfn = lookup( &tnl->vtx.cache.Attribute[sz-1], key );
 
-static void GLAPIENTRY _tnl_FogCoordfvEXT( const GLfloat *v )
-{
-   DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
-}
-
-static void GLAPIENTRY _tnl_Color3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
-}
+      if (!dfn)
+        dfn = tnl->vtx.gen.Attribute[sz-1]( ctx, key );
+   }
 
-static void GLAPIENTRY _tnl_Color3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
+   if (dfn) 
+      return (tnl_attrfv_func) dfn->code;
+   else
+      return 0;
 }
 
-static void GLAPIENTRY _tnl_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
-{
-   DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
-}
+/* Helper function for 'CHOOSE' macro.  Do what's necessary when an
+ * entrypoint is called for the first time.
+ */
 
-static void GLAPIENTRY _tnl_Color4fv( const GLfloat *v )
-{
-   DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
-}
+static tnl_attrfv_func do_choose( GLuint attr, GLuint sz )
+{ 
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   GLuint oldsz = tnl->vtx.attrsz[attr];
 
-static void GLAPIENTRY _tnl_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
-}
+   assert(attr < _TNL_MAX_ATTR_CODEGEN);
 
-static void GLAPIENTRY _tnl_SecondaryColor3fvEXT( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
-}
+   if (oldsz != sz) {
+      /* Reset any active pointers for this attribute 
+       */
+      if (oldsz)
+        tnl->vtx.tabfv[attr][oldsz-1] = choose[attr][oldsz-1];
+   
+      _tnl_fixup_vertex( ctx, attr, sz );
+   }
 
-static void GLAPIENTRY _tnl_MultiTexCoord1f( GLenum target, GLfloat x  )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR1F( attr, x );
-}
 
-static void GLAPIENTRY _tnl_MultiTexCoord1fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR1FV( attr, v );
-}
+   /* Try to use codegen:
+    */
+#ifdef USE_X86_ASM
+   if (tnl->AllowCodegen)
+      tnl->vtx.tabfv[attr][sz-1] = do_codegen( ctx, attr, sz );
+   else
+#endif
+      tnl->vtx.tabfv[attr][sz-1] = 0;
 
-static void GLAPIENTRY _tnl_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR2F( attr, x, y );
-}
+   /* Else use generic version:
+    */
+   if (!tnl->vtx.tabfv[attr][sz-1])
+      tnl->vtx.tabfv[attr][sz-1] = generic_attr_func[attr][sz-1];
 
-static void GLAPIENTRY _tnl_MultiTexCoord2fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR2FV( attr, v );
+   return tnl->vtx.tabfv[attr][sz-1];
 }
 
-static void GLAPIENTRY _tnl_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
-                                   GLfloat z)
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR3F( attr, x, y, z );
-}
 
-static void GLAPIENTRY _tnl_MultiTexCoord3fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR3FV( attr, v );
-}
 
-static void GLAPIENTRY _tnl_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
-                                   GLfloat z, GLfloat w )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR4F( attr, x, y, z, w );
+#define CHOOSE( ATTR, N )                              \
+static void choose_##ATTR##_##N( const GLfloat *v )    \
+{                                                      \
+   tnl_attrfv_func f = do_choose(ATTR, N);                     \
+   f( v );                                             \
 }
 
-static void GLAPIENTRY _tnl_MultiTexCoord4fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR4FV( attr, v );
-}
+#define CHOOSERS( ATTRIB ) \
+   CHOOSE( ATTRIB, 1 )                         \
+   CHOOSE( ATTRIB, 2 )                         \
+   CHOOSE( ATTRIB, 3 )                         \
+   CHOOSE( ATTRIB, 4 )                         \
 
-static void GLAPIENTRY _tnl_VertexAttrib1fNV( GLuint index, GLfloat x )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR1F( index, x );
-   else
-      enum_error(); 
-}
 
-static void GLAPIENTRY _tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
+#define INIT_CHOOSERS(ATTR)                            \
+   choose[ATTR][0] = choose_##ATTR##_1;                                \
+   choose[ATTR][1] = choose_##ATTR##_2;                                \
+   choose[ATTR][2] = choose_##ATTR##_3;                                \
+   choose[ATTR][3] = choose_##ATTR##_4;
+
+CHOOSERS( 0 )
+CHOOSERS( 1 )
+CHOOSERS( 2 )
+CHOOSERS( 3 )
+CHOOSERS( 4 )
+CHOOSERS( 5 )
+CHOOSERS( 6 )
+CHOOSERS( 7 )
+CHOOSERS( 8 )
+CHOOSERS( 9 )
+CHOOSERS( 10 )
+CHOOSERS( 11 )
+CHOOSERS( 12 )
+CHOOSERS( 13 )
+CHOOSERS( 14 )
+CHOOSERS( 15 )
+
+static void error_attrib( const GLfloat *unused )
 {
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR1FV( index, v );
-   else
-      enum_error();
-}
+   GET_CURRENT_CONTEXT( ctx );
+   (void) unused;
+   _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
+}   
 
-static void GLAPIENTRY _tnl_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR2F( index, x, y );
-   else
-      enum_error();
-}
 
-static void GLAPIENTRY _tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR2FV( index, v );
-   else
-      enum_error();
-}
 
-static void GLAPIENTRY _tnl_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y, 
-                                 GLfloat z )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR3F( index, x, y, z );
-   else
-      enum_error();
-}
+static void reset_attrfv( TNLcontext *tnl )
+{   
+   GLuint i;
 
-static void GLAPIENTRY _tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR3FV( index, v );
-   else
-      enum_error();
-}
+   for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) 
+      if (tnl->vtx.attrsz[i]) {
+        GLint j = tnl->vtx.attrsz[i] - 1;
+        tnl->vtx.attrsz[i] = 0;
 
-static void GLAPIENTRY _tnl_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y,
-                                 GLfloat z, GLfloat w )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR4F( index, x, y, z, w );
-   else
-      enum_error();
-}
+        if (i < _TNL_MAX_ATTR_CODEGEN) {
+            while (j >= 0) {
+              tnl->vtx.tabfv[i][j] = choose[i][j];
+               j--;
+            }
+         }
+      }
 
-static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
-{
-   if (index < VERT_ATTRIB_MAX)
-      DISPATCH_ATTR4FV( index, v );
-   else
-      enum_error();
+   tnl->vtx.vertex_size = 0;
+   tnl->vtx.have_materials = 0;
 }
+      
 
 
 /* Materials:  
@@ -758,35 +511,32 @@ static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
  *
  * There is no aliasing of material attributes with other entrypoints.
  */
-#define MAT_ATTR( A, N, params )                       \
+#define OTHER_ATTR( A, N, params )             \
 do {                                                   \
    if (tnl->vtx.attrsz[A] != N) {                      \
       _tnl_fixup_vertex( ctx, A, N );                  \
-      tnl->vtx.have_materials = GL_TRUE;               \
    }                                                   \
                                                        \
    {                                                   \
       GLfloat *dest = tnl->vtx.attrptr[A];             \
-      if (N>0) dest[0] = params[0];                    \
-      if (N>1) dest[1] = params[1];                    \
-      if (N>2) dest[2] = params[2];                    \
-      if (N>3) dest[3] = params[3];                    \
-      ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;   \
+      if (N>0) dest[0] = (params)[0];                  \
+      if (N>1) dest[1] = (params)[1];                  \
+      if (N>2) dest[2] = (params)[2];                  \
+      if (N>3) dest[3] = (params)[3];                  \
    }                                                   \
 } while (0)
 
 
-#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 */      \
+#define MAT( ATTR, N, face, params )                           \
+do {                                                           \
+   if (face != GL_BACK)                                                \
+      OTHER_ATTR( ATTR, N, params ); /* front */       \
+   if (face != GL_FRONT)                                       \
+      OTHER_ATTR( ATTR + 1, N, params ); /* back */    \
 } while (0)
 
 
-/* NOTE: Have to remove/deal-with colormaterial crossovers, probably
- * later on - in the meantime just store everything.  
+/* Colormaterial is dealt with later on.
  */
 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname, 
                               const GLfloat *params )
@@ -832,44 +582,43 @@ static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
       _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
       return;
    }
-}
 
-
-#define IDX_ATTR( A, IDX )                             \
-do {                                                   \
-   GET_CURRENT_CONTEXT( ctx );                         \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
-                                                       \
-   if (tnl->vtx.attrsz[A] != 1) {                      \
-      _tnl_fixup_vertex( ctx, A, 1 );                  \
-   }                                                   \
-                                                       \
-   {                                                   \
-      GLfloat *dest = tnl->vtx.attrptr[A];             \
-      dest[0] = IDX;                           \
-      ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;   \
-   }                                                   \
-} while (0)
+   tnl->vtx.have_materials = GL_TRUE;
+}
 
 
 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
 {
-   IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   GLfloat f = (GLfloat)b;
+
+   OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
 }
 
 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
 {
-   IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)v[0] );
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   GLfloat f = (GLfloat)v[0];
+
+   OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
 }
 
 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
 {
-   IDX_ATTR( _TNL_ATTRIB_INDEX, f );
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+   OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, &f );
 }
 
 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
 {
-   IDX_ATTR( _TNL_ATTRIB_INDEX, v[0] );
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+   OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, v );
 }
 
 /* Eval
@@ -887,19 +636,19 @@ static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
 
       for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
         if (tnl->vtx.eval.map1[i].map) 
-           if (tnl->vtx.attrsz[i] < tnl->vtx.eval.map1[i].sz)
+           if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map1[i].sz)
               _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
       }
    }
 
 
-   memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex, 
-          tnl->vtx.vertex_size * sizeof(GLfloat));
+   _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex, 
+                 tnl->vtx.vertex_size * sizeof(GLfloat));
 
    _tnl_do_EvalCoord1f( ctx, u );
 
-   memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
-          tnl->vtx.vertex_size * sizeof(GLfloat));
+   _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
+                 tnl->vtx.vertex_size * sizeof(GLfloat));
 }
 
 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
@@ -915,22 +664,22 @@ static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
 
       for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
         if (tnl->vtx.eval.map2[i].map) 
-           if (tnl->vtx.attrsz[i] < tnl->vtx.eval.map2[i].sz)
+           if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map2[i].sz)
               _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
       }
 
       if (ctx->Eval.AutoNormal) 
-        if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] < 3)
+        if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] != 3)
            _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
    }
 
-   memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex, 
-          tnl->vtx.vertex_size * sizeof(GLfloat));
+   _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex, 
+                 tnl->vtx.vertex_size * sizeof(GLfloat));
 
    _tnl_do_EvalCoord2f( ctx, u, v );
 
-   memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer, 
-          tnl->vtx.vertex_size * sizeof(GLfloat));
+   _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer, 
+                 tnl->vtx.vertex_size * sizeof(GLfloat));
 }
 
 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
@@ -981,7 +730,17 @@ static void GLAPIENTRY _tnl_Begin( GLenum mode )
 
       if (ctx->NewState) {
         _mesa_update_state( ctx );
-        ctx->Exec->Begin(mode);
+
+         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;
+         }
+
+        if (!(tnl->Driver.NotifyBegin && 
+              tnl->Driver.NotifyBegin( ctx, mode )))
+            ctx->Exec->Begin(mode);
         return;
       }
 
@@ -1037,14 +796,11 @@ static void GLAPIENTRY _tnl_End( void )
 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
 {
    GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
+
    vfmt->ArrayElement = _ae_loopback_array_elt;                /* generic helper */
    vfmt->Begin = _tnl_Begin;
    vfmt->CallList = _mesa_CallList;
    vfmt->CallLists = _mesa_CallLists;
-   vfmt->Color3f = _tnl_Color3f;
-   vfmt->Color3fv = _tnl_Color3fv;
-   vfmt->Color4f = _tnl_Color4f;
-   vfmt->Color4fv = _tnl_Color4fv;
    vfmt->EdgeFlag = _tnl_EdgeFlag;
    vfmt->EdgeFlagv = _tnl_EdgeFlagv;
    vfmt->End = _tnl_End;
@@ -1054,45 +810,9 @@ static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
    vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
    vfmt->EvalPoint1 = _tnl_EvalPoint1;
    vfmt->EvalPoint2 = _tnl_EvalPoint2;
-   vfmt->FogCoordfEXT = _tnl_FogCoordfEXT;
-   vfmt->FogCoordfvEXT = _tnl_FogCoordfvEXT;
    vfmt->Indexf = _tnl_Indexf;
    vfmt->Indexfv = _tnl_Indexfv;
    vfmt->Materialfv = _tnl_Materialfv;
-   vfmt->MultiTexCoord1fARB = _tnl_MultiTexCoord1f;
-   vfmt->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fv;
-   vfmt->MultiTexCoord2fARB = _tnl_MultiTexCoord2f;
-   vfmt->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fv;
-   vfmt->MultiTexCoord3fARB = _tnl_MultiTexCoord3f;
-   vfmt->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fv;
-   vfmt->MultiTexCoord4fARB = _tnl_MultiTexCoord4f;
-   vfmt->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fv;
-   vfmt->Normal3f = _tnl_Normal3f;
-   vfmt->Normal3fv = _tnl_Normal3fv;
-   vfmt->SecondaryColor3fEXT = _tnl_SecondaryColor3fEXT;
-   vfmt->SecondaryColor3fvEXT = _tnl_SecondaryColor3fvEXT;
-   vfmt->TexCoord1f = _tnl_TexCoord1f;
-   vfmt->TexCoord1fv = _tnl_TexCoord1fv;
-   vfmt->TexCoord2f = _tnl_TexCoord2f;
-   vfmt->TexCoord2fv = _tnl_TexCoord2fv;
-   vfmt->TexCoord3f = _tnl_TexCoord3f;
-   vfmt->TexCoord3fv = _tnl_TexCoord3fv;
-   vfmt->TexCoord4f = _tnl_TexCoord4f;
-   vfmt->TexCoord4fv = _tnl_TexCoord4fv;
-   vfmt->Vertex2f = _tnl_Vertex2f;
-   vfmt->Vertex2fv = _tnl_Vertex2fv;
-   vfmt->Vertex3f = _tnl_Vertex3f;
-   vfmt->Vertex3fv = _tnl_Vertex3fv;
-   vfmt->Vertex4f = _tnl_Vertex4f;
-   vfmt->Vertex4fv = _tnl_Vertex4fv;
-   vfmt->VertexAttrib1fNV = _tnl_VertexAttrib1fNV;
-   vfmt->VertexAttrib1fvNV = _tnl_VertexAttrib1fvNV;
-   vfmt->VertexAttrib2fNV = _tnl_VertexAttrib2fNV;
-   vfmt->VertexAttrib2fvNV = _tnl_VertexAttrib2fvNV;
-   vfmt->VertexAttrib3fNV = _tnl_VertexAttrib3fNV;
-   vfmt->VertexAttrib3fvNV = _tnl_VertexAttrib3fvNV;
-   vfmt->VertexAttrib4fNV = _tnl_VertexAttrib4fNV;
-   vfmt->VertexAttrib4fvNV = _tnl_VertexAttrib4fvNV;
 
    vfmt->Rectf = _mesa_noop_Rectf;
    vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
@@ -1112,13 +832,9 @@ void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
       _tnl_flush_vtx( ctx );
    }
 
-   {
+   if (tnl->vtx.vertex_size) {
       _tnl_copy_to_current( ctx );
-
-      /* reset attrfv table
-       */
-      init_attrfv( tnl );
-      flags |= FLUSH_UPDATE_CURRENT;
+      reset_attrfv( tnl );
    }
 
    ctx->Driver.NeedFlush = 0;
@@ -1142,26 +858,105 @@ static void _tnl_current_init( GLcontext *ctx )
    tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
 }
 
+static struct _tnl_dynfn *no_codegen( GLcontext *ctx, int key )
+{
+   return 0;
+}
 
 void _tnl_vtx_init( GLcontext *ctx )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx); 
    struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
    GLuint i;
+   static int firsttime = 1;
+   
+   if (firsttime) {
+      firsttime = 0;
+
+      INIT_CHOOSERS( 0 );
+      INIT_CHOOSERS( 1 );
+      INIT_CHOOSERS( 2 );
+      INIT_CHOOSERS( 3 );
+      INIT_CHOOSERS( 4 );
+      INIT_CHOOSERS( 5 );
+      INIT_CHOOSERS( 6 );
+      INIT_CHOOSERS( 7 );
+      INIT_CHOOSERS( 8 );
+      INIT_CHOOSERS( 9 );
+      INIT_CHOOSERS( 10 );
+      INIT_CHOOSERS( 11 );
+      INIT_CHOOSERS( 12 );
+      INIT_CHOOSERS( 13 );
+      INIT_CHOOSERS( 14 );
+      INIT_CHOOSERS( 15 );
+
+      choose[ERROR_ATTRIB][0] = error_attrib;
+      choose[ERROR_ATTRIB][1] = error_attrib;
+      choose[ERROR_ATTRIB][2] = error_attrib;
+      choose[ERROR_ATTRIB][3] = error_attrib;
+
+#ifdef USE_X86_ASM
+      if (tnl->AllowCodegen) {
+         _tnl_x86choosers(choose, do_choose); /* x86 INIT_CHOOSERS */
+      }
+#endif
+
+      _tnl_generic_attr_table_init( generic_attr_func );
+   }
 
    for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
       _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
 
+   for (i = 0; i < 4; i++) {
+      make_empty_list( &tnl->vtx.cache.Vertex[i] );
+      make_empty_list( &tnl->vtx.cache.Attribute[i] );
+      tnl->vtx.gen.Vertex[i] = no_codegen;
+      tnl->vtx.gen.Attribute[i] = no_codegen;
+   }
+
+#ifdef USE_X86_ASM
+   _tnl_InitX86Codegen( &tnl->vtx.gen );
+#endif
+
    _tnl_current_init( ctx );
    _tnl_exec_vtxfmt_init( ctx );
+   _tnl_generic_exec_vtxfmt_init( ctx );
+#ifdef USE_X86_ASM
+   if (tnl->AllowCodegen) {
+      _tnl_x86_exec_vtxfmt_init( ctx ); /* x86 DISPATCH_ATTRFV */
+   }
+#endif
 
    _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
-   tnl->vtx.vertex_size = 1; init_attrfv( tnl );
+
+   memcpy( tnl->vtx.tabfv, choose, sizeof(choose) );
+
+   for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) 
+      tnl->vtx.attrsz[i] = 0;
+
+   tnl->vtx.vertex_size = 0;
+   tnl->vtx.have_materials = 0;
 }
 
+static void free_funcs( struct _tnl_dynfn *l )
+{
+   struct _tnl_dynfn *f, *tmp;
+   foreach_s (f, tmp, l) {
+      remove_from_list( f );
+      ALIGN_FREE( f->code );
+      FREE( f );
+   }
+}
 
 
 void _tnl_vtx_destroy( GLcontext *ctx )
 {
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   GLuint i;
+
+   for (i = 0; i < 4; i++) {
+      free_funcs( &tnl->vtx.cache.Vertex[i] );
+      free_funcs( &tnl->vtx.cache.Attribute[i] ); 
+   }
 }