remove obsolete t_save_api.c
authorBrian <brian.paul@tungstengraphics.com>
Thu, 28 Jun 2007 13:15:37 +0000 (07:15 -0600)
committerBrian <brian.paul@tungstengraphics.com>
Thu, 28 Jun 2007 13:16:13 +0000 (07:16 -0600)
src/mesa/tnl/t_save_api.c [deleted file]

diff --git a/src/mesa/tnl/t_save_api.c b/src/mesa/tnl/t_save_api.c
deleted file mode 100644 (file)
index b08f053..0000000
+++ /dev/null
@@ -1,1834 +0,0 @@
-/**************************************************************************
-
-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>
- */
-
-
-
-/**
- * The display list compiler attempts to store lists of vertices with the
- * same vertex layout.  Additionally it attempts to minimize the need
- * for execute-time fixup of these vertex lists, allowing them to be
- * cached on hardware.
- *
- * There are still some circumstances where this can be thwarted, for
- * example by building a list that consists of one very long primitive
- * (eg Begin(Triangles), 1000 vertices, End), and calling that list
- * from inside a different begin/end object (Begin(Lines), CallList,
- * End).  
- *
- * In that case the code will have to replay the list as individual
- * commands through the Exec dispatch table, or fix up the copied
- * vertices at execute-time.
- *
- * The other case where fixup is required is when a vertex attribute
- * is introduced in the middle of a primitive.  Eg:
- *  Begin(Lines)
- *  TexCoord1f()           Vertex2f()
- *  TexCoord1f() Color3f() Vertex2f()
- *  End()
- *
- *  If the current value of Color isn't known at compile-time, this
- *  primitive will require fixup.
- *
- *
- * The list compiler currently doesn't attempt to compile lists
- * containing EvalCoord or EvalPoint commands.  On encountering one of
- * these, compilation falls back to opcodes.  
- *
- * This could be improved to fallback only when a mix of EvalCoord and
- * Vertex commands are issued within a single primitive.
- */
-
-
-#include "glheader.h"
-#include "context.h"
-#include "dlist.h"
-#include "enums.h"
-#include "macros.h"
-#include "api_validate.h"
-#include "api_arrayelt.h"
-#include "vtxfmt.h"
-#include "t_save_api.h"
-#include "dispatch.h"
-
-/*
- * NOTE: Old 'parity' issue is gone, but copying can still be
- * wrong-footed on replay.
- */
-static GLuint _save_copy_vertices( GLcontext *ctx, 
-                                  const struct tnl_vertex_list *node )
-{
-   TNLcontext *tnl = TNL_CONTEXT( ctx );
-   const struct tnl_prim *prim = &node->prim[node->prim_count-1];
-   GLuint nr = prim->count;
-   GLuint sz = tnl->save.vertex_size;
-   const GLfloat *src = node->buffer + prim->start * sz;
-   GLfloat *dst = tnl->save.copied.buffer;
-   GLuint ovf, i;
-
-   if (prim->mode & PRIM_END)
-      return 0;
-        
-   switch( prim->mode & PRIM_MODE_MASK )
-   {
-   case GL_POINTS:
-      return 0;
-   case GL_LINES:
-      ovf = nr&1;
-      for (i = 0 ; i < ovf ; i++)
-        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
-      return i;
-   case GL_TRIANGLES:
-      ovf = nr%3;
-      for (i = 0 ; i < ovf ; i++)
-        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
-      return i;
-   case GL_QUADS:
-      ovf = nr&3;
-      for (i = 0 ; i < ovf ; i++)
-        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
-      return i;
-   case GL_LINE_STRIP:
-      if (nr == 0) 
-        return 0;
-      else {
-        _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
-        return 1;
-      }
-   case GL_LINE_LOOP:
-   case GL_TRIANGLE_FAN:
-   case GL_POLYGON:
-      if (nr == 0) 
-        return 0;
-      else if (nr == 1) {
-        _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
-        return 1;
-      } else {
-        _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
-        _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
-        return 2;
-      }
-   case GL_TRIANGLE_STRIP:
-   case GL_QUAD_STRIP:
-      switch (nr) {
-      case 0: ovf = 0; break;
-      case 1: ovf = 1; break;
-      default: ovf = 2 + (nr&1); break;
-      }
-      for (i = 0 ; i < ovf ; i++)
-        _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
-      return i;
-   default:
-      assert(0);
-      return 0;
-   }
-}
-
-
-static void
-build_normal_lengths( struct tnl_vertex_list *node )
-{
-   GLuint i;
-   GLfloat *len;
-   GLfloat *n = node->buffer;
-   GLuint stride = node->vertex_size;
-   GLuint count = node->count;
-
-   len = node->normal_lengths = (GLfloat *) MALLOC( count * sizeof(GLfloat) );
-   if (!len)
-      return;
-
-   /* Find the normal of the first vertex:
-    */
-   for (i = 0 ; i < _TNL_ATTRIB_NORMAL ; i++) 
-      n += node->attrsz[i];
-
-   for (i = 0 ; i < count ; i++, n += stride) {
-      len[i] = LEN_3FV( n );
-      if (len[i] > 0.0F) len[i] = 1.0F / len[i];
-   } 
-}
-
-static struct tnl_vertex_store *alloc_vertex_store( GLcontext *ctx )
-{
-   struct tnl_vertex_store *store = MALLOC_STRUCT(tnl_vertex_store);
-   (void) ctx;
-   store->used = 0;
-   store->refcount = 1;
-   return store;
-}
-
-static struct tnl_primitive_store *alloc_prim_store( GLcontext *ctx )
-{
-   struct tnl_primitive_store *store = MALLOC_STRUCT(tnl_primitive_store);
-   (void) ctx;
-   store->used = 0;
-   store->refcount = 1;
-   return store;
-}
-
-static void _save_reset_counters( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-
-   tnl->save.prim = tnl->save.prim_store->buffer + tnl->save.prim_store->used;
-   tnl->save.buffer = (tnl->save.vertex_store->buffer + 
-                      tnl->save.vertex_store->used);
-
-   if (tnl->save.vertex_size)
-      tnl->save.initial_counter = ((SAVE_BUFFER_SIZE - 
-                                   tnl->save.vertex_store->used) / 
-                                  tnl->save.vertex_size);
-   else
-      tnl->save.initial_counter = 0;
-
-   if (tnl->save.initial_counter > ctx->Const.MaxArrayLockSize )
-      tnl->save.initial_counter = ctx->Const.MaxArrayLockSize;
-
-   tnl->save.counter = tnl->save.initial_counter;
-   tnl->save.prim_count = 0;
-   tnl->save.prim_max = SAVE_PRIM_SIZE - tnl->save.prim_store->used;
-   tnl->save.copied.nr = 0;
-   tnl->save.dangling_attr_ref = 0;
-}
-
-
-/* Insert the active immediate struct onto the display list currently
- * being built.
- */
-static void _save_compile_vertex_list( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct tnl_vertex_list *node;
-
-   /* Allocate space for this structure in the display list currently
-    * being compiled.
-    */
-   node = (struct tnl_vertex_list *)
-      _mesa_alloc_instruction(ctx, tnl->save.opcode_vertex_list, sizeof(*node));
-
-   if (!node)
-      return;
-
-   /* Duplicate our template, increment refcounts to the storage structs:
-    */
-   _mesa_memcpy(node->attrsz, tnl->save.attrsz, sizeof(node->attrsz));
-   node->vertex_size = tnl->save.vertex_size;
-   node->buffer = tnl->save.buffer;
-   node->count = tnl->save.initial_counter - tnl->save.counter;
-   node->wrap_count = tnl->save.copied.nr;
-   node->have_materials = tnl->save.have_materials;
-   node->dangling_attr_ref = tnl->save.dangling_attr_ref;
-   node->normal_lengths = NULL;
-   node->prim = tnl->save.prim;
-   node->prim_count = tnl->save.prim_count;
-   node->vertex_store = tnl->save.vertex_store;
-   node->prim_store = tnl->save.prim_store;
-
-   node->vertex_store->refcount++;
-   node->prim_store->refcount++;
-
-   assert(node->attrsz[_TNL_ATTRIB_POS] != 0 ||
-         node->count == 0);
-
-   if (tnl->save.dangling_attr_ref)
-      ctx->ListState.CurrentList->flags |= MESA_DLIST_DANGLING_REFS;
-
-   /* Maybe calculate normal lengths:
-    */
-   if (tnl->CalcDListNormalLengths && 
-       node->attrsz[_TNL_ATTRIB_NORMAL] == 3 &&
-       !(ctx->ListState.CurrentList->flags & MESA_DLIST_DANGLING_REFS))
-      build_normal_lengths( node );
-
-
-   tnl->save.vertex_store->used += tnl->save.vertex_size * node->count;
-   tnl->save.prim_store->used += node->prim_count;
-
-   /* Decide whether the storage structs are full, or can be used for
-    * the next vertex lists as well.
-    */
-   if (tnl->save.vertex_store->used > 
-       SAVE_BUFFER_SIZE - 16 * (tnl->save.vertex_size + 4)) {
-
-      tnl->save.vertex_store->refcount--; 
-      assert(tnl->save.vertex_store->refcount != 0);
-      tnl->save.vertex_store = alloc_vertex_store( ctx );
-      tnl->save.vbptr = tnl->save.vertex_store->buffer;
-   } 
-
-   if (tnl->save.prim_store->used > SAVE_PRIM_SIZE - 6) {
-      tnl->save.prim_store->refcount--; 
-      assert(tnl->save.prim_store->refcount != 0);
-      tnl->save.prim_store = alloc_prim_store( ctx );
-   } 
-
-   /* Reset our structures for the next run of vertices:
-    */
-   _save_reset_counters( ctx );
-
-   /* Copy duplicated vertices 
-    */
-   tnl->save.copied.nr = _save_copy_vertices( ctx, node );
-
-
-   /* Deal with GL_COMPILE_AND_EXECUTE:
-    */
-   if (ctx->ExecuteFlag) {
-      _tnl_playback_vertex_list( ctx, (void *) node );
-   }
-}
-
-
-/* TODO -- If no new vertices have been stored, don't bother saving
- * it.
- */
-static void _save_wrap_buffers( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLint i = tnl->save.prim_count - 1;
-   GLenum mode;
-
-   assert(i < (GLint) tnl->save.prim_max);
-   assert(i >= 0);
-
-   /* Close off in-progress primitive.
-    */
-   tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) - 
-                            tnl->save.prim[i].start);
-   mode = tnl->save.prim[i].mode & ~(PRIM_BEGIN|PRIM_END);
-   
-   /* store the copied vertices, and allocate a new list.
-    */
-   _save_compile_vertex_list( ctx );
-
-   /* Restart interrupted primitive
-    */
-   tnl->save.prim[0].mode = mode;
-   tnl->save.prim[0].start = 0;
-   tnl->save.prim[0].count = 0;
-   tnl->save.prim_count = 1;
-}
-
-
-
-/* Called only when buffers are wrapped as the result of filling the
- * vertex_store struct.  
- */
-static void _save_wrap_filled_vertex( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLfloat *data = tnl->save.copied.buffer;
-   GLuint i;
-
-   /* Emit a glEnd to close off the last vertex list.
-    */
-   _save_wrap_buffers( ctx );
-   
-    /* Copy stored stored vertices to start of new list.
-    */
-   assert(tnl->save.counter > tnl->save.copied.nr);
-
-   for (i = 0 ; i < tnl->save.copied.nr ; i++) {
-      _mesa_memcpy( tnl->save.vbptr, data, tnl->save.vertex_size * sizeof(GLfloat));
-      data += tnl->save.vertex_size;
-      tnl->save.vbptr += tnl->save.vertex_size;
-      tnl->save.counter--;
-   }
-}
-
-
-static void _save_copy_to_current( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx); 
-   GLuint i;
-
-   /* XXX Use _TNL_FIRST_* and _TNL_LAST_* values instead? */
-   for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_EDGEFLAG ; i++) {
-      if (tnl->save.attrsz[i]) {
-        tnl->save.currentsz[i][0] = tnl->save.attrsz[i];
-        COPY_CLEAN_4V(tnl->save.current[i], 
-                   tnl->save.attrsz[i], 
-                   tnl->save.attrptr[i]);
-      }
-   }
-
-   /* Edgeflag requires special treatment: 
-    *
-    * TODO: change edgeflag to GLfloat in Mesa.
-    */
-   if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
-      ctx->ListState.ActiveEdgeFlag = 1;
-      tnl->save.CurrentFloatEdgeFlag = 
-        tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0];
-      ctx->ListState.CurrentEdgeFlag = 
-        (tnl->save.CurrentFloatEdgeFlag == 1.0);
-   }
-}
-
-
-static void _save_copy_from_current( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx); 
-   GLint i;
-
-   for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_EDGEFLAG ; i++) 
-      switch (tnl->save.attrsz[i]) {
-      case 4: tnl->save.attrptr[i][3] = tnl->save.current[i][3];
-      case 3: tnl->save.attrptr[i][2] = tnl->save.current[i][2];
-      case 2: tnl->save.attrptr[i][1] = tnl->save.current[i][1];
-      case 1: tnl->save.attrptr[i][0] = tnl->save.current[i][0];
-      case 0: break;
-      }
-
-   /* Edgeflag requires special treatment:
-    */
-   if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
-      tnl->save.CurrentFloatEdgeFlag = (GLfloat)ctx->ListState.CurrentEdgeFlag;
-      tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] = tnl->save.CurrentFloatEdgeFlag;
-   }
-}
-
-
-
-
-/* Flush existing data, set new attrib size, replay copied vertices.
- */ 
-static void _save_upgrade_vertex( GLcontext *ctx, 
-                                GLuint attr,
-                                GLuint newsz )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLuint oldsz;
-   GLuint i;
-   GLfloat *tmp;
-
-   /* Store the current run of vertices, and emit a GL_END.  Emit a
-    * BEGIN in the new buffer.
-    */
-   if (tnl->save.initial_counter != tnl->save.counter) 
-      _save_wrap_buffers( ctx );
-   else
-      assert( tnl->save.copied.nr == 0 );
-
-   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
-    * when the attribute already exists in the vertex and is having
-    * its size increased.  
-    */
-   _save_copy_to_current( ctx );
-
-   /* Fix up sizes:
-    */
-   oldsz = tnl->save.attrsz[attr];
-   tnl->save.attrsz[attr] = newsz;
-
-   tnl->save.vertex_size += newsz - oldsz;
-   tnl->save.counter = ((SAVE_BUFFER_SIZE - tnl->save.vertex_store->used) / 
-                       tnl->save.vertex_size);
-   if (tnl->save.counter > ctx->Const.MaxArrayLockSize )
-      tnl->save.counter = ctx->Const.MaxArrayLockSize;
-   tnl->save.initial_counter = tnl->save.counter;
-
-   /* Recalculate all the attrptr[] values:
-    */
-   for (i = 0, tmp = tnl->save.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
-      if (tnl->save.attrsz[i]) {
-        tnl->save.attrptr[i] = tmp;
-        tmp += tnl->save.attrsz[i];
-      }
-      else 
-        tnl->save.attrptr[i] = NULL; /* will not be dereferenced. */
-   }
-
-   /* Copy from current to repopulate the vertex with correct values.
-    */
-   _save_copy_from_current( ctx );
-
-   /* Replay stored vertices to translate them to new format here.
-    *
-    * If there are copied vertices and the new (upgraded) attribute
-    * has not been defined before, this list is somewhat degenerate,
-    * and will need fixup at runtime.
-    */
-   if (tnl->save.copied.nr)
-   {
-      GLfloat *data = tnl->save.copied.buffer;
-      GLfloat *dest = tnl->save.buffer;
-      GLuint j;
-
-      /* Need to note this and fix up at runtime (or loopback):
-       */
-      if (tnl->save.currentsz[attr][0] == 0) {
-        assert(oldsz == 0);
-        tnl->save.dangling_attr_ref = GL_TRUE;
-
-/*      _mesa_debug(NULL, "_save_upgrade_vertex: dangling reference attr %d\n",  */
-/*                  attr);  */
-
-#if 0
-        /* The current strategy is to punt these degenerate cases
-         * through _tnl_loopback_vertex_list(), a lower-performance
-         * option.  To minimize the impact of this, artificially
-         * reduce the size of this vertex_list.
-         */
-        if (t->save.counter > 10) {
-           t->save.initial_counter = 10;
-           t->save.counter = 10;
-        }
-#endif
-      }
-
-      for (i = 0 ; i < tnl->save.copied.nr ; i++) {
-        for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
-           if (tnl->save.attrsz[j]) {
-              if (j == attr) {
-                 if (oldsz) {
-                    COPY_CLEAN_4V( dest, oldsz, data );
-                    data += oldsz;
-                    dest += newsz;
-                 }
-                 else {
-                    COPY_SZ_4V( dest, newsz, tnl->save.current[attr] );
-                    dest += newsz;
-                 }
-              }
-              else {
-                 GLint sz = tnl->save.attrsz[j];
-                 COPY_SZ_4V( dest, sz, data );
-                 data += sz;
-                 dest += sz;
-              }
-           }
-        }
-      }
-
-      tnl->save.vbptr = dest;
-      tnl->save.counter -= tnl->save.copied.nr;
-   }
-}
-
-
-
-
-/* Helper function for 'CHOOSE' macro.  Do what's necessary when an
- * entrypoint is called for the first time.
- */
-static void do_choose( GLuint attr, GLuint sz, 
-                      void (*attr_func)( const GLfloat *),
-                      void (*choose1)( const GLfloat *),
-                      void (*choose2)( const GLfloat *),
-                      void (*choose3)( const GLfloat *),
-                      void (*choose4)( const GLfloat *),
-                      const GLfloat *v )
-{ 
-   GET_CURRENT_CONTEXT( ctx ); 
-   TNLcontext *tnl = TNL_CONTEXT(ctx); 
-   static GLfloat id[4] = { 0, 0, 0, 1 };
-   int i;
-
-   if (tnl->save.attrsz[attr] < sz) {
-      /* New size is larger.  Need to flush existing vertices and get
-       * an enlarged vertex format.
-       */
-      _save_upgrade_vertex( ctx, attr, sz );
-   }
-   else {
-      /* New size is equal or smaller - just need to fill in some
-       * zeros.
-       */
-      for (i = sz ; i <= tnl->save.attrsz[attr] ; i++)
-        tnl->save.attrptr[attr][i-1] = id[i-1];
-   }
-
-   /* Reset any active pointers for this attribute 
-    */
-   tnl->save.tabfv[attr][0] = choose1;
-   tnl->save.tabfv[attr][1] = choose2;
-   tnl->save.tabfv[attr][2] = choose3;
-   tnl->save.tabfv[attr][3] = choose4;
-
-   /* Update the secondary dispatch table with the new function
-    */
-   tnl->save.tabfv[attr][sz-1] = attr_func;
-
-   (*attr_func)(v);
-}
-
-
-
-/* Only one size for each attribute may be active at once.  Eg. if
- * Color3f is installed/active, then Color4f may not be, even if the
- * vertex actually contains 4 color coordinates.  This is because the
- * 3f version won't otherwise set color[3] to 1.0 -- this is the job
- * of the chooser function when switching between Color4f and Color3f.
- */
-#define ATTRFV( ATTR, N )                                      \
-static void save_choose_##ATTR##_##N( const GLfloat *v );      \
-                                                               \
-static void save_attrib_##ATTR##_##N( const GLfloat *v )       \
-{                                                              \
-   GET_CURRENT_CONTEXT( ctx );                                 \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                         \
-                                                               \
-   if ((ATTR) == 0) {                                          \
-      GLuint i;                                                        \
-                                                               \
-      if (N>0) tnl->save.vbptr[0] = v[0];                      \
-      if (N>1) tnl->save.vbptr[1] = v[1];                      \
-      if (N>2) tnl->save.vbptr[2] = v[2];                      \
-      if (N>3) tnl->save.vbptr[3] = v[3];                      \
-                                                               \
-      for (i = N; i < tnl->save.vertex_size; i++)              \
-        tnl->save.vbptr[i] = tnl->save.vertex[i];              \
-                                                               \
-      tnl->save.vbptr += tnl->save.vertex_size;                        \
-                                                               \
-      if (--tnl->save.counter == 0)                            \
-        _save_wrap_filled_vertex( ctx );                       \
-   }                                                           \
-   else {                                                      \
-      GLfloat *dest = tnl->save.attrptr[ATTR];                 \
-      if (N>0) dest[0] = v[0];                                 \
-      if (N>1) dest[1] = v[1];                                 \
-      if (N>2) dest[2] = v[2];                                 \
-      if (N>3) dest[3] = v[3];                                 \
-   }                                                           \
-}
-
-#define CHOOSE( ATTR, N )                                      \
-static void save_choose_##ATTR##_##N( const GLfloat *v )       \
-{                                                              \
-   do_choose(ATTR, N,                                          \
-            save_attrib_##ATTR##_##N,                          \
-            save_choose_##ATTR##_1,                            \
-            save_choose_##ATTR##_2,                            \
-            save_choose_##ATTR##_3,                            \
-            save_choose_##ATTR##_4,                            \
-            v );                                               \
-}
-
-#define INIT(ATTR)                                     \
-static void save_init_##ATTR( TNLcontext *tnl )                \
-{                                                      \
-   tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1;  \
-   tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2;  \
-   tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3;  \
-   tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4;  \
-}
-   
-#define ATTRS( ATTRIB )                                \
-   ATTRFV( ATTRIB, 1 )                         \
-   ATTRFV( ATTRIB, 2 )                         \
-   ATTRFV( ATTRIB, 3 )                         \
-   ATTRFV( ATTRIB, 4 )                         \
-   CHOOSE( ATTRIB, 1 )                         \
-   CHOOSE( ATTRIB, 2 )                         \
-   CHOOSE( ATTRIB, 3 )                         \
-   CHOOSE( ATTRIB, 4 )                         \
-   INIT( ATTRIB )                              \
-
-
-/* Generate a lot of functions.  These are the actual worker
- * functions, which are equivalent to those generated via codegen
- * elsewhere.
- */
-ATTRS( 0 )
-ATTRS( 1 )
-ATTRS( 2 )
-ATTRS( 3 )
-ATTRS( 4 )
-ATTRS( 5 )
-ATTRS( 6 )
-ATTRS( 7 )
-ATTRS( 8 )
-ATTRS( 9 )
-ATTRS( 10 )
-ATTRS( 11 )
-ATTRS( 12 )
-ATTRS( 13 )
-ATTRS( 14 )
-ATTRS( 15 )
-
-ATTRS( 16 )
-ATTRS( 17 )
-ATTRS( 18 )
-ATTRS( 19 )
-ATTRS( 20 )
-ATTRS( 21 )
-ATTRS( 22 )
-ATTRS( 23 )
-ATTRS( 24 )
-ATTRS( 25 )
-ATTRS( 26 )
-ATTRS( 27 )
-ATTRS( 28 )
-ATTRS( 29 )
-ATTRS( 30 )
-ATTRS( 31 )
-
-
-static void _save_reset_vertex( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLuint i;
-
-   /* conventional attributes */
-   save_init_0( tnl );
-   save_init_1( tnl );
-   save_init_2( tnl );
-   save_init_3( tnl );
-   save_init_4( tnl );
-   save_init_5( tnl );
-   save_init_6( tnl );
-   save_init_7( tnl );
-   save_init_8( tnl );
-   save_init_9( tnl );
-   save_init_10( tnl );
-   save_init_11( tnl );
-   save_init_12( tnl );
-   save_init_13( tnl );
-   save_init_14( tnl );
-   save_init_15( tnl );
-
-   /* generic attributes */
-   save_init_16( tnl );
-   save_init_17( tnl );
-   save_init_18( tnl );
-   save_init_19( tnl );
-   save_init_20( tnl );
-   save_init_21( tnl );
-   save_init_22( tnl );
-   save_init_23( tnl );
-   save_init_24( tnl );
-   save_init_25( tnl );
-   save_init_26( tnl );
-   save_init_27( tnl );
-   save_init_28( tnl );
-   save_init_29( tnl );
-   save_init_30( tnl );
-   save_init_31( tnl );
-      
-   for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
-      tnl->save.attrsz[i] = 0;
-      
-   tnl->save.vertex_size = 0;
-   tnl->save.have_materials = 0;
-
-   _save_reset_counters( ctx ); 
-}
-
-
-
-/* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
- * of glMultTexCoord and glProgramParamterNV by routing all these
- * through a second level dispatch table.
- */
-#define DISPATCH_ATTRFV( ATTR, COUNT, P )      \
-do {                                           \
-   GET_CURRENT_CONTEXT( ctx );                         \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
-   tnl->save.tabfv[ATTR][COUNT-1]( P );                \
-} while (0)
-
-#define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
-#define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
-#define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
-#define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
-
-#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
-
-#if defined(USE_X86_ASM) && 0 /* will break register calling convention */
-/* Naughty cheat:
- */
-#define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
-#define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
-#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
-#else
-/* Safe:
- */
-#define DISPATCH_ATTR2F( ATTR, S,T )           \
-do {                                           \
-   GLfloat v[2];                               \
-   v[0] = S; v[1] = T;                         \
-   DISPATCH_ATTR2FV( ATTR, v );                        \
-} while (0)
-#define DISPATCH_ATTR3F( ATTR, S,T,R )                 \
-do {                                           \
-   GLfloat v[3];                               \
-   v[0] = S; v[1] = T; v[2] = R;               \
-   DISPATCH_ATTR3FV( ATTR, v );                        \
-} while (0)
-#define DISPATCH_ATTR4F( ATTR, S,T,R,Q )       \
-do {                                           \
-   GLfloat v[4];                               \
-   v[0] = S; v[1] = T; v[2] = R; v[3] = Q;     \
-   DISPATCH_ATTR4FV( ATTR, v );                        \
-} while (0)
-#endif
-
-
-static void enum_error( void )
-{
-   GET_CURRENT_CONTEXT( ctx );
-   _mesa_compile_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
-}
-
-static void GLAPIENTRY _save_Vertex2f( GLfloat x, GLfloat y )
-{
-   DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
-}
-
-static void GLAPIENTRY _save_Vertex2fv( const GLfloat *v )
-{
-   DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
-}
-
-static void GLAPIENTRY _save_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
-}
-
-static void GLAPIENTRY _save_Vertex3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
-}
-
-static void GLAPIENTRY _save_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
-{
-   DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
-}
-
-static void GLAPIENTRY _save_Vertex4fv( const GLfloat *v )
-{
-   DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
-}
-
-static void GLAPIENTRY _save_TexCoord1f( GLfloat x )
-{
-   DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
-}
-
-static void GLAPIENTRY _save_TexCoord1fv( const GLfloat *v )
-{
-   DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
-}
-
-static void GLAPIENTRY _save_TexCoord2f( GLfloat x, GLfloat y )
-{
-   DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
-}
-
-static void GLAPIENTRY _save_TexCoord2fv( const GLfloat *v )
-{
-   DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
-}
-
-static void GLAPIENTRY _save_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
-}
-
-static void GLAPIENTRY _save_TexCoord3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
-}
-
-static void GLAPIENTRY _save_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
-{
-   DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
-}
-
-static void GLAPIENTRY _save_TexCoord4fv( const GLfloat *v )
-{
-   DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
-}
-
-static void GLAPIENTRY _save_Normal3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
-}
-
-static void GLAPIENTRY _save_Normal3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
-}
-
-static void GLAPIENTRY _save_FogCoordfEXT( GLfloat x )
-{
-   DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
-}
-
-static void GLAPIENTRY _save_FogCoordfvEXT( const GLfloat *v )
-{
-   DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
-}
-
-static void GLAPIENTRY _save_Color3f( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
-}
-
-static void GLAPIENTRY _save_Color3fv( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
-}
-
-static void GLAPIENTRY _save_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
-{
-   DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
-}
-
-static void GLAPIENTRY _save_Color4fv( const GLfloat *v )
-{
-   DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
-}
-
-static void GLAPIENTRY _save_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
-{
-   DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
-}
-
-static void GLAPIENTRY _save_SecondaryColor3fvEXT( const GLfloat *v )
-{
-   DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord1f( GLenum target, GLfloat x  )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR1F( attr, x );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord1fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR1FV( attr, v );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR2F( attr, x, y );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord2fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR2FV( attr, v );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
-                                   GLfloat z)
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR3F( attr, x, y, z );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord3fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR3FV( attr, v );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
-                                   GLfloat z, GLfloat w )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR4F( attr, x, y, z, w );
-}
-
-static void GLAPIENTRY _save_MultiTexCoord4fv( GLenum target, const GLfloat *v )
-{
-   GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
-   DISPATCH_ATTR4FV( attr, v );
-}
-
-
-
-static void GLAPIENTRY
-_save_VertexAttrib1fNV(GLuint index, GLfloat x)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR1F( index, x );
-   }
-   else
-      enum_error(); 
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib1fvNV(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR1FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib2fNV(GLuint index, GLfloat x, GLfloat y)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR2F( index, x, y );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib2fvNV(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR2FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib3fNV(GLuint index, GLfloat x, GLfloat y, GLfloat z)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR3F( index, x, y, z );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib3fvNV(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR3FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib4fNV(GLuint index, GLfloat x, GLfloat y,
-                       GLfloat z, GLfloat w)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR4F( index, x, y, z, w );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib4fvNV(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR4FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib1fARB(GLuint index, GLfloat x)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR1F( index, x );
-   }
-   else
-      enum_error(); 
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib1fvARB(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR1FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib2fARB(GLuint index, GLfloat x, GLfloat y)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR2F( index, x, y );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib2fvARB(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR2FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib3fARB(GLuint index, GLfloat x, GLfloat y, GLfloat z)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR3F( index, x, y, z );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib3fvARB(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR3FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib4fARB(GLuint index, GLfloat x, GLfloat y,
-                        GLfloat z, GLfloat w)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR4F( index, x, y, z, w );
-   }
-   else
-      enum_error();
-}
-
-static void GLAPIENTRY
-_save_VertexAttrib4fvARB(GLuint index, const GLfloat *v)
-{
-   if (index < MAX_VERTEX_ATTRIBS) {
-      if (index > 0)
-         index += VERT_ATTRIB_GENERIC0;
-      DISPATCH_ATTR4FV( index, v );
-   }
-   else
-      enum_error();
-}
-
-
-/* Materials:  
- * 
- * These are treated as per-vertex attributes, at indices above where
- * the NV_vertex_program leaves off.  There are a lot of good things
- * about treating materials this way.  
- *
- * However: I don't want to double the number of generated functions
- * just to cope with this, so I unroll the 'C' varients of CHOOSE and
- * ATTRF into this function, and dispense with codegen and
- * second-level dispatch.
- *
- * There is no aliasing of material attributes with other entrypoints.
- */
-#define MAT_ATTR( A, N, params )                       \
-do {                                                   \
-   if (tnl->save.attrsz[A] < N) {                      \
-      _save_upgrade_vertex( ctx, A, N );               \
-      tnl->save.have_materials = GL_TRUE;               \
-   }                                                   \
-                                                       \
-   {                                                   \
-      GLfloat *dest = tnl->save.attrptr[A];            \
-      if (N>0) dest[0] = params[0];                    \
-      if (N>1) dest[1] = params[1];                    \
-      if (N>2) dest[2] = params[2];                    \
-      if (N>3) dest[3] = params[3];                    \
-   }                                                   \
-} while (0)
-
-
-#define MAT( ATTR, N, face, params )                   \
-do {                                                   \
-   if (face != GL_BACK)                                        \
-      MAT_ATTR( ATTR, N, params ); /* front */         \
-   if (face != GL_FRONT)                               \
-      MAT_ATTR( ATTR + 1, N, params ); /* back */      \
-} while (0)
-
-
-/* NOTE: Have to remove/deal-with colormaterial crossovers, probably
- * later on - in the meantime just store everything.  
- */
-static void GLAPIENTRY _save_Materialfv( GLenum face, GLenum pname, 
-                              const GLfloat *params )
-{
-   GET_CURRENT_CONTEXT( ctx ); 
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-
-   switch (pname) {
-   case GL_EMISSION:
-      MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
-      break;
-   case GL_AMBIENT:
-      MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
-      break;
-   case GL_DIFFUSE:
-      MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
-      break;
-   case GL_SPECULAR:
-      MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
-      break;
-   case GL_SHININESS:
-      MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
-      break;
-   case GL_COLOR_INDEXES:
-      MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
-      break;
-   case GL_AMBIENT_AND_DIFFUSE:
-      MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
-      MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
-      break;
-   default:
-      _mesa_compile_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
-      return;
-   }
-}
-
-
-#define IDX_ATTR( A, IDX )                             \
-do {                                                   \
-   GET_CURRENT_CONTEXT( ctx );                         \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                 \
-                                                       \
-   if (tnl->save.attrsz[A] < 1) {                      \
-      _save_upgrade_vertex( ctx, A, 1 );               \
-   }                                                   \
-                                                       \
-   {                                                   \
-      GLfloat *dest = tnl->save.attrptr[A];            \
-      dest[0] = IDX;                           \
-   }                                                   \
-} while (0)
-
-
-static void GLAPIENTRY _save_EdgeFlag( GLboolean b )
-{
-   IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
-}
-
-
-static void GLAPIENTRY _save_Indexf( GLfloat f )
-{
-   IDX_ATTR( _TNL_ATTRIB_COLOR_INDEX, f );
-}
-
-static void GLAPIENTRY _save_Indexfv( const GLfloat *f )
-{
-   IDX_ATTR( _TNL_ATTRIB_COLOR_INDEX, f[0] );
-}
-
-
-
-
-/* Cope with EvalCoord/CallList called within a begin/end object:
- *     -- Flush current buffer
- *     -- Fallback to opcodes for the rest of the begin/end object.
- */
-#define FALLBACK(ctx)                                                  \
-do {                                                                   \
-   TNLcontext *tnl = TNL_CONTEXT(ctx);                                 \
-                                                                       \
-   if (tnl->save.initial_counter != tnl->save.counter ||               \
-       tnl->save.prim_count)                                           \
-      _save_compile_vertex_list( ctx );                                        \
-                                                                       \
-   _save_copy_to_current( ctx );                                       \
-   _save_reset_vertex( ctx );                                          \
-   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );       \
-   ctx->Driver.SaveNeedFlush = 0;                                      \
-} while (0)
-
-static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_EvalCoord1f(ctx->Save, ( u ));
-}
-
-static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_EvalCoord1fv(ctx->Save, ( v ));
-}
-
-static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_EvalCoord2f(ctx->Save, ( u, v ));
-}
-
-static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_EvalCoord2fv(ctx->Save, ( v ));
-}
-
-static void GLAPIENTRY _save_EvalPoint1( GLint i )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_EvalPoint1(ctx->Save, ( i ));
-}
-
-static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_EvalPoint2(ctx->Save, ( i, j ));
-}
-
-static void GLAPIENTRY _save_CallList( GLuint l )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_CallList(ctx->Save, ( l ));
-}
-
-static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   FALLBACK(ctx);
-   CALL_CallLists(ctx->Save, ( n, type, v ));
-}
-
-
-
-
-/**
- * Called via ctx->Driver.NotifySaveBegin(ctx, mode) when we get a
- * glBegin() call while compiling a display list.
- * See save_Begin() in dlist.c
- *
- * This plugs in our special TNL-related display list functions.
- * All subsequent glBegin/glVertex/glEnd()s found while compiling a
- * display list will get routed to the functions in this file.
- *
- * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
- */
-static GLboolean _save_NotifyBegin( GLcontext *ctx, GLenum mode )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx); 
-
-   if (1) {
-      GLuint i = tnl->save.prim_count++;
-
-      assert(i < tnl->save.prim_max);
-      tnl->save.prim[i].mode = mode | PRIM_BEGIN;
-      tnl->save.prim[i].start = tnl->save.initial_counter - tnl->save.counter;
-      tnl->save.prim[i].count = 0;   
-
-      _mesa_install_save_vtxfmt( ctx, &tnl->save_vtxfmt );      
-      ctx->Driver.SaveNeedFlush = 1;
-      return GL_TRUE;
-   }
-   else 
-      return GL_FALSE;
-}
-
-
-
-static void GLAPIENTRY _save_End( void )
-{
-   GET_CURRENT_CONTEXT( ctx ); 
-   TNLcontext *tnl = TNL_CONTEXT(ctx); 
-   GLint i = tnl->save.prim_count - 1;
-
-   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
-   if (ctx->ExecuteFlag)
-      ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
-
-   tnl->save.prim[i].mode |= PRIM_END;
-   tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) - 
-                             tnl->save.prim[i].start);
-
-   if (i == (GLint) tnl->save.prim_max - 1) {
-      _save_compile_vertex_list( ctx );
-      assert(tnl->save.copied.nr == 0);
-   }
-
-   /* Swap out this vertex format while outside begin/end.  Any color,
-    * etc. received between here and the next begin will be compiled
-    * as opcodes.
-    */   
-   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
-}
-
-
-/* These are all errors as this vtxfmt is only installed inside
- * begin/end pairs.
- */
-static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
-                              const GLvoid *indices)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   (void) mode; (void) count; (void) type; (void) indices;
-   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
-}
-
-
-static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
-                                   GLuint start, GLuint end,
-                                   GLsizei count, GLenum type,
-                                   const GLvoid *indices)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
-   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
-}
-
-static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   (void) mode; (void) start; (void) count;
-   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
-}
-
-static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   (void) x1; (void) y1; (void) x2; (void) y2;
-   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
-}
-
-static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   (void) mode; (void) i1; (void) i2;
-   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
-}
-
-static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
-                                 GLint j1, GLint j2 )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
-   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
-}
-
-/**
- * This is only called if someone tries to compile nested glBegin()s 
- * in their display list.
- */
-static void GLAPIENTRY _save_Begin( GLenum mode )
-{
-   GET_CURRENT_CONTEXT( ctx );
-   (void) mode;
-   _mesa_compile_error(ctx, GL_INVALID_OPERATION,
-                       "glBegin(called inside glBegin/End)");
-}
-
-
-/* Unlike the functions above, these are to be hooked into the vtxfmt
- * maintained in ctx->ListState, active when the list is known or
- * suspected to be outside any begin/end primitive.
- */
-static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
-{
-   GET_CURRENT_CONTEXT(ctx);
-   _save_NotifyBegin( ctx, GL_QUADS | PRIM_WEAK );
-   CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
-   CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
-   CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
-   CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
-   CALL_End(GET_DISPATCH(), ());
-}
-
-
-static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   GLint i;
-
-   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
-      return;
-
-   _ae_map_vbos( ctx );
-
-   _save_NotifyBegin( ctx, mode | PRIM_WEAK );
-   for (i = 0; i < count; i++)
-       CALL_ArrayElement(GET_DISPATCH(), (start + i));
-   CALL_End(GET_DISPATCH(), ());
-
-   _ae_unmap_vbos( ctx );
-}
-
-
-static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
-                                  const GLvoid *indices)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   GLint i;
-
-   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
-      return;
-
-   _ae_map_vbos( ctx );
-
-   _save_NotifyBegin( ctx, mode | PRIM_WEAK );
-
-   switch (type) {
-   case GL_UNSIGNED_BYTE:
-      for (i = 0 ; i < count ; i++)
-         CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
-      break;
-   case GL_UNSIGNED_SHORT:
-      for (i = 0 ; i < count ; i++)
-         CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
-      break;
-   case GL_UNSIGNED_INT:
-      for (i = 0 ; i < count ; i++)
-         CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
-      break;
-   default:
-      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
-      break;
-   }
-
-   CALL_End(GET_DISPATCH(), ());
-
-   _ae_unmap_vbos( ctx );
-}
-
-static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
-                                       GLuint start, GLuint end,
-                                       GLsizei count, GLenum type,
-                                       const GLvoid *indices)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   if (_mesa_validate_DrawRangeElements( ctx, mode,
-                                        start, end,
-                                        count, type, indices ))
-      _save_OBE_DrawElements( mode, count, type, indices );
-}
-
-
-
-
-
-static void _save_vtxfmt_init( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLvertexformat *vfmt = &tnl->save_vtxfmt;
-
-   vfmt->ArrayElement = _ae_loopback_array_elt;                /* generic helper */
-   vfmt->Begin = _save_Begin;
-   vfmt->Color3f = _save_Color3f;
-   vfmt->Color3fv = _save_Color3fv;
-   vfmt->Color4f = _save_Color4f;
-   vfmt->Color4fv = _save_Color4fv;
-   vfmt->EdgeFlag = _save_EdgeFlag;
-   vfmt->End = _save_End;
-   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
-   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
-   vfmt->Indexf = _save_Indexf;
-   vfmt->Indexfv = _save_Indexfv;
-   vfmt->Materialfv = _save_Materialfv;
-   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
-   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
-   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
-   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
-   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
-   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
-   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
-   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
-   vfmt->Normal3f = _save_Normal3f;
-   vfmt->Normal3fv = _save_Normal3fv;
-   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
-   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
-   vfmt->TexCoord1f = _save_TexCoord1f;
-   vfmt->TexCoord1fv = _save_TexCoord1fv;
-   vfmt->TexCoord2f = _save_TexCoord2f;
-   vfmt->TexCoord2fv = _save_TexCoord2fv;
-   vfmt->TexCoord3f = _save_TexCoord3f;
-   vfmt->TexCoord3fv = _save_TexCoord3fv;
-   vfmt->TexCoord4f = _save_TexCoord4f;
-   vfmt->TexCoord4fv = _save_TexCoord4fv;
-   vfmt->Vertex2f = _save_Vertex2f;
-   vfmt->Vertex2fv = _save_Vertex2fv;
-   vfmt->Vertex3f = _save_Vertex3f;
-   vfmt->Vertex3fv = _save_Vertex3fv;
-   vfmt->Vertex4f = _save_Vertex4f;
-   vfmt->Vertex4fv = _save_Vertex4fv;
-   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
-   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
-   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
-   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
-   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
-   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
-   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
-   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
-   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
-   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
-   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
-   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
-   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
-   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
-   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
-   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
-   
-   /* This will all require us to fallback to saving the list as opcodes:
-    */ 
-   vfmt->CallList = _save_CallList; /* inside begin/end */
-   vfmt->CallLists = _save_CallLists; /* inside begin/end */
-   vfmt->EvalCoord1f = _save_EvalCoord1f;
-   vfmt->EvalCoord1fv = _save_EvalCoord1fv;
-   vfmt->EvalCoord2f = _save_EvalCoord2f;
-   vfmt->EvalCoord2fv = _save_EvalCoord2fv;
-   vfmt->EvalPoint1 = _save_EvalPoint1;
-   vfmt->EvalPoint2 = _save_EvalPoint2;
-
-   /* These are all errors as we at least know we are in some sort of
-    * begin/end pair:
-    */
-   vfmt->EvalMesh1 = _save_EvalMesh1;  
-   vfmt->EvalMesh2 = _save_EvalMesh2;
-   vfmt->Begin = _save_Begin;
-   vfmt->Rectf = _save_Rectf;
-   vfmt->DrawArrays = _save_DrawArrays;
-   vfmt->DrawElements = _save_DrawElements;
-   vfmt->DrawRangeElements = _save_DrawRangeElements;
-
-}
-
-
-void _tnl_SaveFlushVertices( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-
-   /* Noop when we are actually active:
-    */
-   if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
-       ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
-      return;
-
-   if (tnl->save.initial_counter != tnl->save.counter ||
-       tnl->save.prim_count) 
-      _save_compile_vertex_list( ctx );
-   
-   _save_copy_to_current( ctx );
-   _save_reset_vertex( ctx );
-   ctx->Driver.SaveNeedFlush = 0;
-}
-
-void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-
-   (void) list; (void) mode;
-
-   if (!tnl->save.prim_store)
-      tnl->save.prim_store = alloc_prim_store( ctx );
-
-   if (!tnl->save.vertex_store) {
-      tnl->save.vertex_store = alloc_vertex_store( ctx );
-      tnl->save.vbptr = tnl->save.vertex_store->buffer;
-   }
-   
-   _save_reset_vertex( ctx );
-   ctx->Driver.SaveNeedFlush = 0;
-}
-
-void _tnl_EndList( GLcontext *ctx )
-{
-   (void) ctx;
-   assert(TNL_CONTEXT(ctx)->save.vertex_size == 0);
-}
-void _tnl_BeginCallList( GLcontext *ctx, struct mesa_display_list *dlist )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   tnl->save.replay_flags |= dlist->flags;
-   tnl->save.replay_flags |= tnl->LoopbackDListCassettes;
-}
-
-void _tnl_EndCallList( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   
-   if (ctx->ListState.CallDepth == 1)
-      tnl->save.replay_flags = 0;
-}
-
-
-static void _tnl_destroy_vertex_list( GLcontext *ctx, void *data )
-{
-   struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
-   (void) ctx;
-
-   if ( --node->vertex_store->refcount == 0 )
-      FREE( node->vertex_store );
-
-   if ( --node->prim_store->refcount == 0 )
-      FREE( node->prim_store );
-
-   if ( node->normal_lengths )
-      FREE( node->normal_lengths );
-}
-
-
-static void _tnl_print_vertex_list( GLcontext *ctx, void *data )
-{
-   struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
-   GLuint i;
-   (void) ctx;
-
-   _mesa_debug(NULL, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
-               node->count,
-              node->prim_count,
-              node->vertex_size);
-
-   for (i = 0 ; i < node->prim_count ; i++) {
-      struct tnl_prim *prim = &node->prim[i];
-      _mesa_debug(NULL, "   prim %d: %s %d..%d %s %s\n",
-                 i, 
-                 _mesa_lookup_enum_by_nr(prim->mode & PRIM_MODE_MASK),
-                 prim->start, 
-                 prim->start + prim->count,
-                 (prim->mode & PRIM_BEGIN) ? "BEGIN" : "(wrap)",
-                 (prim->mode & PRIM_END) ? "END" : "(wrap)");
-   }
-}
-
-
-static void _save_current_init( GLcontext *ctx ) 
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   GLint i;
-
-   for (i = 0; i < _TNL_ATTRIB_MAT_FRONT_AMBIENT; i++) {
-      ASSERT(i < VERT_ATTRIB_MAX);
-      tnl->save.currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
-      tnl->save.current[i] = ctx->ListState.CurrentAttrib[i];
-   }
-
-   for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) {
-      const GLuint j = i - _TNL_FIRST_MAT;
-      ASSERT(j < MAT_ATTRIB_MAX);
-      tnl->save.currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
-      tnl->save.current[i] = ctx->ListState.CurrentMaterial[j];
-   }
-
-   tnl->save.currentsz[_TNL_ATTRIB_EDGEFLAG] = &ctx->ListState.ActiveEdgeFlag;
-   tnl->save.current[_TNL_ATTRIB_EDGEFLAG] = &tnl->save.CurrentFloatEdgeFlag;
-}
-
-/**
- * Initialize the display list compiler
- */
-void _tnl_save_init( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct tnl_vertex_arrays *tmp = &tnl->save_inputs;
-   GLuint i;
-
-
-   for (i = 0; i < _TNL_ATTRIB_MAX; i++)
-      _mesa_vector4f_init( &tmp->Attribs[i], 0, NULL);
-
-   tnl->save.opcode_vertex_list =
-      _mesa_alloc_opcode( ctx,
-                         sizeof(struct tnl_vertex_list),
-                         _tnl_playback_vertex_list,
-                         _tnl_destroy_vertex_list,
-                         _tnl_print_vertex_list );
-
-   ctx->Driver.NotifySaveBegin = _save_NotifyBegin;
-
-   _save_vtxfmt_init( ctx );
-   _save_current_init( ctx );
-
-   /* Hook our array functions into the outside-begin-end vtxfmt in 
-    * ctx->ListState.
-    */
-   ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
-   ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
-   ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
-   ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
-   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
-}
-
-
-/**
- * Deallocate the immediate-mode buffer for the given context, if
- * its reference count goes to zero.
- */
-void _tnl_save_destroy( GLcontext *ctx )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-
-   /* Decrement the refcounts.  References may still be held by
-    * display lists yet to be destroyed, so it may not yet be time to
-    * free these items.
-    */
-   if (tnl->save.prim_store &&
-       --tnl->save.prim_store->refcount == 0 )
-      FREE( tnl->save.prim_store );
-
-   if (tnl->save.vertex_store &&
-       --tnl->save.vertex_store->refcount == 0 )
-      FREE( tnl->save.vertex_store );
-}