Newer version of this file
authorKeith Whitwell <keith@tungstengraphics.com>
Wed, 6 Aug 2003 17:15:29 +0000 (17:15 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Wed, 6 Aug 2003 17:15:29 +0000 (17:15 +0000)
src/mesa/tnl/t_vtx_api.c

index 4076051c87c7d943beaaeeb384802b96729d3c43..d734b67dbd80582d263b7ae5b0027053637fef69 100644 (file)
@@ -31,765 +31,821 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
  *   Keith Whitwell <keith@tungstengraphics.com>
  */
 #include "mtypes.h"
+#include "context.h"
 #include "colormac.h"
 #include "simple_list.h"
-#include "vtxfmt.h"
+#include "api_arrayelt.h"
 
-#include "tnl_vtx_api.h"
-
-/* Fallback versions of all the entrypoints for situations where
- * codegen isn't available.  This is slowed significantly by all the
- * gumph necessary to get to the tnl pointer.
- */
+#include "t_context.h"
+#include "t_vtx_api.h"
 
 
-/* MultiTexcoord ends up with both of these branches, unfortunately
- * (it may get its own version of the macro after size-tracking is
- * working). 
+/* Versions of all the entrypoints for situations where codegen isn't
+ * available.  This is slowed significantly by all the gumph necessary
+ * to get to the tnl pointer, which can be avoided with codegen.
  *
- * Errors (VertexAttribNV when ATTR>15) are handled at a higher level.  
+ * 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 ATTRF( ATTR, N, A, B, C, D )                           \
+#define ATTRF( ATTR, N, A, B, C, D )                   \
+{                                                      \
+   GET_CURRENT_CONTEXT( ctx );                         \
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
+                                                       \
+   if ((ATTR) == 0) {                                  \
+      int i;                                           \
+                                                       \
+      if (N>0) tnl->vtx.vbptr[0].f = A;                        \
+      if (N>1) tnl->vtx.vbptr[1].f = B;                        \
+      if (N>2) tnl->vtx.vbptr[2].f = C;                        \
+      if (N>3) tnl->vtx.vbptr[3].f = D;                        \
+                                                       \
+      for (i = N; i < tnl->vtx.vertex_size; i++)       \
+        tnl->vtx.vbptr[i].ui = tnl->vtx.vertex[i].ui;  \
+                                                       \
+      tnl->vtx.vbptr += tnl->vtx.vertex_size;          \
+                                                       \
+      if (--tnl->vtx.counter == 0)                     \
+        _tnl_FlushVertices( ctx, FLUSH_STORED_VERTICES );      \
+   }                                                   \
+   else {                                              \
+      union uif *dest = tnl->vtx.attrptr[ATTR];                \
+      if (N>0) dest[0].f = A;                          \
+      if (N>1) dest[1].f = B;                          \
+      if (N>2) dest[2].f = C;                          \
+      if (N>3) dest[3].f = D;                          \
+   }                                                   \
+}
+
+#define ATTR4F( ATTR, A, B, C, D )  ATTRF( ATTR, 4, A, B, C, D )
+#define ATTR3F( ATTR, A, B, C )     ATTRF( ATTR, 3, A, B, C, 1 )
+#define ATTR2F( ATTR, A, B )        ATTRF( ATTR, 2, A, B, 0, 1 )
+#define ATTR1F( ATTR, A  )          ATTRF( ATTR, 1, A, 0, 0, 1 )
+
+#define ATTRS( ATTRIB )                                                \
+static void attrib_##ATTRIB##_1_0( GLfloat s )                 \
 {                                                              \
-   GET_CURRENT_CONTEXT( ctx );                                 \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                         \
+   ATTR1F( ATTRIB, s );                                                \
+}                                                              \
                                                                \
-   if ((ATTR) == 0) {                                          \
-      int i;                                                   \
+static void attrib_##ATTRIB##_1_1( const GLfloat *v )          \
+{                                                              \
+   ATTR1F( ATTRIB, v[0] );                                     \
+}                                                              \
                                                                \
-      if (N>0) tnl->vbptr[0].f = A;                            \
-      if (N>1) tnl->vbptr[1].f = B;                            \
-      if (N>2) tnl->vbptr[2].f = C;                            \
-      if (N>3) tnl->vbptr[3].f = D;                            \
+static void attrib_##ATTRIB##_2_0( GLfloat s, GLfloat t )      \
+{                                                              \
+   ATTR2F( ATTRIB, s, t );                                     \
+}                                                              \
                                                                \
-      for (i = N; i < tnl->vertex_size; i++)                   \
-        *tnl->vbptr[i].i = tnl->vertex[i].i;                   \
+static void attrib_##ATTRIB##_2_1( const GLfloat *v )          \
+{                                                              \
+   ATTR2F( ATTRIB, v[0], v[1] );                               \
+}                                                              \
                                                                \
-      tnl->vbptr += tnl->vertex_size;                          \
+static void attrib_##ATTRIB##_3_0( GLfloat s, GLfloat t,       \
+                                  GLfloat r )                  \
+{                                                              \
+   ATTR3F( ATTRIB, s, t, r );                                  \
+}                                                              \
                                                                \
-      if (--tnl->counter == 0)                                 \
-        tnl->notify();                                         \
-   }                                                           \
-   else {                                      \
-      GLfloat *dest = tnl->attrptr[ATTR];                      \
-      if (N>0) dest[0] = A;                                    \
-      if (N>1) dest[1] = B;                                    \
-      if (N>2) dest[2] = C;                                    \
-      if (N>3) dest[3] = D;                                    \
-   }                                                           \
-}
-
-#define ATTR4F( ATTR, A, B, C, D )  ATTRF( ATTR, 4, A, B, C, D )
-#define ATTR3F( ATTR, A, B, C, D )  ATTRF( ATTR, 3, A, B, C, 1 )
-#define ATTR2F( ATTR, A, B, C, D )  ATTRF( ATTR, 2, A, B, 0, 1 )
-#define ATTR1F( ATTR, A, B, C, D )  ATTRF( ATTR, 1, A, 0, 0, 1 )
-
-#define ATTR3UB( ATTR, A, B, C )               \
-   ATTR3F( ATTR,                               \
-          UBYTE_TO_FLOAT(A),                   \
-          UBYTE_TO_FLOAT(B),                   \
-          UBYTE_TO_FLOAT(C))
-
-
-#define ATTR4UB( ATTR, A, B, C, D )            \
-   ATTR4F( ATTR,                               \
-          UBYTE_TO_FLOAT(A),                   \
-          UBYTE_TO_FLOAT(B),                   \
-          UBYTE_TO_FLOAT(C),                   \
-          UBYTE_TO_FLOAT(D))
-
-
-/* Vertex
- */
-static void tnl_Vertex2f( GLfloat x, GLfloat y )
-{
-   ATTR2F( VERT_ATTRIB_POS, x, y ); 
-}
-
-static void tnl_Vertex2fv( const GLfloat *v )
-{
-   ATTR2F( VERT_ATTRIB_POS, v[0], v[1] ); 
-}
-
-static void tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   ATTR3F( VERT_ATTRIB_POS, x, y, z ); 
-}
-
-static void tnl_Vertex3fv( const GLfloat *v )
-{
-   ATTR3F( VERT_ATTRIB_POS, v[0], v[1], v[2] ); 
-}
-
-static void tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
-{
-   ATTR4F( VERT_ATTRIB_POS, x, y, z, w ); 
-}
-
-static void tnl_Vertex4fv( const GLfloat *v )
-{
-   ATTR4F( VERT_ATTRIB_POS, v[0], v[1], v[2], v[3] ); 
+static void attrib_##ATTRIB##_3_1( const GLfloat *v )          \
+{                                                              \
+   ATTR3F( ATTRIB, v[0], v[1], v[2] );                         \
+}                                                              \
+                                                               \
+static void attrib_##ATTRIB##_4_0( GLfloat s, GLfloat t,       \
+                                  GLfloat r, GLfloat q )       \
+{                                                              \
+   ATTR4F( ATTRIB, s, t, r, q );                               \
+}                                                              \
+                                                               \
+static void attrib_##ATTRIB##_4_1( const GLfloat *v )          \
+{                                                              \
+   ATTR4F( ATTRIB, v[0], v[1], v[2], v[3] );                   \
 }
 
-
-/* Color
+/* Generate a lot of functions.  These are the actual worker
+ * functions, which are equivalent to those generated via codegen
+ * elsewhere.
  */
-static void tnl_Color3ub( GLubyte r, GLubyte g, GLubyte b )
-{
-   ATTR3UB( VERT_ATTRIB_COLOR0, r, g, b );
-}
-
-static void tnl_Color3ubv( const GLubyte *v )
-{
-   ATTR3UB( VERT_ATTRIB_COLOR0, v[0], v[1], v[2] );
-}
-
-static void tnl_Color4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a )
-{
-   ATTR4UB( VERT_ATTRIB_COLOR0, r, g, b, a );
-}
+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 )
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */ 
+static void _tnl_upgrade_vertex( GLcontext *ctx, 
+                                GLuint attr,
+                                GLuint newsz )
+{
+   GLuint oldsz = tnl->vtx.attrib[attr].sz;
+
+   _tnl_flush_immediate( ctx );
+
+   tnl->vtx.attrib[attr].sz = newsz;
+   /* What else to do here?
+    */
 
-static void tnl_Color4ubv( const GLubyte *v )
-{
-   ATTR4UB( VERT_ATTRIB_COLOR0, v[0], v[1], v[2], v[3] );
+   /* Replay stored vertices to translate them to new format: Use
+    * bitmap and ffs() to speed inner loop:
+    */
+   for (i = 0 ; i < tnl->copied_verts.nr ; i++) {
+      GLfloat *data = old_data + tnl->copied_verts.offset[i];
+
+      for (j = 1 ; j < MAX_ATTRIB ; j++) {
+        if (tnl->vtx.attrib[j].sz) {
+           if (j == attr) {
+              GLfloat tmp[4];
+              COPY_4FV( tmp, id );
+              COPY_SZ_4V( tmp, oldsz, data );
+              data += oldsz;
+              tnl->vtx.attrib[attr].fv( tmp );
+           }
+           else {
+              GLfloat *tmp = data;
+              data += tnl->vtx.attrib[j].sz;
+              tnl->vtx.attrib[j].fv( tmp );
+           }
+        }
+      }
+   }
 }
 
-static void tnl_Color3f( GLfloat r, GLfloat g, GLfloat b )
+static void _tnl_wrap_buffers( GLcontext *ctx )
 {
-   ATTR3F( VERT_ATTRIB_COLOR0, r, g, b );
-}
+   _tnl_flush_immediate( ctx );
 
-static void tnl_Color3fv( const GLfloat *v )
-{
-   ATTR3F( VERT_ATTRIB_COLOR0, v[0], v[1], v[2] );
-}
-
-static void tnl_Color4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
-{
-   ATTR4F( VERT_ATTRIB_COLOR0, r, g, b, a );
+   /* Replay stored vertices - don't really need to do this, memcpy
+    * would be fine.
+    */
+   for (i = 0 ; i < tnl->copied_verts.nr ; i++) {
+      for (j = 1 ; j < MAX_ATTRIB ; j++) {
+        GLfloat *tmp = data;
+        data += tnl->vtx.attrib[j].sz;
+        tnl->vtx.attrib[j].fv( tmp );
+      }
+   }
 }
 
-static void tnl_Color4fv( const GLfloat *v )
-{
-   ATTR4F( VERT_ATTRIB_COLOR0, v[0], v[1], v[2], v[3] );
-}
 
 
-/* Secondary Color
+/* The functions defined below (CHOOSERS) are the initial state for
+ * dispatch entries for all entrypoints except those requiring
+ * double-dispatch (multitexcoord, material, vertexattrib).
+ *
+ * These may provoke a vertex-upgrade where the existing vertex buffer
+ * is flushed and a new element is added to the active vertex layout.
+ * This can happen between begin/end pairs.
  */
-static void tnl_SecondaryColor3ubEXT( GLubyte r, GLubyte g, GLubyte b )
-{
-   ATTR3UB( VERT_ATTRIB_COLOR1, r, g, b );
-}
-
-static void tnl_SecondaryColor3ubvEXT( const GLubyte *v )
-{
-   ATTR3UB( VERT_ATTRIB_COLOR1, v[0], v[1], v[2] );
-}
-
-static void tnl_SecondaryColor3fEXT( GLfloat r, GLfloat g, GLfloat b )
-{
-   ATTR3F( VERT_ATTRIB_COLOR1, r, g, b );
-}
 
-static void tnl_SecondaryColor3fvEXT( const GLfloat *v )
-{
-   ATTR3F( VERT_ATTRIB_COLOR1, v[0], v[1], v[2] );
-}
-
-
-
-/* Fog Coord
+/* An active attribute has changed size.
  */
-static void tnl_FogCoordfEXT( GLfloat f )
+static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
 {
-   ATTR1F( VERT_ATTRIB_FOG, f );
-}
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
 
-static void tnl_FogCoordfvEXT( const GLfloat *v )
-{
-   ATTR1F( VERT_ATTRIB_FOG, v[0] );
+   if (tnl->vtx.attrib_sz[attr] < sz) {
+      /* New size is larger.  Need to flush existing vertices and get
+       * an enlarged vertex format.
+       */
+      _tnl_upgrade_vertex( tnl, attr, sz );
+   }
+   else {
+      static float id[4] = { 0, 0, 0, 1 };
+      int i;
+
+      /* New size is smaller - just need to fill in some zeros.
+       */
+      for (i = sz ; i < tnl->vtx.attrib_sz[attr] ; i++)
+        tnl->vtx.attrptr[attr][i].f = id[i];
+   }
+   
+   /* Reset the dispatch table - aliasing entrypoints are invalidated.
+    */
+   _tnl_reset_attr_dispatch_tab( ctx );
 }
 
+static int dispatch_offset[TNL_ATTRIB_MAX][4][2];
 
 
-/* Normal
- */
-static void tnl_Normal3f( GLfloat n0, GLfloat n1, GLfloat n2 )
-{
-   ATTR3F( VERT_ATTRIB_NORMAL, n0, n1, n2 );
-}
-
-static void tnl_Normal3fv( const GLfloat *v )
-{
-   ATTR3F( VERT_ATTRIB_COLOR1, v[0], v[1], v[2] );
-}
-
+static void *lookup_or_generate( GLuint attr, GLuint sz, GLuint v,
+                                void *fallback_attr_func )
+{ 
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   void *ptr = 0;
+   struct dynfn *dfn;
+   int key;
 
-/* TexCoord
- */
-static void tnl_TexCoord1f( GLfloat s )
-{
-   ATTR1F( VERT_ATTRIB_TEX0, s );
-}
+   /* This will remove any installed handlers for attr with different
+    * sz, will flush, copy and expand the copied vertices if sz won't
+    * fit in the current vertex, or will clean the current vertex if
+    * it already has this attribute in a larger size.
+    */
+   if (tnl->vtx.attrib_sz[attr] != sz)
+      _tnl_fixup_vertex( ctx, attr, sz );
 
-static void tnl_TexCoord1fv( const GLfloat *v )
-{
-   ATTR1F( VERT_ATTRIB_TEX0, v[0] );
-}
 
-static void tnl_TexCoord2f( GLfloat s, GLfloat t )
-{
-   ATTR2F( VERT_ATTRIB_TEX0, s, t );
-}
+   if (attr == 0) 
+      key = tnl->vtx.vertex_size;
+   else
+      key = (GLuint)tnl->vtx.attrptr[attr];
 
-static void tnl_TexCoord2fv( const GLfloat *v )
-{
-   ATTR2F( VERT_ATTRIB_TEX0, v[0], v[1] );
-}
+   for (dfn = tnl->vtx.generated[sz-1][v][isvertex]; dfn; dfn = dfn->next) {
+      if (dfn->key == key) {
+        ptr = dfn->code;
+        break;
+      }
+   }
 
-static void tnl_TexCoord3f( GLfloat s, GLfloat t, GLfloat r )
-{
-   ATTR3F( VERT_ATTRIB_TEX0, s, t, r );
-}
+   if (ptr == 0) {
+      dfn = tnl->vtx.codegen[sz-1][v][isvertex]( ctx, key );
+      if (dfn) {
+        ptr = dfn->code;
+        dfn->next = tnl->vtx.generated[sz-1][v][isvertex];
+        tnl->vtx.generated[sz-1][v][isvertex] = dfn;
+      }
+   }
+      
+   if (ptr == 0)
+      ptr = fallback_attr_func;
 
-static void tnl_TexCoord3fv( const GLfloat *v )
-{
-   ATTR3F( VERT_ATTRIB_TEX0, v[0], v[1], v[2] );
-}
+   ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
 
-static void tnl_TexCoord4f( GLfloat s, GLfloat t, GLfloat r, GLfloat q )
-{
-   ATTR4F( VERT_ATTRIB_TEX0, s, t, r, q );
-}
+   /* Need to set all the aliases to this function, too
+    */
+   if (dispatch_offset[attr][sz-1][v]) 
+      ((void **)tnl->Exec)[dispatch_offset[attr][sz-1][v]] = ptr;
 
-static void tnl_TexCoord4fv( const GLfloat *v )
-{
-   ATTR4F( VERT_ATTRIB_TEX0, v[0], v[1], v[2], v[3] );
+   return ptr;
 }
 
 
-/* Miscellaneous: 
+/* These functions choose one of the ATTR's generated above (or from
+ * codegen).  Like the ATTR functions, they live in the GL dispatch
+ * table and in the second-level dispatch table for MultiTexCoord,
+ * AttribNV, etc.
  *
- * These don't alias NV attributes, but still need similar treatment.
- * Basically these are attributes with numbers greater than 16.
+ * Need ATTR1 for use in constructing name of 'attrib_x_y_z' function.
  */
-static void tnl_EdgeFlag( GLboolean flag )
-{
-   GLfloat f = flag ? 1 : 0;
-   ATTR1F( VERT_ATTRIB_EDGEFLAG, f);
-}
-
-static void tnl_EdgeFlagv( const GLboolean *flag )
-{
-   GLfloat f = flag[0] ? 1 : 0;
-   ATTR1F( VERT_ATTRIB_EDGEFLAG, f);
+#define CHOOSE( ATTR1, ATTR2, SZ, V, FNTYPE, ARGS1, ARGS2 )    \
+static void choose_##ATTR2##_##SZ##_##V ARGS1                  \
+{                                                              \
+   void *ptr = lookup_or_generate(ATTR1, SZ, V,                        \
+                     (void *)attrib_##ATTR1##_##SZ##_##V );    \
+                                                               \
+   assert(ATTR1 == ATTR2);                                     \
+   ((FNTYPE) ptr) ARGS2;                                       \
 }
 
-static void tnl_Indexi( GLint idx )
-{
-   ATTR1F( VERT_ATTRIB_INDEX, idx );
-}
+#define afv (const GLfloat *v)
+#define a1f (GLfloat a)
+#define a2f (GLfloat a, GLfloat b)
+#define a3f (GLfloat a, GLfloat b, GLfloat c)
+#define a4f (GLfloat a, GLfloat b, GLfloat c, GLfloat d)
 
-static void tnl_Indexiv( const GLint *idx )
-{
-   ATTR1F( VERT_ATTRIB_INDEX, idx );
-}
-
-/* Use dispatch switching to build 'ranges' of eval vertices for each
- * type, avoiding need for flags.  (Make
- * evalcoords/evalpoints/vertices/attr0 mutually exclusive)
+/* Not that many entrypoints when it all boils down:
  */
-static void _tnl_EvalCoord1f( GLfloat u )
-{
-   ATTR1F( VERT_ATTRIB_POS, u );
-}
-
-static void _tnl_EvalCoord1fv( const GLfloat *v )
-{
-   ATTR1F( VERT_ATTRIB_POS, v[0] );
-}
-
-static void _tnl_EvalCoord2f( GLfloat u, GLfloat v )
-{
-   ATTR2F( VERT_ATTRIB_POS, u, v );
-}
-
-static void _tnl_EvalCoord2fv( const GLfloat *v )
-{
-   ATTR2F( VERT_ATTRIB_POS, v[0], v[1] );
-}
-
+CHOOSE( 0, VERT_ATTRIB_POS, 2, 1, pfv, afv, (v) )
+CHOOSE( 0, VERT_ATTRIB_POS, 2, 0, p2f, a2f, (a,b) )
+CHOOSE( 0, VERT_ATTRIB_POS, 3, 1, pfv, afv, (v) )
+CHOOSE( 0, VERT_ATTRIB_POS, 3, 0, p3f, a3f, (a,b,c) )
+CHOOSE( 0, VERT_ATTRIB_POS, 4, 1, pfv, afv, (v) )
+CHOOSE( 0, VERT_ATTRIB_POS, 4, 0, p4f, a4f, (a,b,c,d) )
+CHOOSE( 2, VERT_ATTRIB_NORMAL, 3, 1, pfv, afv, (v) )
+CHOOSE( 2, VERT_ATTRIB_NORMAL, 3, 0, p3f, a3f, (a,b,c) )
+CHOOSE( 3, VERT_ATTRIB_COLOR0, 3, 1, pfv, afv, (v) )
+CHOOSE( 3, VERT_ATTRIB_COLOR0, 3, 0, p3f, a3f, (a,b,c) )
+CHOOSE( 3, VERT_ATTRIB_COLOR0, 4, 1, pfv, afv, (v) )
+CHOOSE( 3, VERT_ATTRIB_COLOR0, 4, 0, p4f, a4f, (a,b,c,d) )
+CHOOSE( 4, VERT_ATTRIB_COLOR1, 3, 1, pfv, afv, (v) )
+CHOOSE( 4, VERT_ATTRIB_COLOR1, 3, 0, p3f, a3f, (a,b,c) )
+CHOOSE( 5, VERT_ATTRIB_FOG, 1, 1, pfv, afv, (v) )
+CHOOSE( 5, VERT_ATTRIB_FOG, 1, 0, p1f, a1f, (a) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 1, 1, pfv, afv, (v) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 1, 0, p1f, a1f, (a) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 2, 1, pfv, afv, (v) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 2, 0, p2f, a2f, (a,b) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 3, 1, pfv, afv, (v) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 3, 0, p3f, a3f, (a,b,c) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 4, 1, pfv, afv, (v) )
+CHOOSE( 8, VERT_ATTRIB_TEX0, 4, 0, p4f, a4f, (a,b,c,d) )
+
+
+/* Gack.  Need to do this without going through the
+ * GET_CURRENT_CONTEXT hoohah.  Could codegen this, I suppose...
+ */
+#define DISPATCH_ATTRFV( ATTR, COUNT, P )      \
+do {                                           \
+   GET_CURRENT_CONTEXT( ctx );                         \
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
+   tnl->vtx.tabfv[COUNT-1][ATTR]( 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 )
 
-/* Second level dispatch table for MultiTexCoord, Material and 
- * VertexAttribNV.
- *
- * Need this because we want to track things like vertex attribute
- * sizes, presence/otherwise of attribs in recorded vertices, etc, by
- * manipulating the state of dispatch tables.  Need therefore a
- * dispatch slot for each value of 'index' or 'unit' in VertexAttribNV
- * and MultiTexCoordARB.  Also need a mechnism for keeping this data
- * consistent with what's coming in via the Vertex/Normal/etc api
- * above (where aliasing exists with the traditional entrypoints).
- * Note that MultiTexCoordARB aliases with TexCoord when unit==0.
- *
- * Need presence tracking for material components, too, but not size
- * tracking or help with aliasing.  Could move material to seperate
- * dispatch without the "*4" below, or even do the checks every time.
+#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
+#ifdef USE_X86_ASM
+/* Naughty cheat:
  */
-struct attr_dispatch_tab {
-   void (*tab[32*4])( void );
-   void (*swapped[32*4])( void );
-   int swapcount;
-   int installed_sizes[32];
-};
-
-#define DISPATCH_ATTR1F( ATTR, N,  ) 
-   tnl->vb.attr_dispatch 
-
-/* Result at the back end after second dispatch -- could further
- * specialize for attr zero -- maybe just in the codegen version.
+#define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
+#define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
+#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
+#else
+/* Safe:
  */
-static void tnl_Attr1f( GLint attr, GLfloat s )
-{
-   ATTR1F( attr, s );
-}
-
-static void tnl_Attr1fv( GLint attr, const GLfloat *v )
-{
-   ATTR1F( attr, v[0] );
-}
+#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)
+#endif
 
-static void tnl_Attr2f( GLint attr, GLfloat s, GLfloat t )
-{
-   ATTR2F( attr, s, t );
-}
 
-static void tnl_Attr2fv( GLint attr, const GLfloat *v )
-{
-   ATTR2F( attr, v[0], v[1] );
-}
 
-static void tnl_Attr3f( GLint attr, GLfloat s, GLfloat t, GLfloat r )
+static void enum_error( void )
 {
-   ATTR3F( attr, s, t, r );
+   GET_CURRENT_CONTEXT( ctx );
+   _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
 }
 
-static void tnl_Attr3fv( GLint attr, const GLfloat *v )
+static void op_error( void )
 {
-   ATTR3F( attr, v[0], v[1], v[2] );
+   GET_CURRENT_CONTEXT( ctx );
+   _mesa_error( ctx, GL_INVALID_OPERATION, __FUNCTION__ );
 }
 
-static void tnl_Attr4f( GLint attr, GLfloat s, GLfloat t, GLfloat r, GLfloat q )
-{
-   ATTR4F( attr, s, t, r, q );
-}
 
-static void tnl_Attr4fv( GLint attr, const GLfloat *v )
-{
-   ATTR4F( attr, v[0], v[1], v[2], v[3] );
-}
-
-
-/* MultiTexcoord:  Send through second level dispatch.
+/* First level for MultiTexcoord:  Send through second level dispatch.
+ * These are permanently installed in the toplevel dispatch.
+ *
+ * Assembly can optimize the generation of arrays by using &s instead
+ * of building 'v'.
  */
-static void tnl_MultiTexCoord1fARB( GLenum target, GLfloat s  )
+static void _tnl_MultiTexCoord1f( GLenum target, GLfloat s  )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR1F( attr, s );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR1FV( attr, &s );
 }
 
-static void tnl_MultiTexCoord1fvARB( GLenum target, const GLfloat *v )
+static void _tnl_MultiTexCoord1fv( GLenum target, const GLfloat *v )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR1F( attr, v[0] );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR1FV( attr, v );
 }
 
-static void tnl_MultiTexCoord2fARB( GLenum target, GLfloat s, GLfloat t )
+static void _tnl_MultiTexCoord2f( GLenum target, GLfloat s, GLfloat t )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR2F( attr, s, t );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR2F( attr, s, t );
 }
 
-static void tnl_MultiTexCoord2fvARB( GLenum target, const GLfloat *v )
+static void _tnl_MultiTexCoord2fv( GLenum target, const GLfloat *v )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR2F( attr, v[0], v[1] );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR2FV( attr, v );
 }
 
-static void tnl_MultiTexCoord3fARB( GLenum target, GLfloat s, GLfloat t,
+static void _tnl_MultiTexCoord3f( GLenum target, GLfloat s, GLfloat t,
                                    GLfloat r)
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR3F( attr, s, t, r );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR3F( attr, s, t, r );
 }
 
-static void tnl_MultiTexCoord3fvARB( GLenum target, const GLfloat *v )
+static void _tnl_MultiTexCoord3fv( GLenum target, const GLfloat *v )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR3F( attr, v[0], v[1], v[2] );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR3FV( attr, v );
 }
 
-static void tnl_MultiTexCoord4fARB( GLenum target, GLfloat s, GLfloat t,
+static void _tnl_MultiTexCoord4f( GLenum target, GLfloat s, GLfloat t,
                                    GLfloat r, GLfloat q )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR4F( attr, s, t, r, q );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR4F( attr, s, t, r, q );
 }
 
-static void tnl_MultiTexCoord4fvARB( GLenum target, const GLfloat *v )
+static void _tnl_MultiTexCoord4fv( GLenum target, const GLfloat *v )
 {
-   GLuint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
-   if (attr < MAX_VERT_ATTRS)
-      DISPATCH_ATTR4F( attr, v[0], v[1], v[2], v[3] );
+   GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
+   DISPATCH_ATTR4FV( attr, v );
 }
 
 
-/* NV_vertex_program:
+/* First level for NV_vertex_program:
  *
  * Check for errors & reroute through second dispatch layer to get
  * size tracking per-attribute.
  */
-static void tnl_VertexAttrib1fNV( GLuint index, GLfloat s )
+static void _tnl_VertexAttrib1fNV( GLuint index, GLfloat s )
 {
-   if (index < MAX_VERT_ATTRS)
+   if (index < TNL_ATTRIB_MAX)
       DISPATCH_ATTR1F( index, s );
    else
-      DISPATCH_ERROR
+      enum_error()
 }
 
-static void tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
+static void _tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
 {
-   if (index < MAX_VERT_ATTRS)
-      DISPATCH_ATTR1F( index, v[0] );
+   if (index < TNL_ATTRIB_MAX)
+      DISPATCH_ATTR1FV( index, v );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
-static void tnl_VertexAttrib2fNV( GLuint index, GLfloat s, GLfloat t )
+static void _tnl_VertexAttrib2fNV( GLuint index, GLfloat s, GLfloat t )
 {
-   if (index < MAX_VERT_ATTRS)
+   if (index < TNL_ATTRIB_MAX)
       DISPATCH_ATTR2F( index, s, t );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
-static void tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
+static void _tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
 {
-   if (index < MAX_VERT_ATTRS)
-      DISPATCH_ATTR2F( index, v[0], v[1] );
+   if (index < TNL_ATTRIB_MAX)
+      DISPATCH_ATTR2FV( index, v );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
-static void tnl_VertexAttrib3fNV( GLuint index, GLfloat s, GLfloat t, 
+static void _tnl_VertexAttrib3fNV( GLuint index, GLfloat s, GLfloat t, 
                                  GLfloat r )
 {
-   if (index < MAX_VERT_ATTRS)
+   if (index < TNL_ATTRIB_MAX)
       DISPATCH_ATTR3F( index, s, t, r );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
-static void tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
+static void _tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
 {
-   if (index < MAX_VERT_ATTRS)
-      DISPATCH_ATTR3F( index, v[0], v[1], v[2] );
+   if (index < TNL_ATTRIB_MAX)
+      DISPATCH_ATTR3FV( index, v );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
-static void tnl_VertexAttrib4fNV( GLuint index, GLfloat s, GLfloat t,
+static void _tnl_VertexAttrib4fNV( GLuint index, GLfloat s, GLfloat t,
                                  GLfloat r, GLfloat q )
 {
-   if (index < MAX_VERT_ATTRS)
+   if (index < TNL_ATTRIB_MAX)
       DISPATCH_ATTR4F( index, s, t, r, q );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
-static void tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
+static void _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
 {
-   if (index < MAX_VERT_ATTRS)
-      DISPATCH_ATTR4F( index, v[0], v[1], v[2], v[3] );
+   if (index < TNL_ATTRIB_MAX)
+      DISPATCH_ATTR4FV( index, v );
    else
-      DISPATCH_ERROR;
+      enum_error();
 }
 
 
-
-
-
-
-
 /* Materials:  
  * 
  * These are treated as per-vertex attributes, at indices above where
  * the NV_vertex_program leaves off.  There are a lot of good things
  * about treating materials this way.  
  *
- * *** Need a dispatch step (like VertexAttribute GLint attr, and MultiTexCoord)
- * *** to expand vertex size, etc.  Use the same second level dispatch
- * *** (keyed by attr number) as above.
+ * However: I don't want to double the number of generated functions
+ * just to cope with this, so I unroll the 'C' varients of CHOOSE and
+ * ATTRF into this function, and dispense with codegen and
+ * second-level dispatch.
  */
-#define MAT( ATTR, face, params )              \
-do {                                           \
-   if (face != GL_BACK)                                \
-      DISPATCH_ATTRF( ATTR, N, params );       \
-   if (face != GL_FRONT)                       \
-      DISPATCH_ATTRF( ATTR+7, N, params );     \
+#define MAT_ATTR( A, N, params )                       \
+do {                                                   \
+   if (tnl->vtx.attrib_sz[A] != N) {                   \
+      tnl_fixup_vertex( ctx, A, N );                   \
+   }                                                   \
+                                                       \
+   {                                                   \
+      union uif *dest = tnl->vtx.attrptr[A];           \
+      if (N>0) dest[0].f = params[0];                  \
+      if (N>1) dest[1].f = params[1];                  \
+      if (N>2) dest[2].f = params[2];                  \
+      if (N>3) dest[3].f = params[3];                  \
+      ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;   \
+   }                                                   \
+} 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 */      \
 } while (0)
 
 
-/* NOTE: Have to remove/dealwith colormaterial crossovers, probably
- * later on - in the meantime just store everything.
+/* NOTE: Have to remove/deal-with colormaterial crossovers, probably
+ * later on - in the meantime just store everything.  
  */
 static void _tnl_Materialfv( GLenum face, GLenum pname, 
                               const GLfloat *params )
 {
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+
    switch (pname) {
    case GL_EMISSION:
-      MAT( VERT_ATTRIB_FRONT_EMMISSION, 4, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
       break;
    case GL_AMBIENT:
-      MAT( VERT_ATTRIB_FRONT_AMBIENT, 4, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
       break;
    case GL_DIFFUSE:
-      MAT( VERT_ATTRIB_FRONT_DIFFUSE, 4, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
       break;
    case GL_SPECULAR:
-      MAT( VERT_ATTRIB_FRONT_SPECULAR, 4, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
       break;
    case GL_SHININESS:
-      MAT( VERT_ATTRIB_FRONT_SHININESS, 1, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
       break;
    case GL_COLOR_INDEXES:
-      MAT( VERT_ATTRIB_FRONT_EMMISSION, 3, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
       break;
    case GL_AMBIENT_AND_DIFFUSE:
-      MAT( VERT_ATTRIB_FRONT_AMBIENT, 4, face, params );
-      MAT( VERT_ATTRIB_FRONT_DIFFUSE, 4, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+      MAT( VERT_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
       break;
    default:
-      _mesa_error( ctx, GL_INVALID_ENUM, where );
+      _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
       return;
    }
 }
 
 
+#define IDX_ATTR( A, IDX )                             \
+do {                                                   \
+   GET_CURRENT_CONTEXT( ctx );                         \
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
+                                                       \
+   if (tnl->vtx.attrib_sz[A] != 1) {                   \
+      tnl_fixup_vertex( ctx, A, 1 );                   \
+   }                                                   \
+                                                       \
+   {                                                   \
+      union uif *dest = tnl->vtx.attrptr[A];           \
+      dest[0].ui = IDX;                                \
+      ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;   \
+   }                                                   \
+} while (0)
 
 
-/* Codegen support
- */
-static struct dynfn *lookup( struct dynfn *l, int key )
+static void _tnl_EdgeFlag( GLboolean f )
 {
-   struct dynfn *f;
+   IDX_ATTR( VERT_ATTRIB_EDGEFLAG, f );
+}
 
-   foreach( f, l ) {
-      if (f->key == key) 
-        return f;
-   }
+static void _tnl_EdgeFlagv( const GLboolean *f )
+{
+   IDX_ATTR( VERT_ATTRIB_EDGEFLAG, f[0] );
+}
 
-   return 0;
+static void _tnl_Indexi( GLint i )
+{
+   IDX_ATTR( VERT_ATTRIB_INDEX, i );
 }
 
-/* Vertex descriptor
+static void _tnl_Indexiv( const GLint *i )
+{
+   IDX_ATTR( VERT_ATTRIB_INDEX, i[0] );
+}
+
+
+
+/* EvalCoord needs special treatment as ususal:
  */
-struct _tnl_vertex_descriptor {
-   GLuint attr_bits[4];
-};
+static void evalcoord( GLfloat a, GLfloat b, GLuint type ) 
+{
+#if 0
+   GET_CURRENT_CONTEXT( ctx );                                 
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                         
+   
+   /* Initialize the list of eval fixups:
+    */
+   if (!tnl->evalptr) {
+      init_eval_ptr( ctx );
+   }
 
+   /* Note that this vertex will need to be fixed up:
+    */
+   tnl->evalptr[0].vert = tnl->initial_counter - tnl->counter;
+   tnl->evalptr[0].type = type;
+
+   /* Now emit the vertex with eval data in obj coordinates:
+    */
+   ATTRF( 0, 2, a, b, 0, 1 );
+#endif
+}
+
+
+static void _tnl_EvalCoord1f( GLfloat u )
+{
+   evalcoord( u, 0, TNL_EVAL_COORD1 );
+}
+
+static void _tnl_EvalCoord1fv( const GLfloat *v )
+{
+   evalcoord( v[0], 0, TNL_EVAL_COORD1 );
+}
+
+static void _tnl_EvalCoord2f( GLfloat u, GLfloat v )
+{
+   evalcoord( u, v, TNL_EVAL_COORD2 );
+}
+
+static void _tnl_EvalCoord2fv( const GLfloat *v )
+{
+   evalcoord( v[0], v[1], TNL_EVAL_COORD2 );
+}
+
+static void _tnl_EvalPoint1( GLint i )
+{
+   evalcoord( (GLfloat)i, 0, TNL_EVAL_POINT1 );
+}
+
+static void _tnl_EvalPoint2( GLint i, GLint j )
+{
+   evalcoord( (GLfloat)i, (GLfloat)j, TNL_EVAL_POINT2 );
+}
 
-/* Can't use the loopback template for this:
+/* Don't do a lot of processing here - errors are raised when this
+ * list is scanned later on (perhaps in display list playback) to
+ * build tnl_prim structs.
  */
-#define CHOOSE(FN, FNTYPE, MASK, ACTIVE, ARGS1, ARGS2 )                        \
-static void choose_##FN ARGS1                                          \
-{                                                                      \
-   int key = tnl->vertex_format & (MASK|ACTIVE);                       \
-   struct dynfn *dfn = lookup( &tnl->dfn_cache.FN, key );              \
-                                                                       \
-   if (dfn == 0)                                                       \
-      dfn = tnl->codegen.FN( &vb, key );                               \
-   else if (MESA_VERBOSE & DEBUG_CODEGEN)                              \
-      _mesa_debug(NULL, "%s -- cached codegen\n", __FUNCTION__ );              \
-                                                                       \
-   if (dfn)                                                            \
-      tnl->context->Exec->FN = (FNTYPE)(dfn->code);                    \
-   else {                                                              \
-      if (MESA_VERBOSE & DEBUG_CODEGEN)                                        \
-        _mesa_debug(NULL, "%s -- generic version\n", __FUNCTION__ );   \
-      tnl->context->Exec->FN = tnl_##FN;                               \
-   }                                                                   \
-                                                                       \
-   tnl->context->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;             \
-   tnl->context->Exec->FN ARGS2;                                       \
-}
-
-
-
-CHOOSE(Normal3f, p3f, 3, VERT_ATTRIB_NORMAL, 
-       (GLfloat a,GLfloat b,GLfloat c), (a,b,c))
-CHOOSE(Normal3fv, pfv, 3, VERT_ATTRIB_NORMAL, 
-       (const GLfloat *v), (v))
-
-CHOOSE(Color4ub, p4ub, 4, VERT_ATTRIB_COLOR0,
-       (GLubyte a,GLubyte b, GLubyte c, GLubyte d), (a,b,c,d))
-CHOOSE(Color4ubv, pubv, 4, VERT_ATTRIB_COLOR0, 
-       (const GLubyte *v), (v))
-CHOOSE(Color3ub, p3ub, 3, VERT_ATTRIB_COLOR0, 
-       (GLubyte a,GLubyte b, GLubyte c), (a,b,c))
-CHOOSE(Color3ubv, pubv, 3, VERT_ATTRIB_COLOR0, 
-       (const GLubyte *v), (v))
-
-CHOOSE(Color4f, p4f, 4, VERT_ATTRIB_COLOR0, 
-       (GLfloat a,GLfloat b, GLfloat c, GLfloat d), (a,b,c,d))
-CHOOSE(Color4fv, pfv, 4, VERT_ATTRIB_COLOR0, 
-       (const GLfloat *v), (v))
-CHOOSE(Color3f, p3f, 3, VERT_ATTRIB_COLOR0,
-       (GLfloat a,GLfloat b, GLfloat c), (a,b,c))
-CHOOSE(Color3fv, pfv, 3, VERT_ATTRIB_COLOR0,
-       (const GLfloat *v), (v))
-
-
-CHOOSE(SecondaryColor3ubEXT, p3ub, VERT_ATTRIB_COLOR1, 
-       (GLubyte a,GLubyte b, GLubyte c), (a,b,c))
-CHOOSE(SecondaryColor3ubvEXT, pubv, VERT_ATTRIB_COLOR1, 
-       (const GLubyte *v), (v))
-CHOOSE(SecondaryColor3fEXT, p3f, VERT_ATTRIB_COLOR1,
-       (GLfloat a,GLfloat b, GLfloat c), (a,b,c))
-CHOOSE(SecondaryColor3fvEXT, pfv, VERT_ATTRIB_COLOR1,
-       (const GLfloat *v), (v))
-
-CHOOSE(TexCoord2f, p2f, VERT_ATTRIB_TEX0, 
-       (GLfloat a,GLfloat b), (a,b))
-CHOOSE(TexCoord2fv, pfv, VERT_ATTRIB_TEX0, 
-       (const GLfloat *v), (v))
-CHOOSE(TexCoord1f, p1f, VERT_ATTRIB_TEX0, 
-       (GLfloat a), (a))
-CHOOSE(TexCoord1fv, pfv, VERT_ATTRIB_TEX0, 
-       (const GLfloat *v), (v))
-
-CHOOSE(MultiTexCoord2fARB, pe2f, VERT_ATTRIB_TEX0,
-        (GLenum u,GLfloat a,GLfloat b), (u,a,b))
-CHOOSE(MultiTexCoord2fvARB, pefv, MASK_ST_ALL, ACTIVE_ST_ALL,
-       (GLenum u,const GLfloat *v), (u,v))
-CHOOSE(MultiTexCoord1fARB, pe1f, MASK_ST_ALL, ACTIVE_ST_ALL,
-        (GLenum u,GLfloat a), (u,a))
-CHOOSE(MultiTexCoord1fvARB, pefv, MASK_ST_ALL, ACTIVE_ST_ALL,
-       (GLenum u,const GLfloat *v), (u,v))
-
-CHOOSE(Vertex3f, p3f, VERT_ATTRIB_POS, 
-       (GLfloat a,GLfloat b,GLfloat c), (a,b,c))
-CHOOSE(Vertex3fv, pfv, VERT_ATTRIB_POS, 
-       (const GLfloat *v), (v))
-CHOOSE(Vertex2f, p2f, VERT_ATTRIB_POS, 
-       (GLfloat a,GLfloat b), (a,b))
-CHOOSE(Vertex2fv, pfv, VERT_ATTRIB_POS, 
-       (const GLfloat *v), (v))
-
-
-
-
-
-void _tnl_InitVtxfmtChoosers( GLvertexformat *vfmt )
-{
-   vfmt->Color3f = choose_Color3f;
-   vfmt->Color3fv = choose_Color3fv;
-   vfmt->Color3ub = choose_Color3ub;
-   vfmt->Color3ubv = choose_Color3ubv;
-   vfmt->Color4f = choose_Color4f;
-   vfmt->Color4fv = choose_Color4fv;
-   vfmt->Color4ub = choose_Color4ub;
-   vfmt->Color4ubv = choose_Color4ubv;
-   vfmt->SecondaryColor3fEXT = choose_SecondaryColor3fEXT;
-   vfmt->SecondaryColor3fvEXT = choose_SecondaryColor3fvEXT;
-   vfmt->SecondaryColor3ubEXT = choose_SecondaryColor3ubEXT;
-   vfmt->SecondaryColor3ubvEXT = choose_SecondaryColor3ubvEXT;
-   vfmt->MultiTexCoord1fARB = dd_MultiTexCoord1fARB;
-   vfmt->MultiTexCoord1fvARB = dd_MultiTexCoord1fvARB;
-   vfmt->MultiTexCoord2fARB = dd_MultiTexCoord2fARB;
-   vfmt->MultiTexCoord2fvARB = dd_MultiTexCoord2fvARB;
-   vfmt->MultiTexCoord3fARB = dd_MultiTexCoord3fARB;
-   vfmt->MultiTexCoord3fvARB = dd_MultiTexCoord3fvARB;
-   vfmt->MultiTexCoord4fARB = dd_MultiTexCoord4fARB;
-   vfmt->MultiTexCoord4fvARB = dd_MultiTexCoord4fvARB;
-   vfmt->Normal3f = choose_Normal3f;
-   vfmt->Normal3fv = choose_Normal3fv;
-   vfmt->TexCoord1f = choose_TexCoord1f;
-   vfmt->TexCoord1fv = choose_TexCoord1fv;
-   vfmt->TexCoord2f = choose_TexCoord2f;
-   vfmt->TexCoord2fv = choose_TexCoord2fv;
-   vfmt->TexCoord3f = choose_TexCoord3f;
-   vfmt->TexCoord3fv = choose_TexCoord3fv;
-   vfmt->TexCoord4f = choose_TexCoord4f;
-   vfmt->TexCoord4fv = choose_TexCoord4fv;
-   vfmt->Vertex2f = choose_Vertex2f;
-   vfmt->Vertex2fv = choose_Vertex2fv;
-   vfmt->Vertex3f = choose_Vertex3f;
-   vfmt->Vertex3fv = choose_Vertex3fv;
-   vfmt->Vertex4f = choose_Vertex4f;
-   vfmt->Vertex4fv = choose_Vertex4fv;
-   vfmt->FogCoordfvEXT = choose_FogCoordfvEXT;
-   vfmt->FogCoordfEXT = choose_FogCoordfEXT;
-   vfmt->EdgeFlag = choose_EdgeFlag;
-   vfmt->EdgeFlagv = choose_EdgeFlagv;
-   vfmt->Indexi = choose_Indexi;
-   vfmt->Indexiv = choose_Indexiv;
-   vfmt->EvalCoord1f = choose_EvalCoord1f;
-   vfmt->EvalCoord1fv = choose_EvalCoord1fv;
-   vfmt->EvalCoord2f = choose_EvalCoord2f;
-   vfmt->EvalCoord2fv = choose_EvalCoord2fv;
-   vfmt->Materialfv = dd_Materialfv;
-}
-
-
-static struct dynfn *codegen_noop( struct _vb *vb, int key )
-{
-   (void) vb; (void) key;
-   return 0;
+static void _tnl_Begin( GLenum mode )
+{
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   int i;
+
+   i = tnl->vtx.be_count++;
+   tnl->vtx.be[i].type = TNL_BEGIN;
+   tnl->vtx.be[i].idx = tnl->vtx.initial_counter - tnl->vtx.counter;
+   tnl->vtx.be[i].mode = mode;
+
+   if (tnl->vtx.be_count == TNL_BE_MAX)
+      _tnl_FlushVertices( ctx, FLUSH_STORED_VERTICES );        
 }
 
-void _tnl_InitCodegen( struct dfn_generators *gen )
+static void _tnl_End( void )
 {
-   /* Generate an attribute or vertex command.
-    */
-   gen->Attr1f = codegen_noop;
-   gen->Attr1fv = codegen_noop;
-   gen->Attr2f = codegen_noop;
-   gen->Attr2fv = codegen_noop;
-   gen->Attr3f = codegen_noop;
-   gen->Attr3fv = codegen_noop;
-   gen->Attr4f = codegen_noop;
-   gen->Attr4fv = codegen_noop;
+   GET_CURRENT_CONTEXT( ctx ); 
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   int i;
+
+   i = tnl->vtx.be_count++;
+   tnl->vtx.be[i].type = TNL_END;
+   tnl->vtx.be[i].idx = tnl->vtx.initial_counter - tnl->vtx.counter;
+   tnl->vtx.be[i].mode = 0;
+
+   if (tnl->vtx.be_count == TNL_BE_MAX)
+      _tnl_FlushVertices( ctx, FLUSH_STORED_VERTICES );        
+}
+
+
+
+
+
+
+
+static void _tnl_InitDispatch( struct _glapi_table *tab )
+{
+   GLint i;
    
-   /* Index is never zero for these...
+   /* Most operations boil down to error/transition behaviour.
+    * However if we transition eagerly, all that's needed is a single
+    * 'error' operation.  This will do for now, but requires that the
+    * old 'flush' stuff lives on in the state functions, and is
+    * wasteful if swapping is expensive (threads?).
     */
-   gen->Attr3ub = codegen_noop;
-   gen->Attr3ubv = codegen_noop;
-   gen->Attr4ub = codegen_noop;
-   gen->Attr4ubv = codegen_noop;
+   for (i = 0 ; i < sizeof(tab)/sizeof(void*) ; i++) 
+      ((void **)tab)[i] = (void *)op_error;
+
+   tab->Begin = _tnl_Begin;
+   tab->End = _tnl_End;
+   tab->Color3f = choose_VERT_ATTRIB_COLOR0_3_0;
+   tab->Color3fv = choose_VERT_ATTRIB_COLOR0_3_1;
+   tab->Color4f = choose_VERT_ATTRIB_COLOR0_4_0;
+   tab->Color4fv = choose_VERT_ATTRIB_COLOR0_4_1;
+   tab->SecondaryColor3fEXT = choose_VERT_ATTRIB_COLOR1_3_0;
+   tab->SecondaryColor3fvEXT = choose_VERT_ATTRIB_COLOR1_3_1;
+   tab->MultiTexCoord1fARB = _tnl_MultiTexCoord1f;
+   tab->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fv;
+   tab->MultiTexCoord2fARB = _tnl_MultiTexCoord2f;
+   tab->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fv;
+   tab->MultiTexCoord3fARB = _tnl_MultiTexCoord3f;
+   tab->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fv;
+   tab->MultiTexCoord4fARB = _tnl_MultiTexCoord4f;
+   tab->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fv;
+   tab->Normal3f = choose_VERT_ATTRIB_NORMAL_3_0;
+   tab->Normal3fv = choose_VERT_ATTRIB_NORMAL_3_1;
+   tab->TexCoord1f = choose_VERT_ATTRIB_TEX0_1_0;
+   tab->TexCoord1fv = choose_VERT_ATTRIB_TEX0_1_1;
+   tab->TexCoord2f = choose_VERT_ATTRIB_TEX0_2_0;
+   tab->TexCoord2fv = choose_VERT_ATTRIB_TEX0_2_1;
+   tab->TexCoord3f = choose_VERT_ATTRIB_TEX0_3_0;
+   tab->TexCoord3fv = choose_VERT_ATTRIB_TEX0_3_1;
+   tab->TexCoord4f = choose_VERT_ATTRIB_TEX0_4_0;
+   tab->TexCoord4fv = choose_VERT_ATTRIB_TEX0_4_1;
+   tab->Vertex2f = choose_VERT_ATTRIB_POS_2_0;
+   tab->Vertex2fv = choose_VERT_ATTRIB_POS_2_1;
+   tab->Vertex3f = choose_VERT_ATTRIB_POS_3_0;
+   tab->Vertex3fv = choose_VERT_ATTRIB_POS_3_1;
+   tab->Vertex4f = choose_VERT_ATTRIB_POS_4_0;
+   tab->Vertex4fv = choose_VERT_ATTRIB_POS_4_1;
+   tab->FogCoordfEXT = choose_VERT_ATTRIB_FOG_1_0;
+   tab->FogCoordfvEXT = choose_VERT_ATTRIB_FOG_1_1;
+   tab->EdgeFlag = _tnl_EdgeFlag;
+   tab->EdgeFlagv = _tnl_EdgeFlagv;
+   tab->Indexi = _tnl_Indexi;
+   tab->Indexiv = _tnl_Indexiv;
+   tab->EvalCoord1f = _tnl_EvalCoord1f;
+   tab->EvalCoord1fv = _tnl_EvalCoord1fv;
+   tab->EvalCoord2f = _tnl_EvalCoord2f;
+   tab->EvalCoord2fv = _tnl_EvalCoord2fv;
+   tab->Materialfv = _tnl_Materialfv;
+   tab->ArrayElement = _ae_loopback_array_elt;         /* generic helper */
+}
+
+
+
+static struct dynfn *codegen_noop( GLcontext *ctx, int key )
+{
+   (void) ctx; (void) key;
+   return 0;
+}
 
-   /* As above, but deal with the extra (redundant by now) index
-    * argument to the generated function.
+static void _tnl_InitCodegen( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                         
+   int sz, v, z;
+
+   /* attr[n][v] 
+    * vertex[n][v]
+    *
+    * Generated functions parameterized by:
+    *    nr     1..4
+    *    v      y/n
+    *    vertex y/n
+    *
+    * Vertex functions also parameterized by:
+    *    vertex_size
+    *  
+    * Attr functions also parameterized by:
+    *    pointer   (destination to receive data)
     */
-   gen->NVAttr1f = codegen_noop;
-   gen->NVAttr1fv = codegen_noop;
-   gen->NVAttr2f = codegen_noop;
-   gen->NVAttr2fv = codegen_noop;
-   gen->NVAttr3f = codegen_noop;
-   gen->NVAttr3fv = codegen_noop;
-   gen->NVAttr4f = codegen_noop;
-   gen->NVAttr4fv = codegen_noop;
-
+   for (sz = 1 ; sz < 5 ; sz++) {
+      for (v = 0 ; v < 2 ; v++) {
+        for (z = 0 ; z < 2 ; z++) {
+           tnl->vtx.codegen[sz-1][v][z] = codegen_noop;
+           tnl->vtx.generated[sz-1][v][z] = 0;
+        }
+      }
+   }
 
+#if 0
    if (!getenv("MESA_NO_CODEGEN")) {
 #if defined(USE_X86_ASM)
       _tnl_InitX86Codegen( gen );
@@ -805,4 +861,38 @@ void _tnl_InitCodegen( struct dfn_generators *gen )
 #if defined(USE_SPARC_ASM)
 #endif
    }
+#endif
+}
+
+
+
+
+void _tnl_vtx_init( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx); 
+   _tnl_InitDispatch( tnl->Exec );
+   _tnl_InitCodegen( ctx );
 }
+
+
+
+void _tnl_vtx_destroy( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                         
+   int sz, v, z;
+   struct dynfn *dfn, *next;
+
+   for (sz = 1 ; sz <= 4 ; sz++) {
+      for (v = 0 ; v <= 1 ; v++) {
+        for (z = 0 ; z <= 1 ; z++) {
+           dfn = tnl->vtx.generated[sz-1][v][z];
+           while (dfn) {
+              next = dfn->next;
+              FREE(dfn);
+              dfn = next;
+           }
+        }
+      }
+   }
+}
+