OSDN Git Service

Core of the future vertex engine. Isn't built yet, nor will be for a while...
authorKeith Whitwell <keith@tungstengraphics.com>
Thu, 18 Apr 2002 08:17:03 +0000 (08:17 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Thu, 18 Apr 2002 08:17:03 +0000 (08:17 +0000)
Checkpoint commit.

src/mesa/tnl/t_vtx_api.c [new file with mode: 0644]
src/mesa/tnl/t_vtx_api.h [new file with mode: 0644]
src/mesa/tnl/t_vtx_exec.c [new file with mode: 0644]
src/mesa/tnl/t_vtx_sse.c [new file with mode: 0644]
src/mesa/tnl/t_vtx_x86.c [new file with mode: 0644]

diff --git a/src/mesa/tnl/t_vtx_api.c b/src/mesa/tnl/t_vtx_api.c
new file mode 100644 (file)
index 0000000..8ae0569
--- /dev/null
@@ -0,0 +1,675 @@
+/* $XFree86$ */
+/**************************************************************************
+
+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 "mtypes.h"
+#include "colormac.h"
+#include "simple_list.h"
+#include "vtxfmt.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.
+ */
+
+
+/* MultiTexcoord ends up with both of these branches, unfortunately
+ * (it may its own version of the macro after size-tracking is working).
+ */
+#define ATTRF( ATTR, N, A, B, C, D )                   \
+{                                                      \
+   GET_CURRENT_CONTEXT( ctx );                         \
+   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
+                                                       \
+   if (((ATTR) & 0xf) == 0) {                          \
+      int i;                                           \
+                                                       \
+      if (N>0) tnl->dmaptr[0].f = A;                   \
+      if (N>1) tnl->dmaptr[1].f = B;                   \
+      if (N>2) tnl->dmaptr[2].f = C;                   \
+      if (N>3) tnl->dmaptr[3].f = D;                   \
+                                                       \
+      for (i = N; i < tnl->vertex_size; i++)           \
+        *tnl->dmaptr[i].i = tnl->vertex[i].i;          \
+                                                       \
+      tnl->dmaptr += tnl->vertex_size;                 \
+                                                       \
+      if (--tnl->counter == 0)                         \
+        tnl->notify();                                 \
+   }                                                   \
+   else {                                              \
+      GLfloat *dest = tnl->attrptr[(ATTR) & 0xf];      \
+      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] ); 
+}
+
+
+/* Color
+ */
+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 );
+}
+
+static void tnl_Color4ubv( const GLubyte *v )
+{
+   ATTR4UB( VERT_ATTRIB_COLOR0, v[0], v[1], v[2], v[3] );
+}
+
+static void tnl_Color3f( GLfloat r, GLfloat g, GLfloat b )
+{
+   ATTR3F( VERT_ATTRIB_COLOR0, r, g, b );
+}
+
+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 );
+}
+
+static void tnl_Color4fv( const GLfloat *v )
+{
+   ATTR4F( VERT_ATTRIB_COLOR0, v[0], v[1], v[2], v[3] );
+}
+
+
+/* Secondary Color
+ */
+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
+ */
+static void tnl_FogCoordfEXT( GLfloat f )
+{
+   ATTR1F( VERT_ATTRIB_FOG, f );
+}
+
+static void tnl_FogCoordfvEXT( const GLfloat *v )
+{
+   ATTR1F( VERT_ATTRIB_FOG, v[0] );
+}
+
+
+
+/* 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] );
+}
+
+
+/* TexCoord
+ */
+static void tnl_TexCoord1f( GLfloat s )
+{
+   ATTR1F( VERT_ATTRIB_TEX0, s );
+}
+
+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 );
+}
+
+static void tnl_TexCoord2fv( const GLfloat *v )
+{
+   ATTR2F( VERT_ATTRIB_TEX0, v[0], v[1] );
+}
+
+static void tnl_TexCoord3f( GLfloat s, GLfloat t, GLfloat r )
+{
+   ATTR3F( VERT_ATTRIB_TEX0, s, t, r );
+}
+
+static void tnl_TexCoord3fv( const GLfloat *v )
+{
+   ATTR3F( VERT_ATTRIB_TEX0, v[0], v[1], v[2] );
+}
+
+static void tnl_TexCoord4f( GLfloat s, GLfloat t, GLfloat r, GLfloat q )
+{
+   ATTR4F( VERT_ATTRIB_TEX0, s, t, r, q );
+}
+
+static void tnl_TexCoord4fv( const GLfloat *v )
+{
+   ATTR4F( VERT_ATTRIB_TEX0, v[0], v[1], v[2], v[3] );
+}
+
+
+/* MultiTexcoord
+ */
+static void tnl_MultiTexCoord1fARB( GLenum target, GLfloat s  )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR1F( attr, s );
+}
+
+static void tnl_MultiTexCoord1fvARB( GLenum target, const GLfloat *v )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR1F( attr, v[0] );
+}
+
+static void tnl_MultiTexCoord2fARB( GLenum target, GLfloat s, GLfloat t )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR2F( attr, s, t );
+}
+
+static void tnl_MultiTexCoord2fvARB( GLenum target, const GLfloat *v )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR2F( attr, v[0], v[1] );
+}
+
+static void tnl_MultiTexCoord3fARB( GLenum target, GLfloat s, GLfloat t,
+                                   GLfloat r)
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR3F( attr, s, t, r );
+}
+
+static void tnl_MultiTexCoord3fvARB( GLenum target, const GLfloat *v )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR3F( attr, v[0], v[1], v[2] );
+}
+
+static void tnl_MultiTexCoord4fARB( GLenum target, GLfloat s, GLfloat t,
+                                   GLfloat r, GLfloat q )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR4F( attr, s, t, r, q );
+}
+
+static void tnl_MultiTexCoord4fvARB( GLenum target, const GLfloat *v )
+{
+   GLint attr = (target - GL_TEXTURE0_ARB) + VERT_ATTRIB_TEX0;
+   ATTR4F( attr, v[0], v[1], v[2], v[3] );
+}
+
+
+/* NV_vertex_program:  
+ *
+ * *** Need second dispatch layer above this for size tracking.  One
+ * *** dispatch layer handles both VertexAttribute and MultiTexCoord 
+ */
+static void tnl_VertexAttrib1fNV( GLuint index, GLfloat s )
+{
+   ATTR1F( index, s );
+}
+
+static void tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
+{
+   ATTR1F( index, v[0] );
+}
+
+static void tnl_VertexAttrib2fNV( GLuint index, GLfloat s, GLfloat t )
+{
+   ATTR2F( index, s, t );
+}
+
+static void tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
+{
+   ATTR2F( index, v[0], v[1] );
+}
+
+static void tnl_VertexAttrib3fNV( GLuint index, GLfloat s, GLfloat t, 
+                                 GLfloat r )
+{
+   ATTR3F( index, s, t, r );
+}
+
+static void tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
+{
+   ATTR3F( index, v[0], v[1], v[2] );
+}
+
+static void tnl_VertexAttrib4fNV( GLuint index, GLfloat s, GLfloat t,
+                                 GLfloat r, GLfloat q )
+{
+   ATTR4F( index, s, t, r, q );
+}
+
+static void tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
+{
+   ATTR4F( index, v[0], v[1], v[2], v[3] );
+}
+
+
+/* Miscellaneous:  (These don't alias NV attributes, right?)
+ */
+static void tnl_EdgeFlag( GLboolean flag )
+{
+   GET_TNL;
+   tnl->edgeflagptr[0] = flag;
+}
+
+static void tnl_EdgeFlagv( const GLboolean *flag )
+{
+   GET_TNL;
+   tnl->edgeflagptr[0] = *flag;
+}
+
+static void tnl_Indexi( GLint idx )
+{
+   GET_TNL;
+   tnl->indexptr[0] = idx;
+}
+
+static void tnl_Indexiv( const GLint *idx )
+{
+   GET_TNL;
+   tnl->indexptr[0] = *idx;
+}
+
+
+
+/* Could use dispatch switching to build 'ranges' of eval vertices for
+ * each type, avoiding need for flags.  (Make
+ * evalcoords/evalpoints/vertices/attr0 mutually exclusive)
+ *  --> In which case, may as well use Vertex{12}f{v} here.
+ */
+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] );
+}
+
+
+/* Materials:  
+ *  *** Treat as more vertex attributes
+ */
+static void _tnl_Materialfv( GLenum face, GLenum pname, 
+                              const GLfloat *params )
+{
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s\n", __FUNCTION__);
+
+   if (tnl->prim[0] != GL_POLYGON+1) {
+      VFMT_FALLBACK( __FUNCTION__ );
+      glMaterialfv( face, pname, params );
+      return;
+   }
+   _mesa_noop_Materialfv( face, pname, params );
+}
+
+
+
+
+/* Codegen support
+ */
+static struct dynfn *lookup( struct dynfn *l, int key )
+{
+   struct dynfn *f;
+
+   foreach( f, l ) {
+      if (f->key == key) 
+        return f;
+   }
+
+   return 0;
+}
+
+/* Can't use the loopback template for this:
+ */
+#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)                              \
+      fprintf(stderr, "%s -- cached codegen\n", __FUNCTION__ );                \
+                                                                       \
+   if (dfn)                                                            \
+      tnl->context->Exec->FN = (FNTYPE)(dfn->code);                    \
+   else {                                                              \
+      if (MESA_VERBOSE & DEBUG_CODEGEN)                                        \
+        fprintf(stderr, "%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 = choose_MultiTexCoord1fARB;
+   vfmt->MultiTexCoord1fvARB = choose_MultiTexCoord1fvARB;
+   vfmt->MultiTexCoord2fARB = choose_MultiTexCoord2fARB;
+   vfmt->MultiTexCoord2fvARB = choose_MultiTexCoord2fvARB;
+   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->Vertex2f = choose_Vertex2f;
+   vfmt->Vertex2fv = choose_Vertex2fv;
+   vfmt->Vertex3f = choose_Vertex3f;
+   vfmt->Vertex3fv = choose_Vertex3fv;
+   vfmt->TexCoord3f = choose_TexCoord3f;
+   vfmt->TexCoord3fv = choose_TexCoord3fv;
+   vfmt->TexCoord4f = choose_TexCoord4f;
+   vfmt->TexCoord4fv = choose_TexCoord4fv;
+   vfmt->MultiTexCoord3fARB = choose_MultiTexCoord3fARB;
+   vfmt->MultiTexCoord3fvARB = choose_MultiTexCoord3fvARB;
+   vfmt->MultiTexCoord4fARB = choose_MultiTexCoord4fARB;
+   vfmt->MultiTexCoord4fvARB = choose_MultiTexCoord4fvARB;
+   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->EvalMesh1 = choose_EvalMesh1;
+   vfmt->EvalMesh2 = choose_EvalMesh2;
+   vfmt->EvalPoint1 = choose_EvalPoint1;
+   vfmt->EvalPoint2 = choose_EvalPoint2;
+
+   vfmt->Materialfv = _tnl_Materialfv;
+}
+
+
+static struct dynfn *codegen_noop( struct _vb *vb, int key )
+{
+   (void) vb; (void) key;
+   return 0;
+}
+
+void _tnl_InitCodegen( struct dfn_generators *gen )
+{
+   gen->Vertex2f = codegen_noop;
+   gen->Vertex2fv = codegen_noop;
+   gen->Vertex3f = codegen_noop;
+   gen->Vertex3fv = codegen_noop;
+   gen->Vertex4f = codegen_noop;
+   gen->Vertex4fv = codegen_noop;
+
+   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;
+   gen->Attr3ub = codegen_noop;
+   gen->Attr3ubv = codegen_noop;
+   gen->Attr4ub = codegen_noop;
+   gen->Attr4ubv = codegen_noop;
+
+   /* Probably need two versions of this, one for the front end
+    * (double dispatch), one for the back end (do the work) -- but
+    * will also need a second level of CHOOSE functions?
+    *   -- Generate the dispatch layer using the existing templates somehow.
+    *   -- Generate the backend and 2nd level choosers here.
+    *   -- No need for a chooser on the top level.
+    *   -- Can aliasing help -- ie can NVAttr1f == Attr1f/Vertex2f at this level (index is known)
+    */
+   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;
+
+   gen->MTAttr1f = codegen_noop;
+   gen->MTAttr1fv = codegen_noop;
+   gen->MTAttr2f = codegen_noop;
+   gen->MTAttr2fv = codegen_noop;
+   gen->MTAttr3f = codegen_noop;
+   gen->MTAttr3fv = codegen_noop;
+   gen->MTAttr4f = codegen_noop;
+   gen->MTAttr4fv = codegen_noop;
+
+   if (!getenv("MESA_NO_CODEGEN")) {
+#if defined(USE_X86_ASM)
+      _tnl_InitX86Codegen( gen );
+#endif
+
+#if defined(USE_SSE_ASM)
+      _tnl_InitSSECodegen( gen );
+#endif
+
+#if defined(USE_3DNOW_ASM)
+#endif
+
+#if defined(USE_SPARC_ASM)
+#endif
+   }
+}
diff --git a/src/mesa/tnl/t_vtx_api.h b/src/mesa/tnl/t_vtx_api.h
new file mode 100644 (file)
index 0000000..6bfdbe8
--- /dev/null
@@ -0,0 +1,234 @@
+/* $XFree86$ */
+/**************************************************************************
+
+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 __RADEON_VTXFMT_H__
+#define __RADEON_VTXFMT_H__
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include "_tnl__context.h"
+
+extern void _tnl_UpdateVtxfmt( GLcontext *ctx );
+extern void _tnl_InitVtxfmt( GLcontext *ctx );
+extern void _tnl_InvalidateVtxfmt( GLcontext *ctx );
+extern void _tnl_DestroyVtxfmt( GLcontext *ctx );
+
+typedef void (*p4f)( GLfloat, GLfloat, GLfloat, GLfloat );
+typedef void (*p3f)( GLfloat, GLfloat, GLfloat );
+typedef void (*p2f)( GLfloat, GLfloat );
+typedef void (*p1f)( GLfloat );
+typedef void (*pe2f)( GLenum, GLfloat, GLfloat );
+typedef void (*pe1f)( GLenum, GLfloat );
+typedef void (*p4ub)( GLubyte, GLubyte, GLubyte, GLubyte );
+typedef void (*p3ub)( GLubyte, GLubyte, GLubyte );
+typedef void (*pfv)( const GLfloat * );
+typedef void (*pefv)( GLenum, const GLfloat * );
+typedef void (*pubv)( const GLubyte * );
+
+/* Want to keep a cache of these around.  Each is parameterized by
+ * only a single value which has only a small range.  Only expect a
+ * few, so just rescan the list each time?
+ */
+struct dynfn {
+   struct dynfn *next, *prev;
+   int key;
+   char *code;
+};
+
+struct dfn_lists {
+   struct dynfn Vertex2f;
+   struct dynfn Vertex2fv;
+   struct dynfn Vertex3f;
+   struct dynfn Vertex3fv;
+   struct dynfn Color4ub;
+   struct dynfn Color4ubv;
+   struct dynfn Color3ub;
+   struct dynfn Color3ubv;
+   struct dynfn Color4f;
+   struct dynfn Color4fv;
+   struct dynfn Color3f;
+   struct dynfn Color3fv;
+   struct dynfn SecondaryColor3ubEXT;
+   struct dynfn SecondaryColor3ubvEXT;
+   struct dynfn SecondaryColor3fEXT;
+   struct dynfn SecondaryColor3fvEXT;
+   struct dynfn Normal3f;
+   struct dynfn Normal3fv;
+   struct dynfn TexCoord2f;
+   struct dynfn TexCoord2fv;
+   struct dynfn TexCoord1f;
+   struct dynfn TexCoord1fv;
+   struct dynfn MultiTexCoord2fARB;
+   struct dynfn MultiTexCoord2fvARB;
+   struct dynfn MultiTexCoord1fARB;
+   struct dynfn MultiTexCoord1fvARB;
+};
+
+struct _vb;
+
+struct dfn_generators {
+   struct dynfn *(*Vertex2f)( struct _vb *, int );
+   struct dynfn *(*Vertex2fv)( struct _vb *, int );
+   struct dynfn *(*Vertex3f)( struct _vb *, int );
+   struct dynfn *(*Vertex3fv)( struct _vb *, int );
+   struct dynfn *(*Color4ub)( struct _vb *, int );
+   struct dynfn *(*Color4ubv)( struct _vb *, int );
+   struct dynfn *(*Color3ub)( struct _vb *, int );
+   struct dynfn *(*Color3ubv)( struct _vb *, int );
+   struct dynfn *(*Color4f)( struct _vb *, int );
+   struct dynfn *(*Color4fv)( struct _vb *, int );
+   struct dynfn *(*Color3f)( struct _vb *, int );
+   struct dynfn *(*Color3fv)( struct _vb *, int );
+   struct dynfn *(*SecondaryColor3ubEXT)( struct _vb *, int );
+   struct dynfn *(*SecondaryColor3ubvEXT)( struct _vb *, int );
+   struct dynfn *(*SecondaryColor3fEXT)( struct _vb *, int );
+   struct dynfn *(*SecondaryColor3fvEXT)( struct _vb *, int );
+   struct dynfn *(*Normal3f)( struct _vb *, int );
+   struct dynfn *(*Normal3fv)( struct _vb *, int );
+   struct dynfn *(*TexCoord2f)( struct _vb *, int );
+   struct dynfn *(*TexCoord2fv)( struct _vb *, int );
+   struct dynfn *(*TexCoord1f)( struct _vb *, int );
+   struct dynfn *(*TexCoord1fv)( struct _vb *, int );
+   struct dynfn *(*MultiTexCoord2fARB)( struct _vb *, int );
+   struct dynfn *(*MultiTexCoord2fvARB)( struct _vb *, int );
+   struct dynfn *(*MultiTexCoord1fARB)( struct _vb *, int );
+   struct dynfn *(*MultiTexCoord1fvARB)( struct _vb *, int );
+};
+
+struct prim {
+   GLuint start;
+   GLuint end;
+   GLuint prim;
+};
+
+#define _TNL__MAX_PRIMS 64
+
+
+
+struct tnl_vbinfo {
+   /* Keep these first: referenced from codegen templates:
+    */
+   GLint counter;
+   GLint *dmaptr;
+   void (*notify)( void );
+   union { float f; int i; GLubyte ub4[4]; } vertex[16*4];
+
+   GLfloat *attrptr[16];
+   GLuint size[16];
+
+   GLenum *prim;               /* &ctx->Driver.CurrentExecPrimitive */
+   GLuint primflags;
+
+   GLboolean installed;
+   GLboolean recheck;
+
+   GLint vertex_size;
+   GLint initial_counter;
+   GLint nrverts;
+   GLuint vertex_format;
+
+   GLuint installed_vertex_format;
+
+   struct prim primlist[RADEON_MAX_PRIMS];
+   int nrprims;
+
+   struct dfn_lists dfn_cache;
+   struct dfn_generators codegen;
+   GLvertexformat vtxfmt;
+};
+
+
+extern void _tnl_InitVtxfmtChoosers( GLvertexformat *vfmt );
+
+
+#define FIXUP( CODE, OFFSET, CHECKVAL, NEWVAL )        \
+do {                                           \
+   int *icode = (int *)(CODE+OFFSET);          \
+   assert (*icode == CHECKVAL);                        \
+   *icode = (int)NEWVAL;                       \
+} while (0)
+
+
+/* Useful for figuring out the offsets:
+ */
+#define FIXUP2( CODE, OFFSET, CHECKVAL, NEWVAL )               \
+do {                                                           \
+   while (*(int *)(CODE+OFFSET) != CHECKVAL) OFFSET++;         \
+   fprintf(stderr, "%s/%d CVAL %x OFFSET %d\n", __FUNCTION__,  \
+          __LINE__, CHECKVAL, OFFSET);                         \
+   *(int *)(CODE+OFFSET) = (int)NEWVAL;                                \
+   OFFSET += 4;                                                        \
+} while (0)
+
+/* 
+ */
+void _tnl_InitCodegen( struct dfn_generators *gen );
+void _tnl_InitX86Codegen( struct dfn_generators *gen );
+void _tnl_InitSSECodegen( struct dfn_generators *gen );
+
+void _tnl_copy_to_current( GLcontext *ctx );
+
+
+/* Defined in tnl_vtxfmt_c.c.
+ */
+struct dynfn *tnl_makeX86Vertex2f( TNLcontext *, int );
+struct dynfn *tnl_makeX86Vertex2fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86Vertex3f( TNLcontext *, int );
+struct dynfn *tnl_makeX86Vertex3fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color4ub( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color4ubv( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color3ub( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color3ubv( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color4f( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color4fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color3f( TNLcontext *, int );
+struct dynfn *tnl_makeX86Color3fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86SecondaryColor3ubEXT( TNLcontext *, int );
+struct dynfn *tnl_makeX86SecondaryColor3ubvEXT( TNLcontext *, int );
+struct dynfn *tnl_makeX86SecondaryColor3fEXT( TNLcontext *, int );
+struct dynfn *tnl_makeX86SecondaryColor3fvEXT( TNLcontext *, int );
+struct dynfn *tnl_makeX86Normal3f( TNLcontext *, int );
+struct dynfn *tnl_makeX86Normal3fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86TexCoord2f( TNLcontext *, int );
+struct dynfn *tnl_makeX86TexCoord2fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86TexCoord1f( TNLcontext *, int );
+struct dynfn *tnl_makeX86TexCoord1fv( TNLcontext *, int );
+struct dynfn *tnl_makeX86MultiTexCoord2fARB( TNLcontext *, int );
+struct dynfn *tnl_makeX86MultiTexCoord2fvARB( TNLcontext *, int );
+struct dynfn *tnl_makeX86MultiTexCoord1fARB( TNLcontext *, int );
+struct dynfn *tnl_makeX86MultiTexCoord1fvARB( TNLcontext *, int );
+
+
+#endif
+#endif
diff --git a/src/mesa/tnl/t_vtx_exec.c b/src/mesa/tnl/t_vtx_exec.c
new file mode 100644 (file)
index 0000000..8470d6a
--- /dev/null
@@ -0,0 +1,636 @@
+/* $XFree86$ */
+/**************************************************************************
+
+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 "api_noop.h"
+#include "api_arrayelt.h"
+#include "context.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+#include "enums.h"
+#include "glapi.h"
+#include "colormac.h"
+#include "light.h"
+#include "state.h"
+#include "vtxfmt.h"
+
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_array_api.h"
+
+static void _tnl_FlushVertices( GLcontext *, GLuint );
+
+
+void tnl_copy_to_current( GLcontext *ctx ) 
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   GLuint flag = tnl->vertex_format;
+   GLint i;
+
+   assert(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT);
+
+   for (i = 0 ; i < 16 ; i++)
+      if (flag & (1<<i))
+        COPY_4FV( ctx->Current.Attrib[i], tnl->attribptr[i] );
+
+   if (flag & VERT_BIT_INDEX)
+      ctx->Current.Index = tnl->indexptr[0];
+
+   if (flag & VERT_BIT_EDGEFLAG)
+      ctx->Current.EdgeFlag = tnl->edgeflagptr[0];
+
+   if (flag & VERT_BIT_MATERIAL) {
+      _mesa_update_material( ctx,
+                         IM->Material[IM->LastMaterial],
+                         IM->MaterialOrMask );
+
+      tnl->Driver.NotifyMaterialChange( ctx );
+   }
+
+
+   ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+}
+
+static GLboolean discreet_gl_prim[GL_POLYGON+1] = {
+   1,                          /* 0 points */
+   1,                          /* 1 lines */
+   0,                          /* 2 line_strip */
+   0,                          /* 3 line_loop */
+   1,                          /* 4 tris */
+   0,                          /* 5 tri_fan */
+   0,                          /* 6 tri_strip */
+   1,                          /* 7 quads */
+   0,                          /* 8 quadstrip */
+   0,                          /* 9 poly */
+};
+
+/* Optimize the primitive list:  ONLY FOR EXECUTE ATM
+ */
+static void optimize_prims( TNLcontext *tnl )
+{
+   int i, j;
+
+   if (tnl->nrprims <= 1)
+      return;
+
+   for (j = 0, i = 1 ; i < tnl->nrprims; i++) {
+      int pj = tnl->primlist[j].prim & 0xf;
+      int pi = tnl->primlist[i].prim & 0xf;
+      
+      if (pj == pi && discreet_gl_prim[pj] &&
+         tnl->primlist[i].start == tnl->primlist[j].end) {
+        tnl->primlist[j].end = tnl->primlist[i].end;
+      }
+      else {
+        j++;
+        if (j != i) tnl->primlist[j] = tnl->primlist[i];
+      }
+   }
+
+   tnl->nrprims = j+1;
+}
+
+
+/* Bind vertex buffer pointers, run pipeline:
+ */
+static void flush_prims( TNLcontext *tnl )
+{
+   int i,j;
+
+   tnl->dma.current.ptr = tnl->dma.current.start += 
+      (tnl->initial_counter - tnl->counter) * tnl->vertex_size * 4; 
+
+   tnl->tcl.vertex_format = tnl->vertex_format;
+   tnl->tcl.aos_components[0] = &tmp;
+   tnl->tcl.nr_aos_components = 1;
+   tnl->dma.flush = 0;
+
+   tnl->Driver.RunPipeline( ... );
+   
+   tnl->nrprims = 0;
+}
+
+
+static void start_prim( TNLcontext *tnl, GLuint mode )
+{
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s %d\n", __FUNCTION__, 
+             tnl->initial_counter - tnl->counter);
+
+   tnl->primlist[tnl->nrprims].start = tnl->initial_counter - tnl->counter;
+   tnl->primlist[tnl->nrprims].prim = mode;
+}
+
+static void note_last_prim( TNLcontext *tnl, GLuint flags )
+{
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s %d\n", __FUNCTION__, 
+             tnl->initial_counter - tnl->counter);
+
+   if (tnl->prim[0] != GL_POLYGON+1) {
+      tnl->primlist[tnl->nrprims].prim |= flags;
+      tnl->primlist[tnl->nrprims].end = tnl->initial_counter - tnl->counter;
+
+      if (++tnl->nrprims == TNL_MAX_PRIMS)
+        flush_prims( tnl );
+   }
+}
+
+
+static void copy_vertex( TNLcontext *tnl, GLuint n, GLfloat *dst )
+{
+   GLuint i;
+   GLfloat *src = (GLfloat *)(tnl->dma.current.address + 
+                             tnl->dma.current.ptr + 
+                             (tnl->primlist[tnl->nrprims].start + n) * 
+                             tnl->vertex_size * 4);
+
+   if (MESA_VERBOSE & DEBUG_VFMT) 
+      fprintf(stderr, "copy_vertex %d\n", 
+             tnl->primlist[tnl->nrprims].start + n);
+
+   for (i = 0 ; i < tnl->vertex_size; i++) {
+      dst[i] = src[i];
+   }
+}
+
+/* NOTE: This actually reads the copied vertices back from uncached
+ * memory.  Could also use the counter/notify mechanism to populate
+ * tmp on the fly as vertices are generated.  
+ */
+static GLuint copy_wrapped_verts( TNLcontext *tnl, GLfloat (*tmp)[15] )
+{
+   GLuint ovf, i;
+   GLuint nr = (tnl->initial_counter - tnl->counter) - tnl->primlist[tnl->nrprims].start;
+
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s %d verts\n", __FUNCTION__, nr);
+
+   switch( tnl->prim[0] )
+   {
+   case GL_POINTS:
+      return 0;
+   case GL_LINES:
+      ovf = nr&1;
+      for (i = 0 ; i < ovf ; i++)
+        copy_vertex( tnl, nr-ovf+i, tmp[i] );
+      return i;
+   case GL_TRIANGLES:
+      ovf = nr%3;
+      for (i = 0 ; i < ovf ; i++)
+        copy_vertex( tnl, nr-ovf+i, tmp[i] );
+      return i;
+   case GL_QUADS:
+      ovf = nr&3;
+      for (i = 0 ; i < ovf ; i++)
+        copy_vertex( tnl, nr-ovf+i, tmp[i] );
+      return i;
+   case GL_LINE_STRIP:
+      if (nr == 0) 
+        return 0;
+      copy_vertex( tnl, nr-1, tmp[0] );
+      return 1;
+   case GL_LINE_LOOP:
+   case GL_TRIANGLE_FAN:
+   case GL_POLYGON:
+      if (nr == 0) 
+        return 0;
+      else if (nr == 1) {
+        copy_vertex( tnl, 0, tmp[0] );
+        return 1;
+      } else {
+        copy_vertex( tnl, 0, tmp[0] );
+        copy_vertex( tnl, nr-1, tmp[1] );
+        return 2;
+      }
+   case GL_TRIANGLE_STRIP:
+      ovf = MIN2( nr-1, 2 );
+      for (i = 0 ; i < ovf ; i++)
+        copy_vertex( tnl, nr-ovf+i, tmp[i] );
+      return i;
+   case GL_QUAD_STRIP:
+      ovf = MIN2( nr-1, 2 );
+      if (nr > 2) ovf += nr&1;
+      for (i = 0 ; i < ovf ; i++)
+        copy_vertex( tnl, nr-ovf+i, tmp[i] );
+      return i;
+   default:
+      assert(0);
+      return 0;
+   }
+}
+
+
+
+/* Extend for vertex-format changes on wrap:
+ */
+static void wrap_buffer( void )
+{
+   TNLcontext *tnl = tnl->tnl;
+   GLfloat tmp[3][15];
+   GLuint i, nrverts;
+
+   if (MESA_VERBOSE & (DEBUG_VFMT|DEBUG_PRIMS))
+      fprintf(stderr, "%s %d\n", __FUNCTION__, 
+             tnl->initial_counter - tnl->counter);
+
+   /* Don't deal with parity.  *** WONT WORK FOR COMPILE
+    */
+   if ((((tnl->initial_counter - tnl->counter) -  
+        tnl->primlist[tnl->nrprims].start) & 1)) {
+      tnl->counter++;
+      tnl->initial_counter++;
+      return;
+   }
+
+   /* Copy vertices out of dma:
+    */
+   nrverts = copy_dma_verts( tnl, tmp );
+
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%d vertices to copy\n", nrverts);
+   
+
+   /* Finish the prim at this point:
+    */
+   note_last_prim( tnl, 0 );
+   flush_prims( tnl );
+
+   /* Reset counter, dmaptr
+    */
+   tnl->dmaptr = (int *)(tnl->dma.current.ptr + tnl->dma.current.address);
+   tnl->counter = (tnl->dma.current.end - tnl->dma.current.ptr) / 
+      (tnl->vertex_size * 4);
+   tnl->counter--;
+   tnl->initial_counter = tnl->counter;
+   tnl->notify = wrap_buffer;
+
+   tnl->dma.flush = flush_prims;
+   start_prim( tnl, tnl->prim[0] );
+
+
+   /* Reemit saved vertices 
+    * *** POSSIBLY IN NEW FORMAT
+    *       --> Can't always extend at end of vertex?
+    */
+   for (i = 0 ; i < nrverts; i++) {
+      if (MESA_VERBOSE & DEBUG_VERTS) {
+        int j;
+        fprintf(stderr, "re-emit vertex %d to %p\n", i, tnl->dmaptr);
+        if (MESA_VERBOSE & DEBUG_VERBOSE)
+           for (j = 0 ; j < tnl->vertex_size; j++) 
+              fprintf(stderr, "\t%08x/%f\n", *(int*)&tmp[i][j], tmp[i][j]);
+      }
+
+      memcpy( tnl->dmaptr, tmp[i], tnl->vertex_size * 4 );
+      tnl->dmaptr += tnl->vertex_size;
+      tnl->counter--;
+   }
+}
+
+
+
+/* Always follow data, don't try to predict what's necessary.  
+ */
+static GLboolean check_vtx_fmt( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+   if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) 
+      ctx->Driver.FlushVertices( ctx, FLUSH_UPDATE_CURRENT );
+   
+
+   TNL_NEWPRIM(tnl);
+   tnl->vertex_format = VERT_BIT_POS;
+   tnl->prim = &ctx->Driver.CurrentExecPrimitive;
+
+
+   /* Currently allow the full 4 components per attrib.  Can use the
+    * mechanism from radeon driver color handling to reduce this (and
+    * also to store ubyte colors where these are incoming).  This
+    * won't work for compile mode.
+    *
+    * Only adding components when they are first received eliminates
+    * the need for displaylist fixup, as there are no 'empty' slots
+    * at the start of buffers.  
+    */
+   for (i = 0 ; i < 16 ; i++) {
+      if (ind & (1<<i)) {
+        tnl->attribptr[i] = &tnl->vertex[tnl->vertex_size].f;
+        tnl->vertex_size += 4;
+        tnl->attribptr[i][0] = ctx->Current.Attrib[i][0];
+        tnl->attribptr[i][1] = ctx->Current.Attrib[i][1];
+        tnl->attribptr[i][2] = ctx->Current.Attrib[i][2];
+        tnl->attribptr[i][3] = ctx->Current.Attrib[i][3];
+      }
+      else
+        tnl->attribptr[i] = ctx->Current.Attrib[i];
+   }
+
+   /* Edgeflag, Index:
+    */
+   for (i = 16 ; i < 18 ; i++)
+      ;
+
+   /* Materials:
+    */
+   for (i = 18 ; i < 28 ; i++)
+      ;
+
+   /* Eval:
+    */
+   for (i = 28 ; i < 29 ; i++)
+      ;
+          
+
+   if (tnl->installed_vertex_format != tnl->vertex_format) {
+      if (MESA_VERBOSE & DEBUG_VFMT)
+        fprintf(stderr, "reinstall on vertex_format change\n");
+      _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
+      tnl->installed_vertex_format = tnl->vertex_format;
+   }
+
+   return GL_TRUE;
+}
+
+
+void _tnl_InvalidateVtxfmt( GLcontext *ctx )
+{
+   tnl->recheck = GL_TRUE;
+   tnl->fell_back = GL_FALSE;
+}
+
+
+
+
+static void _tnl_ValidateVtxfmt( GLcontext *ctx )
+{
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s\n", __FUNCTION__);
+
+   if (ctx->Driver.NeedFlush)
+      ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush );
+
+   tnl->recheck = GL_FALSE;
+
+   if (check_vtx_fmt( ctx )) {
+      if (!tnl->installed) {
+        if (MESA_VERBOSE & DEBUG_VFMT)
+           fprintf(stderr, "reinstall (new install)\n");
+
+        _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
+        ctx->Driver.FlushVertices = _tnl_FlushVertices;
+        tnl->installed = GL_TRUE;
+      }
+      else
+        fprintf(stderr, "%s: already installed", __FUNCTION__);
+   } 
+   else {
+      if (MESA_VERBOSE & DEBUG_VFMT)
+        fprintf(stderr, "%s: failed\n", __FUNCTION__);
+
+      if (tnl->installed) {
+        if (tnl->tnl->dma.flush)
+           tnl->tnl->dma.flush( tnl->tnl );
+        _tnl_wakeup_exec( ctx );
+        tnl->installed = GL_FALSE;
+      }
+   }      
+}
+
+
+
+
+
+/* Begin/End
+ */
+static void _tnl_Begin( GLenum mode )
+{
+   GLcontext *ctx = tnl->context;
+   TNLcontext *tnl = tnl->tnl;
+   
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s\n", __FUNCTION__);
+
+   if (mode > GL_POLYGON) {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
+      return;
+   }
+
+   if (tnl->prim[0] != GL_POLYGON+1) {
+      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+      return;
+   }
+   
+   if (ctx->NewState) 
+      _mesa_update_state( ctx );
+
+   if (tnl->recheck) 
+      _tnl_ValidateVtxfmt( ctx );
+
+   if (tnl->dma.flush && tnl->counter < 12) {
+      if (MESA_VERBOSE & DEBUG_VFMT)
+        fprintf(stderr, "%s: flush almost-empty buffers\n", __FUNCTION__);
+      flush_prims( tnl );
+   }
+
+   if (!tnl->dma.flush) {
+      if (tnl->dma.current.ptr + 12*tnl->vertex_size*4 > 
+         tnl->dma.current.end) {
+        TNL_NEWPRIM( tnl );
+        _tnl_RefillCurrentDmaRegion( tnl );
+      }
+
+      tnl->dmaptr = (int *)(tnl->dma.current.address + tnl->dma.current.ptr);
+      tnl->counter = (tnl->dma.current.end - tnl->dma.current.ptr) / 
+        (tnl->vertex_size * 4);
+      tnl->counter--;
+      tnl->initial_counter = tnl->counter;
+      tnl->notify = wrap_buffer;
+      tnl->dma.flush = flush_prims;
+      tnl->context->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+   }
+   
+   
+   tnl->prim[0] = mode;
+   start_prim( tnl, mode | PRIM_BEGIN );
+}
+
+
+
+
+
+static void _tnl_End( void )
+{
+   TNLcontext *tnl = tnl->tnl;
+   GLcontext *ctx = tnl->context;
+
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s\n", __FUNCTION__);
+
+   if (tnl->prim[0] == GL_POLYGON+1) {
+      _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+      return;
+   }
+         
+   note_last_prim( tnl, PRIM_END );
+   tnl->prim[0] = GL_POLYGON+1;
+}
+
+
+static void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
+{
+   if (MESA_VERBOSE & DEBUG_VFMT)
+      fprintf(stderr, "%s\n", __FUNCTION__);
+
+   assert(tnl->installed);
+
+   if (flags & FLUSH_UPDATE_CURRENT) {
+      _tnl_copy_to_current( ctx );
+      if (MESA_VERBOSE & DEBUG_VFMT)
+        fprintf(stderr, "reinstall on update_current\n");
+      _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
+      ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+   }
+
+   if (flags & FLUSH_STORED_VERTICES) {
+      TNLcontext *tnl = TNL_CONTEXT( ctx );
+      assert (tnl->dma.flush == 0 ||
+             tnl->dma.flush == flush_prims);
+      if (tnl->dma.flush == flush_prims)
+        flush_prims( TNL_CONTEXT( ctx ) );
+      ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
+   }
+}
+
+
+
+/* At this point, don't expect very many versions of each function to
+ * be generated, so not concerned about freeing them?
+ */
+
+
+static void _tnl_InitVtxfmt( GLcontext *ctx )
+{
+   GLvertexformat *vfmt = &(tnl->vtxfmt);
+
+   MEMSET( vfmt, 0, sizeof(GLvertexformat) );
+
+   /* Hook in chooser functions for codegen, etc:
+    */
+   _tnl_InitVtxfmtChoosers( vfmt );
+
+   /* Handled fully in supported states, but no codegen:
+    */
+   vfmt->ArrayElement = _ae_loopback_array_elt;                /* generic helper */
+   vfmt->Rectf = _mesa_noop_Rectf;                     /* generic helper */
+   vfmt->Begin = _tnl_Begin;
+   vfmt->End = _tnl_End;
+   
+   tnl->context = ctx;
+   tnl->tnl = TNL_CONTEXT(ctx);
+   tnl->prim = &ctx->Driver.CurrentExecPrimitive;
+   tnl->primflags = 0;
+
+   make_empty_list( &tnl->dfn_cache.Vertex2f );
+   make_empty_list( &tnl->dfn_cache.Vertex2fv );
+   make_empty_list( &tnl->dfn_cache.Vertex3f );
+   make_empty_list( &tnl->dfn_cache.Vertex3fv );
+   make_empty_list( &tnl->dfn_cache.Color4ub );
+   make_empty_list( &tnl->dfn_cache.Color4ubv );
+   make_empty_list( &tnl->dfn_cache.Color3ub );
+   make_empty_list( &tnl->dfn_cache.Color3ubv );
+   make_empty_list( &tnl->dfn_cache.Color4f );
+   make_empty_list( &tnl->dfn_cache.Color4fv );
+   make_empty_list( &tnl->dfn_cache.Color3f );
+   make_empty_list( &tnl->dfn_cache.Color3fv );
+   make_empty_list( &tnl->dfn_cache.SecondaryColor3fEXT );
+   make_empty_list( &tnl->dfn_cache.SecondaryColor3fvEXT );
+   make_empty_list( &tnl->dfn_cache.SecondaryColor3ubEXT );
+   make_empty_list( &tnl->dfn_cache.SecondaryColor3ubvEXT );
+   make_empty_list( &tnl->dfn_cache.Normal3f );
+   make_empty_list( &tnl->dfn_cache.Normal3fv );
+   make_empty_list( &tnl->dfn_cache.TexCoord2f );
+   make_empty_list( &tnl->dfn_cache.TexCoord2fv );
+   make_empty_list( &tnl->dfn_cache.TexCoord1f );
+   make_empty_list( &tnl->dfn_cache.TexCoord1fv );
+   make_empty_list( &tnl->dfn_cache.MultiTexCoord2fARB );
+   make_empty_list( &tnl->dfn_cache.MultiTexCoord2fvARB );
+   make_empty_list( &tnl->dfn_cache.MultiTexCoord1fARB );
+   make_empty_list( &tnl->dfn_cache.MultiTexCoord1fvARB );
+
+   _tnl_InitCodegen( &tnl->codegen );
+}
+
+static void free_funcs( struct dynfn *l )
+{
+   struct dynfn *f, *tmp;
+   foreach_s (f, tmp, l) {
+      remove_from_list( f );
+      ALIGN_FREE( f->code );
+      FREE( f );
+   }
+}
+
+
+static void _tnl_DestroyVtxfmt( GLcontext *ctx )
+{
+   count_funcs();
+   free_funcs( &tnl->dfn_cache.Vertex2f );
+   free_funcs( &tnl->dfn_cache.Vertex2fv );
+   free_funcs( &tnl->dfn_cache.Vertex3f );
+   free_funcs( &tnl->dfn_cache.Vertex3fv );
+   free_funcs( &tnl->dfn_cache.Color4ub );
+   free_funcs( &tnl->dfn_cache.Color4ubv );
+   free_funcs( &tnl->dfn_cache.Color3ub );
+   free_funcs( &tnl->dfn_cache.Color3ubv );
+   free_funcs( &tnl->dfn_cache.Color4f );
+   free_funcs( &tnl->dfn_cache.Color4fv );
+   free_funcs( &tnl->dfn_cache.Color3f );
+   free_funcs( &tnl->dfn_cache.Color3fv );
+   free_funcs( &tnl->dfn_cache.SecondaryColor3ubEXT );
+   free_funcs( &tnl->dfn_cache.SecondaryColor3ubvEXT );
+   free_funcs( &tnl->dfn_cache.SecondaryColor3fEXT );
+   free_funcs( &tnl->dfn_cache.SecondaryColor3fvEXT );
+   free_funcs( &tnl->dfn_cache.Normal3f );
+   free_funcs( &tnl->dfn_cache.Normal3fv );
+   free_funcs( &tnl->dfn_cache.TexCoord2f );
+   free_funcs( &tnl->dfn_cache.TexCoord2fv );
+   free_funcs( &tnl->dfn_cache.TexCoord1f );
+   free_funcs( &tnl->dfn_cache.TexCoord1fv );
+   free_funcs( &tnl->dfn_cache.MultiTexCoord2fARB );
+   free_funcs( &tnl->dfn_cache.MultiTexCoord2fvARB );
+   free_funcs( &tnl->dfn_cache.MultiTexCoord1fARB );
+   free_funcs( &tnl->dfn_cache.MultiTexCoord1fvARB );
+}
+
diff --git a/src/mesa/tnl/t_vtx_sse.c b/src/mesa/tnl/t_vtx_sse.c
new file mode 100644 (file)
index 0000000..240d6cf
--- /dev/null
@@ -0,0 +1,93 @@
+/* $XFree86$ */
+/**************************************************************************
+
+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 <stdio.h>
+#include <assert.h>
+#include "mem.h" 
+#include "simple_list.h" 
+#include "t_vtx_api.h"
+
+#if defined(USE_SSE_ASM)
+
+/* Build specialized versions of the immediate calls on the fly for
+ * the current state.  ???P4 SSE2 versions???
+ */
+
+
+static struct dynfn *makeSSENormal3fv( struct _vb *vb, int key )
+{
+   /* Requires P4 (sse2?)
+    */
+   static unsigned char temp[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /*  mov    0x4(%esp,1),%eax */
+      0xba, 0x78, 0x56, 0x34, 0x12,    /*  mov    $0x12345678,%edx */
+      0xf3, 0x0f, 0x7e, 0x00,                  /*  movq   (%eax),%xmm0 */
+      0x66, 0x0f, 0x6e, 0x48, 0x08,            /*  movd   0x8(%eax),%xmm1 */
+      0x66, 0x0f, 0xd6, 0x42, 0x0c,            /*  movq   %xmm0,0xc(%edx) */
+      0x66, 0x0f, 0x7e, 0x4a, 0x14,            /*  movd   %xmm1,0x14(%edx) */
+      0xc3,                            /*  ret     */
+   };
+
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+   insert_at_head( &vb->dfn_cache.Normal3fv, dfn );
+   dfn->key = key;
+
+   dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+   memcpy (dfn->code, temp, sizeof(temp));
+   FIXUP(dfn->code, 5, 0x0, (int)vb->normalptr); 
+   return dfn;
+}
+
+void _tnl_InitSSECodegen( struct dfn_generators *gen )
+{
+   /* Need to: 
+    *    - check kernel sse support
+    *    - check p4/sse2
+    */
+   (void) makeSSENormal3fv;
+}
+
+
+#else 
+
+void _tnl_InitSSECodegen( struct dfn_generators *gen )
+{
+   (void) gen;
+}
+
+#endif
+
+
+
+
diff --git a/src/mesa/tnl/t_vtx_x86.c b/src/mesa/tnl/t_vtx_x86.c
new file mode 100644 (file)
index 0000000..4713a32
--- /dev/null
@@ -0,0 +1,727 @@
+/* $XFree86$ */
+/**************************************************************************
+
+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 <stdio.h>
+#include <assert.h>
+#include "mem.h" 
+#include "mmath.h" 
+#include "simple_list.h" 
+#include "tnl_vtxfmt.h"
+
+#if defined(USE_X86_ASM)
+
+/* Build specialized versions of the immediate calls on the fly for
+ * the current state.  Generic x86 versions.
+ */
+
+struct dynfn *tnl_makeX86Vertex3f( TNLcontext *tnl, int key )
+{
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (RADEON_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   switch (tnl->vertex_size) {
+   case 4: {
+      static  char temp[] = {
+        0x8b, 0x0d, 0,0,0,0,           /* mov    DMAPTR,%ecx */
+        0x8b, 0x44, 0x24, 0x04,        /* mov    0x4(%esp,1),%eax */
+        0x8b, 0x54, 0x24, 0x08,        /* mov    0x8(%esp,1),%edx */
+        0x89, 0x01,                    /* mov    %eax,(%ecx) */
+        0x89, 0x51, 0x04,              /* mov    %edx,0x4(%ecx) */
+        0x8b, 0x44, 0x24, 0x0c,        /* mov    0xc(%esp,1),%eax */
+        0x8b, 0x15, 0,0,0,0,           /* mov    VERTEX[3],%edx */
+        0x89, 0x41, 0x08,              /* mov    %eax,0x8(%ecx) */
+        0x89, 0x51, 0x0c,              /* mov    %edx,0xc(%ecx) */
+        0xa1, 0, 0, 0, 0,              /* mov    COUNTER,%eax */
+        0x83, 0xc1, 0x10,              /* add    $0x10,%ecx */
+        0x48,                          /* dec    %eax */
+        0x89, 0x0d, 0,0,0,0,           /* mov    %ecx,DMAPTR */
+        0xa3, 0, 0, 0, 0,              /* mov    %eax,COUNTER */
+        0x74, 0x01,                    /* je     +1 */
+        0xc3,                          /* ret     */
+        0xff, 0x25, 0,0,0,0            /* jmp    *NOTIFY */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 2, 0x0, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 25, 0x0, (int)&tnl->vertex[3]);
+      FIXUP(dfn->code, 36, 0x0, (int)&tnl->counter);
+      FIXUP(dfn->code, 46, 0x0, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 51, 0x0, (int)&tnl->counter);
+      FIXUP(dfn->code, 60, 0x0, (int)&tnl->notify);
+      break;
+   }
+   case 6: {
+      static  char temp[] = {
+        0x57,                          /* push   %edi */
+        0x8b, 0x3d, 0, 0, 0, 0,        /* mov    DMAPTR,%edi */
+        0x8b, 0x44, 0x24, 0x8,         /* mov    0x8(%esp,1),%eax */
+        0x8b, 0x54, 0x24, 0xc,         /* mov    0xc(%esp,1),%edx */
+        0x8b, 0x4c, 0x24, 0x10,        /* mov    0x10(%esp,1),%ecx */
+        0x89, 0x07,                    /* mov    %eax,(%edi) */
+        0x89, 0x57, 0x04,              /* mov    %edx,0x4(%edi) */
+        0x89, 0x4f, 0x08,              /* mov    %ecx,0x8(%edi) */
+        0xa1, 0, 0, 0, 0,              /* mov    VERTEX[3],%eax */
+        0x8b, 0x15, 0, 0, 0, 0,        /* mov    VERTEX[4],%edx */
+        0x8b, 0x0d, 0, 0, 0, 0,        /* mov    VERTEX[5],%ecx */
+        0x89, 0x47, 0x0c,              /* mov    %eax,0xc(%edi) */
+        0x89, 0x57, 0x10,              /* mov    %edx,0x10(%edi) */
+        0x89, 0x4f, 0x14,              /* mov    %ecx,0x14(%edi) */
+        0x83, 0xc7, 0x18,              /* add    $0x18,%edi */
+        0xa1, 0, 0, 0, 0,              /* mov    COUNTER,%eax */
+        0x89, 0x3d, 0, 0, 0, 0,        /* mov    %edi,DMAPTR */
+        0x48,                          /* dec    %eax */
+        0x5f,                          /* pop    %edi */
+        0xa3, 0, 0, 0, 0,              /* mov    %eax,COUNTER */
+        0x74, 0x01,                    /* je     +1 */
+        0xc3,                          /* ret     */
+        0xff, 0x25, 0,0,0,0,           /* jmp    *NOTIFY */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 3, 0x0, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 28, 0x0, (int)&tnl->vertex[3]);
+      FIXUP(dfn->code, 34, 0x0, (int)&tnl->vertex[4]);
+      FIXUP(dfn->code, 40, 0x0, (int)&tnl->vertex[5]);
+      FIXUP(dfn->code, 57, 0x0, (int)&tnl->counter);
+      FIXUP(dfn->code, 63, 0x0, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 70, 0x0, (int)&tnl->counter);
+      FIXUP(dfn->code, 79, 0x0, (int)&tnl->notify);
+      break;
+   }
+   default: {
+      /* Repz convenient as it's possible to emit code for any size
+       * vertex with little tweaking.  Might as well read vertsize
+       * though, and have only one of these.
+       */
+      static  char temp[] = {
+        0x57,                          /* push   %edi */
+        0x56,                          /* push   %esi */
+        0xbe, 0, 0, 0, 0,              /* mov    $VERTEX+3,%esi */
+        0x8b, 0x3d, 0, 0, 0, 0,        /* mov    DMAPTR,%edi */
+        0x8b, 0x44, 0x24, 0x0c,        /* mov    0x0c(%esp,1),%eax */
+        0x8b, 0x54, 0x24, 0x10,        /* mov    0x10(%esp,1),%edx */
+        0x8b, 0x4c, 0x24, 0x14,        /* mov    0x14(%esp,1),%ecx */
+        0x89, 0x07,                    /* mov    %eax,(%edi) */
+        0x89, 0x57, 0x04,              /* mov    %edx,0x4(%edi) */
+        0x89, 0x4f, 0x08,              /* mov    %ecx,0x8(%edi) */
+        0x83, 0xc7, 0x0c,              /* add    $0xc,%edi */
+        0xb9, 0, 0, 0, 0,              /* mov    $VERTSIZE-3,%ecx */
+        0xf3, 0xa5,                    /* repz movsl %ds:(%esi),%es:(%edi)*/
+        0xa1, 0, 0, 0, 0,              /* mov    COUNTER,%eax */
+        0x89, 0x3d, 0, 0, 0, 0,        /* mov    %edi,DMAPTR */
+        0x48,                          /* dec    %eax */
+        0xa3, 0, 0, 0, 0,              /* mov    %eax,COUNTER */
+        0x5e,                          /* pop    %esi */
+        0x5f,                          /* pop    %edi */
+        0x74, 0x01,                    /* je     +1 */
+        0xc3,                          /* ret     */
+        0xff, 0x25, 0, 0, 0, 0         /* jmp    NOTIFY */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 3, 0x0, (int)&tnl->vertex[3]);
+      FIXUP(dfn->code, 9, 0x0, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 37, 0x0, tnl->vertex_size-3);
+      FIXUP(dfn->code, 44, 0x0, (int)&tnl->counter);
+      FIXUP(dfn->code, 50, 0x0, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 56, 0x0, (int)&tnl->counter);
+      FIXUP(dfn->code, 67, 0x0, (int)&tnl->notify);
+   break;
+   }
+   }
+
+   insert_at_head( &tnl->dfn_cache.Vertex3f, dfn );
+   dfn->key = key;
+   return dfn;
+}
+
+
+
+struct dynfn *tnl_makeX86Vertex3fv( TNLcontext *tnl, int key )
+{
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   switch (tnl->vertex_size) {
+   case 6: {
+      static  char temp[] = {
+        0xa1, 0x00, 0x00, 0, 0,        /* mov    0x0,%eax */
+        0x8b, 0x4c, 0x24, 0x04,        /* mov    0x4(%esp,1),%ecx */
+        0x8b, 0x11,                    /* mov    (%ecx),%edx */
+        0x89, 0x10,                    /* mov    %edx,(%eax) */
+        0x8b, 0x51, 0x04,              /* mov    0x4(%ecx),%edx */
+        0x8b, 0x49, 0x08,              /* mov    0x8(%ecx),%ecx */
+        0x89, 0x50, 0x04,              /* mov    %edx,0x4(%eax) */
+        0x89, 0x48, 0x08,              /* mov    %ecx,0x8(%eax) */
+        0x8b, 0x15, 0x1c, 0, 0, 0,     /* mov    0x1c,%edx */
+        0x8b, 0x0d, 0x20, 0, 0, 0,     /* mov    0x20,%ecx */
+        0x89, 0x50, 0x0c,              /* mov    %edx,0xc(%eax) */
+        0x89, 0x48, 0x10,              /* mov    %ecx,0x10(%eax) */
+        0x8b, 0x15, 0x24, 0, 0, 0,     /* mov    0x24,%edx */
+        0x89, 0x50, 0x14,              /* mov    %edx,0x14(%eax) */
+        0x83, 0xc0, 0x18,              /* add    $0x18,%eax */
+        0xa3, 0x00, 0x00, 0, 0,        /* mov    %eax,0x0 */
+        0xa1, 0x04, 0x00, 0, 0,        /* mov    0x4,%eax */
+        0x48,                          /* dec    %eax */
+        0xa3, 0x04, 0x00, 0, 0,        /* mov    %eax,0x4 */
+        0x74, 0x01,                    /* je     2a4 <.f11> */
+        0xc3,                          /* ret     */
+        0xff, 0x25, 0x08, 0, 0, 0,     /* jmp    *0x8 */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 1, 0x00000000, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 27, 0x0000001c, (int)&tnl->vertex[3]);
+      FIXUP(dfn->code, 33, 0x00000020, (int)&tnl->vertex[4]);
+      FIXUP(dfn->code, 45, 0x00000024, (int)&tnl->vertex[5]);
+      FIXUP(dfn->code, 56, 0x00000000, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 61, 0x00000004, (int)&tnl->counter);
+      FIXUP(dfn->code, 67, 0x00000004, (int)&tnl->counter);
+      FIXUP(dfn->code, 76, 0x00000008, (int)&tnl->notify);
+      break;
+   }
+   
+
+   case 8: {
+      static  char temp[] = {
+        0xa1, 0x00, 0x00, 0, 0,        /* mov    0x0,%eax */
+        0x8b, 0x4c, 0x24, 0x04,        /* mov    0x4(%esp,1),%ecx */
+        0x8b, 0x11,                    /* mov    (%ecx),%edx */
+        0x89, 0x10,                    /* mov    %edx,(%eax) */
+        0x8b, 0x51, 0x04,              /* mov    0x4(%ecx),%edx */
+        0x8b, 0x49, 0x08,              /* mov    0x8(%ecx),%ecx */
+        0x89, 0x50, 0x04,              /* mov    %edx,0x4(%eax) */
+        0x89, 0x48, 0x08,              /* mov    %ecx,0x8(%eax) */
+        0x8b, 0x15, 0x1c, 0, 0, 0,     /* mov    0x1c,%edx */
+        0x8b, 0x0d, 0x20, 0, 0, 0,     /* mov    0x20,%ecx */
+        0x89, 0x50, 0x0c,              /* mov    %edx,0xc(%eax) */
+        0x89, 0x48, 0x10,              /* mov    %ecx,0x10(%eax) */
+        0x8b, 0x15, 0x1c, 0, 0, 0,     /* mov    0x1c,%edx */
+        0x8b, 0x0d, 0x20, 0, 0, 0,     /* mov    0x20,%ecx */
+        0x89, 0x50, 0x14,              /* mov    %edx,0x14(%eax) */
+        0x89, 0x48, 0x18,              /* mov    %ecx,0x18(%eax) */
+        0x8b, 0x15, 0x24, 0, 0, 0,     /* mov    0x24,%edx */
+        0x89, 0x50, 0x1c,              /* mov    %edx,0x1c(%eax) */
+        0x83, 0xc0, 0x20,              /* add    $0x20,%eax */
+        0xa3, 0x00, 0x00, 0, 0,        /* mov    %eax,0x0 */
+        0xa1, 0x04, 0x00, 0, 0,        /* mov    0x4,%eax */
+        0x48,                          /* dec    %eax */
+        0xa3, 0x04, 0x00, 0, 0,        /* mov    %eax,0x4 */
+        0x74, 0x01,                    /* je     2a4 <.f11> */
+        0xc3,                          /* ret     */
+        0xff, 0x25, 0x08, 0, 0, 0,     /* jmp    *0x8 */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 1, 0x00000000, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 27, 0x0000001c, (int)&tnl->vertex[3]);
+      FIXUP(dfn->code, 33, 0x00000020, (int)&tnl->vertex[4]);
+      FIXUP(dfn->code, 45, 0x0000001c, (int)&tnl->vertex[5]);
+      FIXUP(dfn->code, 51, 0x00000020, (int)&tnl->vertex[6]);
+      FIXUP(dfn->code, 63, 0x00000024, (int)&tnl->vertex[7]);
+      FIXUP(dfn->code, 74, 0x00000000, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 79, 0x00000004, (int)&tnl->counter);
+      FIXUP(dfn->code, 85, 0x00000004, (int)&tnl->counter);
+      FIXUP(dfn->code, 94, 0x00000008, (int)&tnl->notify);
+      break;
+   }
+   
+
+
+   default: {
+      /* Repz convenient as it's possible to emit code for any size
+       * vertex with little tweaking.  Might as well read vertsize
+       * though, and have only one of these.
+       */
+      static  char temp[] = {
+        0x8b, 0x54, 0x24, 0x04,        /* mov    0x4(%esp,1),%edx */
+        0x57,                          /* push   %edi */
+        0x56,                          /* push   %esi */
+        0x8b, 0x3d, 1,1,1,1,           /* mov    DMAPTR,%edi */
+        0x8b, 0x02,                    /* mov    (%edx),%eax */
+        0x8b, 0x4a, 0x04,              /* mov    0x4(%edx),%ecx */
+        0x8b, 0x72, 0x08,              /* mov    0x8(%edx),%esi */
+        0x89, 0x07,                    /* mov    %eax,(%edi) */
+        0x89, 0x4f, 0x04,              /* mov    %ecx,0x4(%edi) */
+        0x89, 0x77, 0x08,              /* mov    %esi,0x8(%edi) */
+        0x83, 0xc7, 0x0c,              /* add    $0xc,%edi */
+        0xb9, 0x06, 0x00, 0x00, 0x00,  /* mov    $VERTSIZE-3,%ecx */
+        0xbe, 0x58, 0x00, 0x00, 0x00,  /* mov    $VERTEX[3],%esi */
+        0xf3, 0xa5,                    /* repz movsl %ds:(%esi),%es:(%edi)*/
+        0x89, 0x3d, 1, 1, 1, 1,        /* mov    %edi,DMAPTR */
+        0xa1, 2, 2, 2, 2,              /* mov    COUNTER,%eax */
+        0x5e,                          /* pop    %esi */
+        0x5f,                          /* pop    %edi */
+        0x48,                          /* dec    %eax */
+        0xa3, 2, 2, 2, 2,              /* mov    %eax,COUNTER */
+        0x74, 0x01,                    /* je     +1 */
+        0xc3,                          /* ret     */
+        0xff, 0x25, 0, 0, 0, 0         /* jmp    NOTIFY */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 8, 0x01010101, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 32, 0x00000006, tnl->vertex_size-3);
+      FIXUP(dfn->code, 37, 0x00000058, (int)&tnl->vertex[3]);
+      FIXUP(dfn->code, 45, 0x01010101, (int)&tnl->dmaptr);
+      FIXUP(dfn->code, 50, 0x02020202, (int)&tnl->counter);
+      FIXUP(dfn->code, 58, 0x02020202, (int)&tnl->counter);
+      FIXUP(dfn->code, 67, 0x0, (int)&tnl->notify);
+   break;
+   }
+   }
+
+   insert_at_head( &tnl->dfn_cache.Vertex3fv, dfn );
+   dfn->key = key;
+   return dfn;
+}
+
+
+struct dynfn *tnl_makeX86Normal3fv( TNLcontext *tnl, int key )
+{
+   static  char temp[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0xba, 0, 0, 0, 0,                /* mov    $DEST,%edx */
+      0x8b, 0x08,                      /* mov    (%eax),%ecx */
+      0x89, 0x0a,                      /* mov    %ecx,(%edx) */
+      0x8b, 0x48, 0x04,                /* mov    0x4(%eax),%ecx */
+      0x89, 0x4a, 0x04,                /* mov    %ecx,0x4(%edx) */
+      0x8b, 0x48, 0x08,                /* mov    0x8(%eax),%ecx */
+      0x89, 0x4a, 0x08,                /* mov    %ecx,0x8(%edx) */
+      0xc3,                            /* ret    */
+   };
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   insert_at_head( &tnl->dfn_cache.Normal3fv, dfn );
+   dfn->key = key;
+   dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+   memcpy (dfn->code, temp, sizeof(temp));
+   FIXUP(dfn->code, 5, 0x0, (int)tnl->normalptr); 
+   return dfn;
+}
+
+struct dynfn *tnl_makeX86Normal3f( TNLcontext *tnl, int key )
+{
+   static  char temp[] = {
+      0xba, 0x78, 0x56, 0x34, 0x12,            /*  mov    $DEST,%edx */
+      0x8b, 0x44, 0x24, 0x04,                  /*  mov    0x4(%esp,1),%eax */
+      0x89, 0x02,                      /*  mov    %eax,(%edx) */
+      0x8b, 0x44, 0x24, 0x08,                  /*  mov    0x8(%esp,1),%eax */
+      0x89, 0x42, 0x04,                /*  mov    %eax,0x4(%edx) */
+      0x8b, 0x44, 0x24, 0x0c,                  /*  mov    0xc(%esp,1),%eax */
+      0x89, 0x42, 0x08,                /*  mov    %eax,0x8(%edx) */
+      0xc3,                            /*  ret     */
+   };
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   insert_at_head( &tnl->dfn_cache.Normal3f, dfn );
+   dfn->key = key;
+   dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+   memcpy (dfn->code, temp, sizeof(temp));
+   FIXUP(dfn->code, 1, 0x12345678, (int)tnl->normalptr); 
+   return dfn;
+}
+
+struct dynfn *tnl_makeX86Color4ubv( TNLcontext *tnl, int key )
+{
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+   insert_at_head( &tnl->dfn_cache.Color4ubv, dfn );
+   dfn->key = key;
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   if (key & TNL_CP_VC_FRMT_PKCOLOR) {
+      static  char temp[] = {
+        0x8b, 0x44, 0x24, 0x04,        /*  mov    0x4(%esp,1),%eax */
+        0xba, 0x78, 0x56, 0x34, 0x12,  /*  mov    $DEST,%edx */
+        0x8b, 0x00,                    /*  mov    (%eax),%eax */
+        0x89, 0x02,                    /*  mov    %eax,(%edx) */
+        0xc3,                          /*  ret     */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 5, 0x12345678, (int)tnl->ubytecolorptr); 
+      return dfn;
+   } 
+   else {
+      static  char temp[] = {
+        0x53,                                  /* push   %ebx */
+        0xba, 0x00, 0x00, 0x00, 0x00,          /* mov    $0x0,%edx */
+        0x31, 0xc0,                            /* xor    %eax,%eax */
+        0x31, 0xc9,                            /* xor    %ecx,%ecx */
+        0x8b, 0x5c, 0x24, 0x08,                /* mov    0x8(%esp,1), %ebx */
+        0x8b, 0x1b,                            /* mov    (%ebx), %ebx */
+        0x88, 0xd8,                            /* mov    %bl, %al */
+        0x88, 0xf9,                            /* mov    %bh, %cl */
+        0x8b, 0x04, 0x82,                      /* mov    (%edx,%eax,4),%eax */
+        0x8b, 0x0c, 0x8a,                      /* mov    (%edx,%ecx,4),%ecx */
+        0xa3, 0xaf, 0xbe, 0xad, 0xde,          /* mov    %eax,0xdeadbeaf */
+        0x89, 0x0d, 0xaf, 0xbe, 0xad, 0xde,    /* mov    %ecx,0xdeadbeaf */
+        0x31, 0xc0,                            /* xor    %eax,%eax */
+        0x31, 0xc9,                            /* xor    %ecx,%ecx */
+        0xc1, 0xeb, 0x10,                      /* shr    $0x10, %ebx */
+        0x88, 0xd8,                            /* mov    %bl, %al */
+        0x88, 0xf9,                            /* mov    %bh, %cl */
+        0x8b, 0x04, 0x82,                      /* mov    (%edx,%eax,4),%eax */
+        0x8b, 0x0c, 0x8a,                      /* mov    (%edx,%ecx,4),%ecx */
+        0xa3, 0xaf, 0xbe, 0xad, 0xde,          /* mov    %eax,0xdeadbeaf */
+        0x89, 0x0d, 0xaf, 0xbe, 0xad, 0xde,    /* mov    %ecx,0xdeadbeaf */
+        0x5b,                                  /* pop    %ebx */
+        0xc3,                                  /* ret     */
+      };
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 2, 0x00000000, (int)_mesa_ubyte_to_float_color_tab); 
+      FIXUP(dfn->code, 27, 0xdeadbeaf, (int)tnl->floatcolorptr); 
+      FIXUP(dfn->code, 33, 0xdeadbeaf, (int)tnl->floatcolorptr+4); 
+      FIXUP(dfn->code, 55, 0xdeadbeaf, (int)tnl->floatcolorptr+8); 
+      FIXUP(dfn->code, 61, 0xdeadbeaf, (int)tnl->floatcolorptr+12); 
+      return dfn;
+   }
+}
+
+struct dynfn *tnl_makeX86Color4ub( TNLcontext *tnl, int key )
+{
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   if (key & TNL_CP_VC_FRMT_PKCOLOR) {
+      /* XXX push/pop */
+      static  char temp[] = {
+        0x53,                          /* push   %ebx */
+        0x8b, 0x44, 0x24, 0x08,                /* mov    0x8(%esp,1),%eax */
+        0x8b, 0x54, 0x24, 0x0c,                /* mov    0xc(%esp,1),%edx */
+        0x8b, 0x4c, 0x24, 0x10,                /* mov    0x10(%esp,1),%ecx */
+        0x8b, 0x5c, 0x24, 0x14,                /* mov    0x14(%esp,1),%ebx */
+        0xa2, 0, 0, 0, 0,              /* mov    %al,DEST */
+        0x88, 0x15, 0, 0, 0, 0,        /* mov    %dl,DEST+1 */
+        0x88, 0x0d, 0, 0, 0, 0,        /* mov    %cl,DEST+2 */
+        0x88, 0x1d, 0, 0, 0, 0,        /* mov    %bl,DEST+3 */
+        0x5b,                          /* pop    %ebx */
+        0xc3,                          /* ret     */
+      };
+
+      struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+      insert_at_head( &tnl->dfn_cache.Color4ub, dfn );
+      dfn->key = key;
+
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 18, 0x0, (int)tnl->ubytecolorptr); 
+      FIXUP(dfn->code, 24, 0x0, (int)tnl->ubytecolorptr+1); 
+      FIXUP(dfn->code, 30, 0x0, (int)tnl->ubytecolorptr+2); 
+      FIXUP(dfn->code, 36, 0x0, (int)tnl->ubytecolorptr+3); 
+      return dfn;
+   }
+   else
+      return 0;
+}
+
+
+struct dynfn *tnl_makeX86Color3fv( TNLcontext *tnl, int key )
+{
+   if (key & (TNL_CP_VC_FRMT_PKCOLOR|TNL_CP_VC_FRMT_FPALPHA))
+      return 0;
+   else
+   {
+      static  char temp[] = {
+        0x8b, 0x44, 0x24, 0x04,                /* mov    0x4(%esp,1),%eax */
+        0xba, 0, 0, 0, 0,              /* mov    $DEST,%edx */
+        0x8b, 0x08,                    /* mov    (%eax),%ecx */
+        0x89, 0x0a,                    /* mov    %ecx,(%edx) */
+        0x8b, 0x48, 0x04,              /* mov    0x4(%eax),%ecx */
+        0x89, 0x4a, 0x04,              /* mov    %ecx,0x4(%edx) */
+        0x8b, 0x48, 0x08,              /* mov    0x8(%eax),%ecx */
+        0x89, 0x4a, 0x08,              /* mov    %ecx,0x8(%edx) */
+        0xc3,                          /* ret    */
+      };
+
+      struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+      if (TNL_DEBUG & DEBUG_CODEGEN)
+        fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+      insert_at_head( &tnl->dfn_cache.Color3fv, dfn );
+      dfn->key = key;
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 5, 0x0, (int)tnl->floatcolorptr); 
+      return dfn;
+   }
+}
+
+struct dynfn *tnl_makeX86Color3f( TNLcontext *tnl, int key )
+{
+   if (key & (TNL_CP_VC_FRMT_PKCOLOR|TNL_CP_VC_FRMT_FPALPHA))
+      return 0;
+   else
+   {
+      static  char temp[] = {
+        0xba, 0x78, 0x56, 0x34, 0x12,          /*  mov    $DEST,%edx */
+        0x8b, 0x44, 0x24, 0x04,                /*  mov    0x4(%esp,1),%eax */
+        0x89, 0x02,                    /*  mov    %eax,(%edx) */
+        0x8b, 0x44, 0x24, 0x08,                /*  mov    0x8(%esp,1),%eax */
+        0x89, 0x42, 0x04,              /*  mov    %eax,0x4(%edx) */
+        0x8b, 0x44, 0x24, 0x0c,                /*  mov    0xc(%esp,1),%eax */
+        0x89, 0x42, 0x08,              /*  mov    %eax,0x8(%edx) */
+        0xc3,                          /*  ret     */
+      };
+
+      struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+      if (TNL_DEBUG & DEBUG_CODEGEN)
+        fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+      insert_at_head( &tnl->dfn_cache.Color3f, dfn );
+      dfn->key = key;
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 1, 0x12345678, (int)tnl->floatcolorptr); 
+      return dfn;
+   }
+}
+
+
+
+struct dynfn *tnl_makeX86TexCoord2fv( TNLcontext *tnl, int key )
+{
+   static  char temp[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0xba, 0x78, 0x56, 0x34, 0x12,     /* mov    $DEST,%edx */
+      0x8b, 0x08,                      /* mov    (%eax),%ecx */
+      0x8b, 0x40, 0x04,                /* mov    0x4(%eax),%eax */
+      0x89, 0x0a,                      /* mov    %ecx,(%edx) */
+      0x89, 0x42, 0x04,                /* mov    %eax,0x4(%edx) */
+      0xc3,                            /* ret     */
+   };
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   insert_at_head( &tnl->dfn_cache.TexCoord2fv, dfn );
+   dfn->key = key;
+   dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+   memcpy (dfn->code, temp, sizeof(temp));
+   FIXUP(dfn->code, 5, 0x12345678, (int)tnl->texcoordptr[0]); 
+   return dfn;
+}
+
+struct dynfn *tnl_makeX86TexCoord2f( TNLcontext *tnl, int key )
+{
+   static  char temp[] = {
+      0xba, 0x78, 0x56, 0x34, 0x12,            /* mov    $DEST,%edx */
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0x8b, 0x4c, 0x24, 0x08,                  /* mov    0x8(%esp,1),%ecx */
+      0x89, 0x02,                      /* mov    %eax,(%edx) */
+      0x89, 0x4a, 0x04,                /* mov    %ecx,0x4(%edx) */
+      0xc3,                            /* ret     */
+   };
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   insert_at_head( &tnl->dfn_cache.TexCoord2f, dfn );
+   dfn->key = key;
+   dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+   memcpy (dfn->code, temp, sizeof(temp));
+   FIXUP(dfn->code, 1, 0x12345678, (int)tnl->texcoordptr[0]); 
+   return dfn;
+}
+
+struct dynfn *tnl_makeX86MultiTexCoord2fvARB( TNLcontext *tnl, int key )
+{
+   static  char temp[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0x8b, 0x4c, 0x24, 0x08,                  /* mov    0x8(%esp,1),%ecx */
+      0x2d, 0xc0, 0x84, 0x00, 0x00,            /* sub    $0x84c0,%eax */
+      0x83, 0xe0, 0x01,                /* and    $0x1,%eax */
+      0x8b, 0x11,                      /* mov    (%ecx),%edx */
+      0xc1, 0xe0, 0x03,                /* shl    $0x3,%eax */
+      0x8b, 0x49, 0x04,                /* mov    0x4(%ecx),%ecx */
+      0x89, 0x90, 0, 0, 0, 0,/* mov    %edx,DEST(%eax) */
+      0x89, 0x88, 0, 0, 0, 0,/* mov    %ecx,DEST+8(%eax) */
+      0xc3,                            /* ret     */
+   };
+
+   static char temp2[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0x8b, 0x4c, 0x24, 0x08,                  /* mov    0x8(%esp,1),%ecx */
+      0x2d, 0xc0, 0x84, 0x00, 0x00,            /* sub    $0x84c0,%eax */
+      0x83, 0xe0, 0x01,                /* and    $0x1,%eax */
+      0x8b, 0x14, 0x85, 0, 0, 0, 0, /* mov    DEST(,%eax,4),%edx */
+      0x8b, 0x01,                      /* mov    (%ecx),%eax */
+      0x89, 0x02,                      /* mov    %eax,(%edx) */
+      0x8b, 0x41, 0x04,                /* mov    0x4(%ecx),%eax */
+      0x89, 0x42, 0x04,                /* mov    %eax,0x4(%edx) */
+      0xc3,                            /* ret     */
+   };
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   insert_at_head( &tnl->dfn_cache.MultiTexCoord2fvARB, dfn );
+   dfn->key = key;
+
+   if ((key & (TNL_CP_VC_FRMT_ST0|TNL_CP_VC_FRMT_ST1)) ==
+      (TNL_CP_VC_FRMT_ST0|TNL_CP_VC_FRMT_ST1)) {
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 26, 0x0, (int)tnl->texcoordptr[0]);     
+      FIXUP(dfn->code, 32, 0x0, (int)tnl->texcoordptr[0]+4);
+   } else {
+      dfn->code = ALIGN_MALLOC( sizeof(temp2), 16 );
+      memcpy (dfn->code, temp2, sizeof(temp2));
+      FIXUP(dfn->code, 19, 0x0, (int)tnl->texcoordptr);
+   }
+   return dfn;
+}
+
+struct dynfn *tnl_makeX86MultiTexCoord2fARB( TNLcontext *tnl, 
+                                               int key )
+{
+   static  char temp[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0x8b, 0x54, 0x24, 0x08,                  /* mov    0x8(%esp,1),%edx */
+      0x2d, 0xc0, 0x84, 0x00, 0x00,            /* sub    $0x84c0,%eax */
+      0x8b, 0x4c, 0x24, 0x0c,                  /* mov    0xc(%esp,1),%ecx */
+      0x83, 0xe0, 0x01,                /* and    $0x1,%eax */
+      0xc1, 0xe0, 0x03,                /* shl    $0x3,%eax */
+      0x89, 0x90, 0, 0, 0, 0,  /* mov    %edx,DEST(%eax) */
+      0x89, 0x88, 0, 0, 0, 0,  /* mov    %ecx,DEST+8(%eax) */
+      0xc3,                            /* ret     */
+   };
+
+   static char temp2[] = {
+      0x8b, 0x44, 0x24, 0x04,                  /* mov    0x4(%esp,1),%eax */
+      0x8b, 0x54, 0x24, 0x08,                  /* mov    0x8(%esp,1),%edx */
+      0x2d, 0xc0, 0x84, 0x00, 0x00,            /* sub    $0x84c0,%eax */
+      0x8b, 0x4c, 0x24, 0x0c,                  /* mov    0xc(%esp,1),%ecx */
+      0x83, 0xe0, 0x01,                /* and    $0x1,%eax */
+      0x8b, 0x04, 0x85, 0, 0, 0, 0,     /* mov    DEST(,%eax,4),%eax */
+      0x89, 0x10,                      /* mov    %edx,(%eax) */
+      0x89, 0x48, 0x04,                /* mov    %ecx,0x4(%eax) */
+      0xc3,                            /* ret     */
+   };
+
+   struct dynfn *dfn = MALLOC_STRUCT( dynfn );
+
+   if (TNL_DEBUG & DEBUG_CODEGEN)
+      fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key );
+
+   insert_at_head( &tnl->dfn_cache.MultiTexCoord2fARB, dfn );
+   dfn->key = key;
+
+   if ((key & (TNL_CP_VC_FRMT_ST0|TNL_CP_VC_FRMT_ST1)) ==
+       (TNL_CP_VC_FRMT_ST0|TNL_CP_VC_FRMT_ST1)) {
+      dfn->code = ALIGN_MALLOC( sizeof(temp), 16 );
+      memcpy (dfn->code, temp, sizeof(temp));
+      FIXUP(dfn->code, 25, 0x0, (int)tnl->texcoordptr[0]); 
+      FIXUP(dfn->code, 31, 0x0, (int)tnl->texcoordptr[0]+4); 
+   }
+   else {
+      /* Note: this might get generated multiple times, even though the
+       * actual emitted code is the same.
+       */
+      dfn->code = ALIGN_MALLOC( sizeof(temp2), 16 );
+      memcpy (dfn->code, temp2, sizeof(temp2));
+      FIXUP(dfn->code, 23, 0x0, (int)tnl->texcoordptr); 
+   }      
+   return dfn;
+}
+
+
+void _tnl_InitX86Codegen( struct dfn_generators *gen )
+{
+   gen->Vertex3f = tnl_makeX86Vertex3f;
+   gen->Vertex3fv = tnl_makeX86Vertex3fv;
+   gen->Color4ub = tnl_makeX86Color4ub; /* PKCOLOR only */
+   gen->Color4ubv = tnl_makeX86Color4ubv; /* PKCOLOR only */
+   gen->Normal3f = tnl_makeX86Normal3f;
+   gen->Normal3fv = tnl_makeX86Normal3fv;
+   gen->TexCoord2f = tnl_makeX86TexCoord2f;
+   gen->TexCoord2fv = tnl_makeX86TexCoord2fv;
+   gen->MultiTexCoord2fARB = tnl_makeX86MultiTexCoord2fARB;
+   gen->MultiTexCoord2fvARB = tnl_makeX86MultiTexCoord2fvARB;
+   gen->Color3f = tnl_makeX86Color3f;
+   gen->Color3fv = tnl_makeX86Color3fv;
+
+   /* Not done:
+    */
+/*     gen->Vertex2f = tnl_makeX86Vertex2f; */
+/*     gen->Vertex2fv = tnl_makeX86Vertex2fv; */
+/*     gen->Color3ub = tnl_makeX86Color3ub; */
+/*     gen->Color3ubv = tnl_makeX86Color3ubv; */
+/*     gen->Color4f = tnl_makeX86Color4f; */
+/*     gen->Color4fv = tnl_makeX86Color4fv; */
+/*     gen->TexCoord1f = tnl_makeX86TexCoord1f; */
+/*     gen->TexCoord1fv = tnl_makeX86TexCoord1fv; */
+/*     gen->MultiTexCoord1fARB = tnl_makeX86MultiTexCoord1fARB; */
+/*     gen->MultiTexCoord1fvARB = tnl_makeX86MultiTexCoord1fvARB; */
+}
+
+
+#else 
+
+void _tnl_InitX86Codegen( struct dfn_generators *gen )
+{
+   (void) gen;
+}
+
+#endif