draw: initialize headers in the none post paths as well
[mesa.git] / src / mesa / tnl / t_vertex.c
index 61ac08efc4dac02a7761e8c5ba1fbef23cd34db7..c1b1570232a6fc6ae8bf27a738b0630fa0750581 100644 (file)
  *    Keith Whitwell <keithw@tungstengraphics.com>
  */
 
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/colormac.h"
 
+#include "t_context.h"
+#include "t_vertex.h"
 
+#define DBG 0
 
+/* Build and manage clipspace/ndc/window vertices.
+ */
 
-
-struct attr {
-   int attrib;
-   int vertoffset;
-   int vertattrsize;
-   int *inputptr;
-   int inputstride;
-   void (*insert)( const struct attr *a, char *v, const GLfloat *input );
-   void (*extract)( const struct attr *a, GLfloat *output, const char *v );
-   const GLfloat *vp;
-};
-
-
-static void insert_4f_viewport( const struct attr *a, char *v,
-                               const GLfloat *in )
-{
-   GLfloat *out = (GLfloat *)v;
-   const GLfloat * const vp = a->vp;
-   
-   out[0] = vp[0] * in[0] + vp[12];
-   out[1] = vp[5] * in[1] + vp[13];
-   out[2] = vp[10] * in[2] + vp[14];
-   out[3] = in[3];
-}
-
-static void insert_3f_viewport( const struct attr *a, char *v,
-                               const GLfloat *in )
+static GLboolean match_fastpath( struct tnl_clipspace *vtx,
+                                const struct tnl_clipspace_fastpath *fp)
 {
-   GLfloat *out = (GLfloat *)v;
-   const GLfloat * const vp = a->vp;
-   
-   out[0] = vp[0] * in[0] + vp[12];
-   out[1] = vp[5] * in[1] + vp[13];
-   out[2] = vp[10] * in[2] + vp[14];
-}
+   GLuint j;
 
-static void insert_2f_viewport( const struct attr *a, char *v,
-                               const GLfloat *in )
-{
-   GLfloat *out = (GLfloat *)v;
-   const GLfloat * const vp = a->vp;
-   
-   out[0] = vp[0] * in[0] + vp[12];
-   out[1] = vp[5] * in[1] + vp[13];
-}
+   if (vtx->attr_count != fp->attr_count) 
+      return GL_FALSE;
 
+   for (j = 0; j < vtx->attr_count; j++) 
+      if (vtx->attr[j].format != fp->attr[j].format ||
+         vtx->attr[j].inputsize != fp->attr[j].size ||
+         vtx->attr[j].vertoffset != fp->attr[j].offset) 
+        return GL_FALSE;
+      
+   if (fp->match_strides) {
+      if (vtx->vertex_size != fp->vertex_size)
+        return GL_FALSE;
 
-static void insert_4f( const struct attr *a, char *v, const GLfloat *in )
-{
-   GLfloat *out = (GLfloat *)(v);
-   
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = in[2];
-   out[3] = in[3];
-}
-
-static void insert_3f_xyw( const struct attr *a, char *v, const GLfloat *in )
-{
-   GLfloat *out = (GLfloat *)(v);
+      for (j = 0; j < vtx->attr_count; j++) 
+        if (vtx->attr[j].inputstride != fp->attr[j].stride) 
+           return GL_FALSE;
+   }
    
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = in[3];
+   return GL_TRUE;
 }
 
-
-static void insert_3f( const struct attr *a, char *v, const GLfloat *in )
+static GLboolean search_fastpath_emit( struct tnl_clipspace *vtx )
 {
-   GLfloat *out = (GLfloat *)(v);
-   
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = in[2];
-}
-
+   struct tnl_clipspace_fastpath *fp = vtx->fastpath;
 
-static void insert_2f( const struct attr *a, char *v, const GLfloat *in )
-{
-   GLfloat *out = (GLfloat *)(v);
-   
-   out[0] = in[0];
-   out[1] = in[1];
-}
+   for ( ; fp ; fp = fp->next) {
+      if (match_fastpath(vtx, fp)) {
+         vtx->emit = fp->func;
+        return GL_TRUE;
+      }
+   }
 
-static void insert_1f( const struct attr *a, char *v, const GLfloat *in )
-{
-   GLfloat *out = (GLfloat *)(v);
-   
-   out[0] = in[0];
+   return GL_FALSE;
 }
 
-static void insert_4ub_4f_rgba( const struct attr *a, char *v, 
-                               const GLfloat *in )
+void _tnl_register_fastpath( struct tnl_clipspace *vtx,
+                            GLboolean match_strides )
 {
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]);
-}
+   struct tnl_clipspace_fastpath *fastpath = CALLOC_STRUCT(tnl_clipspace_fastpath);
+   GLuint i;
 
-static void insert_4ub_4f_bgra( const struct attr *a, char *v, 
-                               const GLfloat *in )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]);
-}
+   fastpath->vertex_size = vtx->vertex_size;
+   fastpath->attr_count = vtx->attr_count;
+   fastpath->match_strides = match_strides;
+   fastpath->func = vtx->emit;
+   fastpath->attr = (struct tnl_attr_type *)
+      malloc(vtx->attr_count * sizeof(fastpath->attr[0]));
 
-static void insert_3ub_3f_rgb( const struct attr *a, char *v, 
-                              const GLfloat *in )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
-}
+   for (i = 0; i < vtx->attr_count; i++) {
+      fastpath->attr[i].format = vtx->attr[i].format;
+      fastpath->attr[i].stride = vtx->attr[i].inputstride;
+      fastpath->attr[i].size = vtx->attr[i].inputsize;
+      fastpath->attr[i].offset = vtx->attr[i].vertoffset;
+   }
 
-static void insert_3ub_3f_bgr( const struct attr *a, char *v, 
-                              const GLfloat *in )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
+   fastpath->next = vtx->fastpath;
+   vtx->fastpath = fastpath;
 }
 
-static void insert_1ub_1f( const struct attr *a, char *v, 
-                          const GLfloat *in )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
-}
 
 
 /***********************************************************************
- * Functions to perform the reverse operations to the above, for
- * swrast translation and clip-interpolation.
- * 
- * Currently always extracts a full 4 floats.
+ * Build codegen functions or return generic ones:
  */
-
-static void extract_4f_viewport( const struct attr *a, GLfloat *out, 
-                                const char *v )
+static void choose_emit_func( GLcontext *ctx, GLuint count, GLubyte *dest)
 {
-   const GLfloat *in = (const GLfloat *)v;
-   const GLfloat * const vp = a->vp;
-   
-   out[0] = (in[0] - vp[12]) / vp[0];
-   out[1] = (in[1] - vp[13]) / vp[5];
-   out[2] = (in[2] - vp[14]) / vp[10];
-   out[3] = in[3];
-}
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   struct tnl_clipspace_attr *a = vtx->attr;
+   const GLuint attr_count = vtx->attr_count;
+   GLuint j;
 
-static void extract_3f_viewport( const struct attr *a, GLfloat *out, 
-                                const char *v )
-{
-   const GLfloat *in = (const GLfloat *)v;
-   const GLfloat * const vp = a->vp;
+   for (j = 0; j < attr_count; j++) {
+      GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
+      a[j].inputstride = vptr->stride;
+      a[j].inputsize = vptr->size;
+      a[j].emit = a[j].insert[vptr->size - 1]; /* not always used */
+   }
+
+   vtx->emit = NULL;
    
-   out[0] = (in[0] - vp[12]) / vp[0];
-   out[1] = (in[1] - vp[13]) / vp[5];
-   out[2] = (in[2] - vp[14]) / vp[10];
-   out[3] = 1;
-}
+   /* Does this match an existing (hardwired, codegen or known-bad)
+    * fastpath?
+    */
+   if (search_fastpath_emit(vtx)) {
+      /* Use this result.  If it is null, then it is already known
+       * that the current state will fail for codegen and there is no
+       * point trying again.
+       */
+   }
+   else if (vtx->codegen_emit) {
+      vtx->codegen_emit(ctx);
+   }
 
+   if (!vtx->emit) {
+      _tnl_generate_hardwired_emit(ctx);
+   }
 
-static void extract_2f_viewport( const struct attr *a, GLfloat *out, 
-                                const char *v )
-{
-   const GLfloat *in = (const GLfloat *)v;
-   const GLfloat * const vp = a->vp;
-   
-   out[0] = (in[0] - vp[12]) / vp[0];
-   out[1] = (in[1] - vp[13]) / vp[5];
-   out[2] = 0;
-   out[3] = 1;
+   /* Otherwise use the generic version:
+    */
+   if (!vtx->emit)
+      vtx->emit = _tnl_generic_emit;
+
+   vtx->emit( ctx, count, dest );
 }
 
 
-static void extract_4f( const struct attr *a, GLfloat *out, const char *v  )
-{
-   const GLfloat *in = (const GLfloat *)v;
-   
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = in[2];
-   out[3] = in[3];
-}
 
-static void extract_3f_xyw( const struct attr *a, GLfloat *out, const char *v )
+static void choose_interp_func( GLcontext *ctx,
+                               GLfloat t,
+                               GLuint edst, GLuint eout, GLuint ein,
+                               GLboolean force_boundary )
 {
-   const GLfloat *in = (const GLfloat *)v;
-   
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = in[3];
-   out[3] = 1;
-}
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
 
+   if (vtx->need_extras && 
+       (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+      vtx->interp = _tnl_generic_interp_extras;
+   } else {
+      vtx->interp = _tnl_generic_interp;
+   }
 
-static void extract_3f( const struct attr *a, GLfloat *out, const char *v )
-{
-   const GLfloat *in = (const GLfloat *)v;
-   
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = in[2];
-   out[3] = 1;
+   vtx->interp( ctx, t, edst, eout, ein, force_boundary );
 }
 
 
-static void extract_2f( const struct attr *a, GLfloat *out, const char *v )
+static void choose_copy_pv_func(  GLcontext *ctx, GLuint edst, GLuint esrc )
 {
-   const GLfloat *in = (const GLfloat *)v;
-   
-   out[0] = in[0];
-   out[1] = in[1];
-   out[2] = 0;
-   out[3] = 1;
-}
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
 
-static void extract_1f( const struct attr *a, GLfloat *out, const char *v )
-{
-   const GLfloat *in = (const GLfloat *)v;
-   
-   out[0] = in[0];
-   out[1] = 0;
-   out[2] = 0;
-   out[3] = 1;
-}
+   if (vtx->need_extras && 
+       (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+      vtx->copy_pv = _tnl_generic_copy_pv_extras;
+   } else {
+      vtx->copy_pv = _tnl_generic_copy_pv;
+   }
 
-static void extract_4ub_4f_rgba( const struct attr *a, GLfloat *out, 
-                                const char *v )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]);
+   vtx->copy_pv( ctx, edst, esrc );
 }
 
-static void extract_4ub_4f_bgra( const struct attr *a, GLfloat *out, 
-                                const char *v )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]);
-}
 
-static void extract_3ub_3f_rgb( const struct attr *a, GLfloat *out, 
-                               const char *v )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
-   out[3] = 1;
-}
+/***********************************************************************
+ * Public entrypoints, mostly dispatch to the above:
+ */
 
-static void extract_3ub_3f_bgr( const struct attr *a, GLfloat *out, 
-                               const char *v )
-{
-   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
-   out[3] = 1;
-}
 
-static void extract_1ub_1f( const struct attr *a, GLfloat *out, const char *v )
+/* Interpolate between two vertices to produce a third:
+ */
+void _tnl_interp( GLcontext *ctx,
+                 GLfloat t,
+                 GLuint edst, GLuint eout, GLuint ein,
+                 GLboolean force_boundary )
 {
-   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
-   out[1] = 0;
-   out[2] = 0;
-   out[3] = 1;
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   vtx->interp( ctx, t, edst, eout, ein, force_boundary );
 }
 
-/***********************************************************************
- * Generic (non-codegen) functions for whole vertices or groups of
- * vertices
+/* Copy colors from one vertex to another:
  */
-
-static void generic_emit( GLcontext *ctx,
-                         GLuint start, GLuint end,
-                         void *dest,
-                         GLuint stride )
+void _tnl_copy_pv(  GLcontext *ctx, GLuint edst, GLuint esrc )
 {
-   int i, j;
-   char *v = (char *)dest;
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   vtx->copy_pv( ctx, edst, esrc );
+}
 
-   vtx->vertex_buf = v - start * stride;
-   vtx->vertex_stride = stride;
 
-   end -= start;
+/* Extract a named attribute from a hardware vertex.  Will have to
+ * reverse any viewport transformation, swizzling or other conversions
+ * which may have been applied:
+ */
+void _tnl_get_attr( GLcontext *ctx, const void *vin,
+                             GLenum attr, GLfloat *dest )
+{
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   const struct tnl_clipspace_attr *a = vtx->attr;
+   const GLuint attr_count = vtx->attr_count;
+   GLuint j;
 
-   for (j = 0; j < vtx->attr_count; j++) {
-      GLvector4f *vptr = VB->AttrPtr[a[j].attrib];
-      a[j].inputptr = STRIDE_4F(vptr->data, start * vptr->stride);
+   for (j = 0; j < attr_count; j++) {
+      if (a[j].attrib == attr) {
+        a[j].extract( &a[j], dest, (GLubyte *)vin + a[j].vertoffset );
+        return;
+      }
    }
 
-   for (i = 0 ; i < end ; i++, v += stride) {
-      for (j = 0; j < vtx->attr_count; j++) {
-        int *in = a[j].inputptr;
-        (char *)a[j].inputptr += a[j].inputstride;
-        a[j].out( &a[j], v + a[j].vertoffset, in );
-      }
+   /* Else return the value from ctx->Current.
+    */
+   if (attr == _TNL_ATTRIB_POINTSIZE) {
+      /* If the hardware vertex doesn't have point size then use size from
+       * GLcontext.  XXX this will be wrong if drawing attenuated points!
+       */
+      dest[0] = ctx->Point.Size;
+   }
+   else {
+      memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
    }
 }
 
 
-static void generic_interp( GLcontext *ctx,
-                           GLfloat t,
-                           GLuint edst, GLuint eout, GLuint ein,
-                           GLboolean force_boundary )
+/* Complementary operation to the above.
+ */
+void _tnl_set_attr( GLcontext *ctx, void *vout,
+                   GLenum attr, const GLfloat *src )
 {
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   char *vin  = vtx->vertex_buf + ein  * vtx->vertex_stride;
-   char *vout = vtx->vertex_buf + eout * vtx->vertex_stride;
-   char *vdst = vtx->vertex_buf + edst * vtx->vertex_stride;
-   const struct attr *a = vtx->attr;
-   int attr_count = vtx->attr_count;
-   int j;
-   
-   for (j = 0; j < attr_count; j++) {
-      GLfloat fin[4], fout[4], fdst[4];
-      
-      a[j].extract( &a[j], vin, fin );
-      a[j].extract( &a[j], vout, fout );
-
-      INTERP_F( t, fdst[3], fout[3], fin[3] );
-      INTERP_F( t, fdst[2], fout[2], fin[2] );
-      INTERP_F( t, fdst[1], fout[1], fin[1] );
-      INTERP_F( t, fdst[0], fout[0], fin[0] );
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   const struct tnl_clipspace_attr *a = vtx->attr;
+   const GLuint attr_count = vtx->attr_count;
+   GLuint j;
 
-      a[j].insert( &a[j], vdst, fdst );
+   for (j = 0; j < attr_count; j++) {
+      if (a[j].attrib == attr) {
+        a[j].insert[4-1]( &a[j], (GLubyte *)vout + a[j].vertoffset, src );
+        return;
+      }
    }
 }
 
 
-/* Extract color attributes from one vertex and insert them into
- * another.  (Shortcircuit extract/insert with memcpy).
- */
-static void generic_copy_colors( GLcontext *ctx, GLuint edst, GLuint esrc )
+void *_tnl_get_vertex( GLcontext *ctx, GLuint nr )
 {
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   char *vsrc = vert_start + esrc * vert_stride;
-   char *vdst = vert_start + edst * vert_stride;
-   const struct attr *a = vtx->attr;
-   int attr_count = vtx->attr_count;
-   int j;
-
-   for (j = 0; j < attr_count; j++) {
-      if (a[j].attribute == VERT_ATTRIB_COLOR0 ||
-         a[j].attribute == VERT_ATTRIB_COLOR1) {
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
 
-        memcpy( vdst + a[j].vertoffset,
-                vsrc + a[j].vertoffset,
-                a[j].vertattrsize );
-   }
+   return vtx->vertex_buf + nr * vtx->vertex_size;
 }
 
-static void generic_get_attr( GLcontext *ctx, const char *vertex,
-                             GLenum attr, GLfloat *dest )
+void _tnl_invalidate_vertex_state( GLcontext *ctx, GLuint new_state )
 {
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   const struct attr *a = vtx->attr;
-   int attr_count = vtx->attr_count;
-   int j;
-
-   for (j = 0; j < attr_count; j++) {
-      if (a[j].attribute == attr) {
-        a[j].extract( &a[j], vin, dest );
-        return;
-      }
+   if (new_state & (_DD_NEW_TRI_LIGHT_TWOSIDE|_DD_NEW_TRI_UNFILLED) ) {
+      struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+      vtx->new_inputs = ~0;
+      vtx->interp = choose_interp_func;
+      vtx->copy_pv = choose_copy_pv_func;
    }
-
-   /* Else return the value from ctx->Current
-    */
-   memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
 }
 
+static void invalidate_funcs( struct tnl_clipspace *vtx )
+{
+   vtx->emit = choose_emit_func;
+   vtx->interp = choose_interp_func;
+   vtx->copy_pv = choose_copy_pv_func;
+   vtx->new_inputs = ~0;
+}
 
+GLuint _tnl_install_attrs( GLcontext *ctx, const struct tnl_attr_map *map,
+                          GLuint nr, const GLfloat *vp, 
+                          GLuint unpacked_size )
+{
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   GLuint offset = 0;
+   GLuint i, j;
 
+   assert(nr < _TNL_ATTRIB_MAX);
+   assert(nr == 0 || map[0].attrib == VERT_ATTRIB_POS);
 
+   vtx->new_inputs = ~0;
+   vtx->need_viewport = GL_FALSE;
 
+   if (vp) {
+      vtx->need_viewport = GL_TRUE;
+   }
 
+   for (j = 0, i = 0; i < nr; i++) {
+      const GLuint format = map[i].format;
+      if (format == EMIT_PAD) {
+        if (DBG)
+           printf("%d: pad %d, offset %d\n", i,  
+                  map[i].offset, offset);  
 
-/***********************************************************************
- * Build codegen functions or return generic ones:
- */
+        offset += map[i].offset;
 
+      }
+      else {
+        GLuint tmpoffset;
+
+        if (unpacked_size) 
+           tmpoffset = map[i].offset;
+        else
+           tmpoffset = offset;
+
+        if (vtx->attr_count != j ||
+            vtx->attr[j].attrib != map[i].attrib ||
+            vtx->attr[j].format != format ||
+            vtx->attr[j].vertoffset != tmpoffset) {
+           invalidate_funcs(vtx);
+
+           vtx->attr[j].attrib = map[i].attrib;
+           vtx->attr[j].format = format;
+           vtx->attr[j].vp = vp;
+           vtx->attr[j].insert = _tnl_format_info[format].insert;
+           vtx->attr[j].extract = _tnl_format_info[format].extract;
+           vtx->attr[j].vertattrsize = _tnl_format_info[format].attrsize;
+           vtx->attr[j].vertoffset = tmpoffset;
+        }
+
+        
+        if (DBG)
+           printf("%d: %s, vp %p, offset %d\n", i,  
+                  _tnl_format_info[format].name, (void *)vp,
+                  vtx->attr[j].vertoffset);   
+
+        offset += _tnl_format_info[format].attrsize;
+        j++;
+      }
+   }
 
-static void choose_emit_func( GLcontext *ctx,
-                             GLuint start, GLuint end,
-                             void *dest,
-                             GLuint stride )
-{
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->emit_func = generic_emit_func;
-   vtx->emit_func( ctx, start, end, dest, stride );
-}
+   vtx->attr_count = j;
 
+   if (unpacked_size)
+      vtx->vertex_size = unpacked_size;
+   else
+      vtx->vertex_size = offset;
 
-static void choose_interp_func( GLcontext *ctx,
-                               GLfloat t,
-                               GLuint edst, GLuint eout, GLuint ein,
-                               GLboolean force_boundary )
-{
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->interp_func = generic_interp_func;
-   vtx->interp_func( ctx, t, edst, eout, ein, force_boundary );
+   assert(vtx->vertex_size <= vtx->max_vertex_size);
+   return vtx->vertex_size;
 }
 
 
-static void choose_copy_color_func(  GLcontext *ctx, GLuint edst, GLuint esrc )
-{
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->copy_color_func = generic_copy_color_func;
-   vtx->copy_color_func( ctx, edst, esrc );
-}
 
-
-/***********************************************************************
- * Public entrypoints, mostly dispatch to the above:
- */
-
-void _tnl_emit( GLcontext *ctx,
-               GLuint start, GLuint end,
-               void *dest,
-               GLuint stride )
+void _tnl_invalidate_vertices( GLcontext *ctx, GLuint newinputs )
 {
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->emit_func( ctx, start, end, dest, stride );
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   vtx->new_inputs |= newinputs;
 }
 
-/* Interpolate between two vertices to produce a third:
- */
-void _tnl_interp( GLcontext *ctx,
-                 GLfloat t,
-                 GLuint edst, GLuint eout, GLuint ein,
-                 GLboolean force_boundary )
-{
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->interp_func( ctx, t, edst, eout, ein, force_boundary );
-}
 
-/* Copy colors from one vertex to another:
+/* This event has broader use beyond this file - will move elsewhere
+ * and probably invoke a driver callback.
  */
-void _tnl_copy_colors(  GLcontext *ctx, GLuint edst, GLuint esrc )
+void _tnl_notify_pipeline_output_change( GLcontext *ctx )
 {
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->copy_color_func( ctx, edst, esrc );
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   invalidate_funcs(vtx);
 }
 
 
-/* Extract a named attribute from a hardware vertex.  Will have to
- * reverse any viewport transformation, swizzling or other conversions
- * which may have been applied:
- */
-void _tnl_get_attr( GLcontext *ctx, void *vertex, GLenum attrib,
-                   GLfloat *dest )
+static void adjust_input_ptrs( GLcontext *ctx, GLint diff)
 {
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   vtx->get_attr_func( ctx, vertex, attrib, dest );
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   struct tnl_clipspace_attr *a = vtx->attr;
+   const GLuint count = vtx->attr_count;
+   GLuint j;
+
+   diff -= 1;
+   for (j=0; j<count; ++j) {
+           register GLvector4f *vptr = VB->AttribPtr[a->attrib];
+          (a++)->inputptr += diff*vptr->stride;
+   }
 }
 
+static void update_input_ptrs( GLcontext *ctx, GLuint start )
+{
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   struct tnl_clipspace_attr *a = vtx->attr;
+   const GLuint count = vtx->attr_count;
+   GLuint j;
+   
+   for (j = 0; j < count; j++) {
+      GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
 
+      if (vtx->emit != choose_emit_func) {
+        assert(a[j].inputstride == vptr->stride);
+        assert(a[j].inputsize == vptr->size);
+      }
 
-void _tnl_install_attrs( GLcontext *ctx, const struct dri_attr_map *map,
-                        GLuint nr, const GLfloat *vp )
-{
-   struct dri_vertex_state *vtx = GET_VERTEX_STATE(ctx);
-   int i;
-
-   assert(nr < _TNL_ATTR_MAX);
-
-   vtx->attr_count = nr;
-   vtx->emit_func = choose_emit_func;
-   vtx->interp_func = choose_interp_func;
-   vtx->copy_color_func = choose_copy_color_func;
-   vtx->get_attr_func = choose_get_attr_func;
-
-   for (i = 0; i < nr; i++) {
-      GLuint attrib = map[i].attrib;
-      vtx->attr[i].attrib = map[i].attrib;
-      vtx->attr[i].hw_format = map[i].hw_format;
-      vtx->attr[i].vp = vp;
-      vtx->attr[i].insert = attrib_info[attrib].insert;
-      vtx->attr[i].extract = attrib_info[attrib].extract;
-      vtx->attr[i].vertattrsize = attrib_info[attrib].attrsize;
-      vtx->attr[i].vertoffset = offset;
-      offset += attrib_info[attrib].attrsize;
+      a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride;
+   }
+   
+   if (a->vp) {
+      vtx->vp_scale[0] = a->vp[MAT_SX];
+      vtx->vp_scale[1] = a->vp[MAT_SY];
+      vtx->vp_scale[2] = a->vp[MAT_SZ];
+      vtx->vp_scale[3] = 1.0;
+      vtx->vp_xlate[0] = a->vp[MAT_TX];
+      vtx->vp_xlate[1] = a->vp[MAT_TY];
+      vtx->vp_xlate[2] = a->vp[MAT_TZ];
+      vtx->vp_xlate[3] = 0.0;
    }
 }
 
 
+void _tnl_build_vertices( GLcontext *ctx,
+                         GLuint start,
+                         GLuint end,
+                         GLuint newinputs )
+{
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);  
+   update_input_ptrs( ctx, start );      
+   vtx->emit( ctx, end - start, 
+             (GLubyte *)(vtx->vertex_buf + 
+                         start * vtx->vertex_size));
+}
 
-
-/* Populate a swrast SWvertex from an attrib-style vertex.
+/* Emit VB vertices start..end to dest.  Note that VB vertex at
+ * postion start will be emitted to dest at position zero.
  */
-void _tnl_translate( GLcontext *ctx, const void *vertex, SWvertex *dest )
+void *_tnl_emit_vertices_to_buffer( GLcontext *ctx,
+                                   GLuint start,
+                                   GLuint end,
+                                   void *dest )
 {
-   _tnl_get_attr( ctx, vertex, VERT_ATTRIB_POS, dest.win );
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
 
-   for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
-      _tnl_get_attr( ctx, vertex, VERT_ATTRIB_TEX(i), dest.texcoord[i] );
-         
-   _tnl_get_attr( ctx, vertex, VERT_ATTRIB_COLOR0, tmp );
-   UNCLAMPED_FLOAT_TO_CHAN_RGBA( dest.color, tmp );
-
-   _tnl_get_attr( ctx, vertex, VERT_ATTRIB_COLOR1, tmp );
-   UNCLAMPED_FLOAT_TO_CHAN_RGB( dest.specular, tmp );
+   update_input_ptrs(ctx, start);
+   /* Note: dest should not be adjusted for non-zero 'start' values:
+    */
+   vtx->emit( ctx, end - start, (GLubyte*) dest );     
+   return (void *)((GLubyte *)dest + vtx->vertex_size * (end - start));
+}
 
-   _tnl_get_attr( ctx, vertex, VERT_ATTRIB_FOG, tmp );
-   dest.fog = tmp[0];
+/* Emit indexed VB vertices start..end to dest.  Note that VB vertex at
+ * postion start will be emitted to dest at position zero.
+ */
 
-   _tnl_get_attr( ctx, vertex, VERT_ATTRIB_INDEX, tmp );
-   dest.index = (GLuint) tmp[0];
+void *_tnl_emit_indexed_vertices_to_buffer( GLcontext *ctx,
+                                           const GLuint *elts,
+                                           GLuint start,
+                                           GLuint end,
+                                           void *dest )
+{
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+   GLuint oldIndex;
+   GLubyte *cdest = dest;
+
+   update_input_ptrs(ctx, oldIndex = elts[start++]);
+   vtx->emit( ctx, 1, cdest );
+   cdest += vtx->vertex_size;
+
+   for (; start < end; ++start) {
+      adjust_input_ptrs(ctx, elts[start] - oldIndex);
+      oldIndex = elts[start];
+      vtx->emit( ctx, 1, cdest);
+      cdest += vtx->vertex_size;
+   }
 
-   _tnl_get_attr( ctx, vertex, VERT_ATTRIB_POINTSIZE, tmp );
-   dest.pointSize = tmp[0];
+   return (void *) cdest;
 }
 
 
-static void interp_extras( GLcontext *ctx,
-                          GLfloat t,
-                          GLuint dst, GLuint out, GLuint in,
-                          GLboolean force_boundary )
+void _tnl_init_vertices( GLcontext *ctx, 
+                       GLuint vb_size,
+                       GLuint max_vertex_size )
 {
-   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);  
 
-   if (VB->ColorPtr[1]) {
-      assert(VB->ColorPtr[1]->stride == 4 * sizeof(GLfloat));
+   _tnl_install_attrs( ctx, NULL, 0, NULL, 0 );
 
-      INTERP_4F( t,
-                GET_COLOR(VB->ColorPtr[1], dst),
-                GET_COLOR(VB->ColorPtr[1], out),
-                GET_COLOR(VB->ColorPtr[1], in) );
-
-      if (VB->SecondaryColorPtr[1]) {
-        INTERP_3F( t,
-                   GET_COLOR(VB->SecondaryColorPtr[1], dst),
-                   GET_COLOR(VB->SecondaryColorPtr[1], out),
-                   GET_COLOR(VB->SecondaryColorPtr[1], in) );
-      }
+   vtx->need_extras = GL_TRUE;
+   if (max_vertex_size > vtx->max_vertex_size) {
+      _tnl_free_vertices( ctx );
+      vtx->max_vertex_size = max_vertex_size;
+      vtx->vertex_buf = (GLubyte *)_mesa_align_calloc(vb_size * max_vertex_size, 32 );
+      invalidate_funcs(vtx);
    }
 
-   if (VB->EdgeFlag) {
-      VB->EdgeFlag[dst] = VB->EdgeFlag[out] || force_boundary;
+   switch(CHAN_TYPE) {
+   case GL_UNSIGNED_BYTE:
+      vtx->chan_scale[0] = 255.0;
+      vtx->chan_scale[1] = 255.0;
+      vtx->chan_scale[2] = 255.0;
+      vtx->chan_scale[3] = 255.0;
+      break;
+   case GL_UNSIGNED_SHORT:
+      vtx->chan_scale[0] = 65535.0;
+      vtx->chan_scale[1] = 65535.0;
+      vtx->chan_scale[2] = 65535.0;
+      vtx->chan_scale[3] = 65535.0;
+      break;
+   default:
+      vtx->chan_scale[0] = 1.0;
+      vtx->chan_scale[1] = 1.0;
+      vtx->chan_scale[2] = 1.0;
+      vtx->chan_scale[3] = 1.0;
+      break;
    }
 
-   generic_interp(ctx, t, dst, out, in, force_boundary);
+   vtx->identity[0] = 0.0;
+   vtx->identity[1] = 0.0;
+   vtx->identity[2] = 0.0;
+   vtx->identity[3] = 1.0;
+
+   vtx->codegen_emit = NULL;
+
+#ifdef USE_SSE_ASM
+   if (!_mesa_getenv("MESA_NO_CODEGEN"))
+      vtx->codegen_emit = _tnl_generate_sse_emit;
+#endif
 }
 
-static void copy_pv_extras( GLcontext *ctx, 
-                           GLuint dst, GLuint src )
+
+void _tnl_free_vertices( GLcontext *ctx )
 {
-   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   if (tnl) {
+      struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+      struct tnl_clipspace_fastpath *fp, *tmp;
 
-   if (VB->ColorPtr[1]) {
-      COPY_4FV( GET_COLOR(VB->ColorPtr[1], dst), 
-               GET_COLOR(VB->ColorPtr[1], src) );
+      if (vtx->vertex_buf) {
+         _mesa_align_free(vtx->vertex_buf);
+         vtx->vertex_buf = NULL;
+      }
 
-      if (VB->SecondaryColorPtr[1]) {
-        COPY_4FV( GET_COLOR(VB->SecondaryColorPtr[1], dst), 
-                  GET_COLOR(VB->SecondaryColorPtr[1], src) );
+      for (fp = vtx->fastpath ; fp ; fp = tmp) {
+         tmp = fp->next;
+         FREE(fp->attr);
+
+         /* KW: At the moment, fp->func is constrained to be allocated by
+          * _mesa_exec_alloc(), as the hardwired fastpaths in
+          * t_vertex_generic.c are handled specially.  It would be nice
+          * to unify them, but this probably won't change until this
+          * module gets another overhaul.
+          */
+         _mesa_exec_free((void *) fp->func);
+         FREE(fp);
       }
-   }
 
-   generic_copy_colors(ctx, dst, src);
+      vtx->fastpath = NULL;
+   }
 }
-
-#endif