Merge branch 'mesa_7_7_branch'
[mesa.git] / src / mesa / tnl_dd / t_dd_dmatmp.h
index 10ff1df5f0bdbb6fa0f461f326932e518901d575..e5885782c7a053a6c284a2b66af5554766165cf4 100644 (file)
@@ -1,9 +1,8 @@
-
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  6.5.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  Brian Paul   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"),
@@ -27,7 +26,9 @@
  */
 
 
-/* Template for render stages which build and emit vertices directly
+/**
+ * \file t_dd_dmatmp.h
+ * Template for render stages which build and emit vertices directly
  * to fixed-size dma buffers.  Useful for rendering strips and other
  * native primitives where clipping and per-vertex tweaks such as
  * those in t_dd_tritmp.h are not required.
@@ -36,8 +37,6 @@
  * Where various primitive types are unaccelerated by hardware, the
  * code attempts to fallback to other primitive types (quadstrips to
  * tristrips, lineloops to linestrips), or to indexed vertices.
- * Ultimately, a FALLBACK() macro is invoked if there is no way to
- * render the primitive natively.
  */
 
 #if !defined(HAVE_TRIANGLES)
 #endif
 
 #if !HAVE_ELTS
-#define ELTS_VARS
-#define ALLOC_ELTS( nr )
+#define ELTS_VARS(buf)
+#define ALLOC_ELTS(nr) 0
 #define EMIT_ELT( offset, elt )
 #define EMIT_TWO_ELTS( offset, elt0, elt1 )
 #define INCR_ELTS( nr )
 #define ELT_INIT(prim)
 #define GET_CURRENT_VB_MAX_ELTS() 0
 #define GET_SUBSEQUENT_VB_MAX_ELTS() 0
-#define ALLOC_ELTS_NEW_PRIMITIVE(nr)
 #define RELEASE_ELT_VERTS()
 #define EMIT_INDEXED_VERTS( ctx, start, count )
 #endif
@@ -66,9 +64,6 @@ do {                                          \
 } while (0)
 #endif
 
-#ifndef FINISH
-#define FINISH
-#endif
 
 /**********************************************************************/
 /*                  Render whole begin/end objects                    */
@@ -76,49 +71,39 @@ do {                                                \
 
 
 
-static GLboolean TAG(emit_elt_verts)( GLcontext *ctx,
-                                     GLuint start, GLuint count )
-{
-   if (HAVE_ELTS) {
-      LOCAL_VARS;
-      GLuint nr = count - start;
-
-      if ( nr >= GET_SUBSEQUENT_VB_MAX_VERTS() ) /* assumes same packing for
-                                                 * indexed and regualar verts
-                                                 */
-        return GL_FALSE;
-
-      NEW_PRIMITIVE(); /* finish last prim */
-      EMIT_INDEXED_VERTS( ctx, start, count );
-      return GL_TRUE;
-   } else {
-      return GL_FALSE;
-   }
-}
 
 #if (HAVE_ELTS)
-static void TAG(emit_elts)( GLcontext *ctx, GLuint *elts, GLuint nr )
+static void *TAG(emit_elts)( GLcontext *ctx, GLuint *elts, GLuint nr,
+                            void *buf)
 {
    GLint i;
    LOCAL_VARS;
-   ELTS_VARS;
+   ELTS_VARS(buf);
 
-   ALLOC_ELTS( nr );
-
-   for ( i = 0 ; i < nr ; i+=2, elts += 2 ) {
+   for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
       EMIT_TWO_ELTS( 0, elts[0], elts[1] );
       INCR_ELTS( 2 );
    }
+   
+   if (i < nr) {
+      EMIT_ELT( 0, elts[0] );
+      INCR_ELTS( 1 );
+   }
+
+   return (void *)ELTPTR;
 }
 #endif
 
+static __inline void *TAG(emit_verts)( GLcontext *ctx, GLuint start, 
+                                    GLuint count, void *buf )
+{
+   return EMIT_VERTS(ctx, start, count, buf);
+}
 
 /***********************************************************************
  *                    Render non-indexed primitives.
  ***********************************************************************/
 
-
-
 static void TAG(render_points_verts)( GLcontext *ctx,
                                      GLuint start,
                                      GLuint count,
@@ -127,24 +112,24 @@ static void TAG(render_points_verts)( GLcontext *ctx,
    if (HAVE_POINTS) {
       LOCAL_VARS;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
       GLuint j, nr;
 
       INIT( GL_POINTS );
 
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       if (currentsz < 8)
         currentsz = dmasz;
 
       for (j = start; j < count; j += nr ) {
         nr = MIN2( currentsz, count - j );
-        EMIT_VERTS( ctx, j, nr );
+        TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
         currentsz = dmasz;
       }
 
-      FINISH;
-
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -156,7 +141,7 @@ static void TAG(render_lines_verts)( GLcontext *ctx,
    if (HAVE_LINES) {
       LOCAL_VARS;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
       GLuint j, nr;
 
       INIT( GL_LINES );
@@ -164,6 +149,7 @@ static void TAG(render_lines_verts)( GLcontext *ctx,
       /* Emit whole number of lines in total and in each buffer:
        */
       count -= (count-start) & 1;
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       currentsz -= currentsz & 1;
       dmasz -= dmasz & 1;
 
@@ -172,14 +158,13 @@ static void TAG(render_lines_verts)( GLcontext *ctx,
 
       for (j = start; j < count; j += nr ) {
         nr = MIN2( currentsz, count - j );
-        EMIT_VERTS( ctx, j, nr );
+        TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
         currentsz = dmasz;
       }
 
-      FINISH;
-
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -192,25 +177,26 @@ static void TAG(render_line_strip_verts)( GLcontext *ctx,
    if (HAVE_LINE_STRIPS) {
       LOCAL_VARS;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
       GLuint j, nr;
 
-      NEW_PRIMITIVE(); /* always a new primitive */
       INIT( GL_LINE_STRIP );
 
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       if (currentsz < 8)
         currentsz = dmasz;
 
       for (j = start; j + 1 < count; j += nr - 1 ) {
         nr = MIN2( currentsz, count - j );
-        EMIT_VERTS( ctx, j, nr );
+        TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
         currentsz = dmasz;
       }
  
-      FINISH;
+      FLUSH();
 
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -223,10 +209,9 @@ static void TAG(render_line_loop_verts)( GLcontext *ctx,
    if (HAVE_LINE_STRIPS) {
       LOCAL_VARS;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
       GLuint j, nr;
 
-      NEW_PRIMITIVE();
       INIT( GL_LINE_STRIP );
 
       if (flags & PRIM_BEGIN)
@@ -236,33 +221,46 @@ static void TAG(render_line_loop_verts)( GLcontext *ctx,
 
       /* Ensure last vertex won't wrap buffers:
        */
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       currentsz--;
       dmasz--;
 
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
       if (j + 1 < count) {
         for ( ; j + 1 < count; j += nr - 1 ) {
            nr = MIN2( currentsz, count - j );
-           EMIT_VERTS( ctx, j, nr );
-           currentsz = dmasz;
+
+           if (j + nr >= count &&
+               start < count - 1 && 
+               (flags & PRIM_END)) 
+           {
+              void *tmp;
+              tmp = ALLOC_VERTS(nr+1);
+              tmp = TAG(emit_verts)( ctx, j, nr, tmp );
+              tmp = TAG(emit_verts)( ctx, start, 1, tmp );
+           }
+           else {
+              TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
+              currentsz = dmasz;
+           }
         }
 
-        if (start < count - 1 && (flags & PRIM_END))
-           EMIT_VERTS( ctx, start, 1 );
       }
       else if (start + 1 < count && (flags & PRIM_END)) {
-        EMIT_VERTS( ctx, start+1, 1 );
-        EMIT_VERTS( ctx, start, 1 );
+        void *tmp;
+        tmp = ALLOC_VERTS(2);
+        tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
+        tmp = TAG(emit_verts)( ctx, start, 1, tmp );
       }
 
-      FINISH;
+      FLUSH();
 
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -274,11 +272,13 @@ static void TAG(render_triangles_verts)( GLcontext *ctx,
 {
    LOCAL_VARS;
    int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
-   int currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
+   int currentsz;
    GLuint j, nr;
 
    INIT(GL_TRIANGLES);
 
+   currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
+
    /* Emit whole number of tris in total.  dmasz is already a multiple
     * of 3.
     */
@@ -289,10 +289,9 @@ static void TAG(render_triangles_verts)( GLcontext *ctx,
 
    for (j = start; j < count; j += nr) {
       nr = MIN2( currentsz, count - j );
-      EMIT_VERTS( ctx, j, nr );
+      TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
       currentsz = dmasz;
    }
-   FINISH;
 }
 
 
@@ -309,12 +308,10 @@ static void TAG(render_tri_strip_verts)( GLcontext *ctx,
       int currentsz;
 
       INIT(GL_TRIANGLE_STRIP);
-      NEW_PRIMITIVE();
 
       currentsz = GET_CURRENT_VB_MAX_VERTS();
 
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
@@ -325,14 +322,15 @@ static void TAG(render_tri_strip_verts)( GLcontext *ctx,
 
       for (j = start ; j + 2 < count; j += nr - 2 ) {
         nr = MIN2( currentsz, count - j );
-        EMIT_VERTS( ctx, j, nr );
+        TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
         currentsz = dmasz;
       }
 
-      FINISH;
+      FLUSH();
 
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -345,31 +343,32 @@ static void TAG(render_tri_fan_verts)( GLcontext *ctx,
       LOCAL_VARS;
       GLuint j, nr;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
 
-      NEW_PRIMITIVE();
       INIT(GL_TRIANGLE_FAN);
 
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
-      for (j = start + 1 ; j + 1 < count; j += nr - 1 ) {
+      for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
+        void *tmp;
         nr = MIN2( currentsz, count - j + 1 );
-        EMIT_VERTS( ctx, start, 1 );
-        EMIT_VERTS( ctx, j, nr - 1 );
+        tmp = ALLOC_VERTS( nr );
+        tmp = TAG(emit_verts)( ctx, start, 1, tmp );
+        tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp );
         currentsz = dmasz;
       }
 
-      FINISH;
-
+      FLUSH();
    }
    else {
       /* Could write code to emit these as indexed vertices (for the
        * g400, for instance).
        */
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -383,30 +382,31 @@ static void TAG(render_poly_verts)( GLcontext *ctx,
       LOCAL_VARS;
       GLuint j, nr;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
 
-      NEW_PRIMITIVE();
       INIT(GL_POLYGON);
 
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
-      for (j = start + 1 ; j + 1 < count ; j += nr - 1 ) {
+      for (j = start + 1 ; j + 1 < count ; j += nr - 2 ) {
+        void *tmp;
         nr = MIN2( currentsz, count - j + 1 );
-        EMIT_VERTS( ctx, start, 1 );
-        EMIT_VERTS( ctx, j, nr - 1 );
+        tmp = ALLOC_VERTS( nr );
+        tmp = TAG(emit_verts)( ctx, start, 1, tmp );
+        tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp );
         currentsz = dmasz;
       }
 
-      FINISH;
-
+      FLUSH();
    }
-   else if (HAVE_TRI_FANS && !(ctx->_TriangleCaps & DD_FLATSHADE)) {
+   else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
       TAG(render_tri_fan_verts)( ctx, start, count, flags );
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -424,12 +424,9 @@ static void TAG(render_quad_strip_verts)( GLcontext *ctx,
       int currentsz;
 
       INIT(GL_QUAD_STRIP);
-      NEW_PRIMITIVE();
 
       currentsz = GET_CURRENT_VB_MAX_VERTS();
-
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
@@ -438,22 +435,25 @@ static void TAG(render_quad_strip_verts)( GLcontext *ctx,
 
       for (j = start ; j + 3 < count; j += nr - 2 ) {
         nr = MIN2( currentsz, count - j );
-        EMIT_VERTS( ctx, j, nr );
+        TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
         currentsz = dmasz;
       }
 
-      FINISH;
+      FLUSH();
 
-   } else if (HAVE_TRI_STRIPS && (ctx->_TriangleCaps & DD_FLATSHADE)) {
-      if (TAG(emit_elt_verts)( ctx, start, count )) {
+   } else if (HAVE_TRI_STRIPS && 
+             ctx->Light.ShadeModel == GL_FLAT &&
+             TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) {
+      if (HAVE_ELTS) {
         LOCAL_VARS;
         int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
         int currentsz;
         GLuint j, nr;
 
+         EMIT_INDEXED_VERTS( ctx, start, count );
+
         /* Simulate flat-shaded quadstrips using indexed vertices:
          */
-        NEW_PRIMITIVE();
         ELT_INIT( GL_TRIANGLES );
 
         currentsz = GET_CURRENT_VB_MAX_ELTS();
@@ -475,10 +475,7 @@ static void TAG(render_quad_strip_verts)( GLcontext *ctx,
            if (nr >= 4) {
               GLint quads = (nr/2)-1;
               GLint i;
-              ELTS_VARS;
-
-              NEW_PRIMITIVE();
-              ALLOC_ELTS_NEW_PRIMITIVE( quads*6 );
+              ELTS_VARS( ALLOC_ELTS( quads*6 ) );
 
               for ( i = j-start ; i < j-start+quads*2 ; i+=2 ) {
                  EMIT_TWO_ELTS( 0, (i+0), (i+1) );
@@ -487,51 +484,54 @@ static void TAG(render_quad_strip_verts)( GLcontext *ctx,
                  INCR_ELTS( 6 );
               }
 
-              NEW_PRIMITIVE();
+              FLUSH();
            }
            currentsz = dmasz;
         }
 
         RELEASE_ELT_VERTS();
+        FLUSH();
       }
       else {
-        /* Vertices won't fit in a single buffer or elts not available,
-         * VERT_FALLBACK.
+        /* Vertices won't fit in a single buffer or elts not
+         * available - should never happen.
          */
-        VERT_FALLBACK( ctx, start, count, flags );
+        fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+        return;
       }
    }
    else if (HAVE_TRI_STRIPS) {
       LOCAL_VARS;
       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
-      int currentsz = GET_CURRENT_VB_MAX_VERTS();
+      int currentsz;
 
       /* Emit smooth-shaded quadstrips as tristrips:
        */
-      NEW_PRIMITIVE();
+      FLUSH();
       INIT( GL_TRIANGLE_STRIP );
 
       /* Emit whole number of quads in total, and in each buffer.
        */
       dmasz -= dmasz & 1;
+      currentsz = GET_CURRENT_VB_MAX_VERTS();
       currentsz -= currentsz & 1;
       count -= (count-start) & 1;
 
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
       for (j = start; j + 3 < count; j += nr - 2 ) {
         nr = MIN2( currentsz, count - j );
-        EMIT_VERTS( ctx, j, nr );
+        TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
         currentsz = dmasz;
       }
 
-      FINISH;
+      FLUSH();
 
    } else {
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -544,7 +544,7 @@ static void TAG(render_quads_verts)( GLcontext *ctx,
    if (HAVE_QUADS) {
       LOCAL_VARS;
       int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4;
-      int currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
+      int currentsz;
       GLuint j, nr;
 
       INIT(GL_QUADS);
@@ -554,16 +554,17 @@ static void TAG(render_quads_verts)( GLcontext *ctx,
        */
       count -= (count-start)%4;
 
+      currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
       if (currentsz < 8)
          currentsz = dmasz;
 
       for (j = start; j < count; j += nr) {
          nr = MIN2( currentsz, count - j );
-         EMIT_VERTS( ctx, j, nr );
+         TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
          currentsz = dmasz;
       }
-      FINISH;
-   } else if (TAG(emit_elt_verts)( ctx, start, count )) {
+   }
+   else if (HAVE_ELTS) {
       /* Hardware doesn't have a quad primitive type -- try to
        * simulate it using indexed vertices and the triangle
        * primitive:
@@ -573,7 +574,9 @@ static void TAG(render_quads_verts)( GLcontext *ctx,
       int currentsz;
       GLuint j, nr;
 
-      NEW_PRIMITIVE();
+      EMIT_INDEXED_VERTS( ctx, start, count );
+
+      FLUSH();
       ELT_INIT( GL_TRIANGLES );
       currentsz = GET_CURRENT_VB_MAX_ELTS();
 
@@ -596,10 +599,7 @@ static void TAG(render_quads_verts)( GLcontext *ctx,
         if (nr >= 4) {
            GLint quads = nr/4;
            GLint i;
-           ELTS_VARS;
-
-           NEW_PRIMITIVE();
-           ALLOC_ELTS_NEW_PRIMITIVE( quads*6 );
+           ELTS_VARS( ALLOC_ELTS( quads*6 ) );
 
            for ( i = j-start ; i < j-start+quads*4 ; i+=4 ) {
               EMIT_TWO_ELTS( 0, (i+0), (i+1) );
@@ -608,17 +608,39 @@ static void TAG(render_quads_verts)( GLcontext *ctx,
               INCR_ELTS( 6 );
            }
 
-           NEW_PRIMITIVE();
+           FLUSH();
         }
         currentsz = dmasz;
       }
 
       RELEASE_ELT_VERTS();
    }
+   else if (HAVE_TRIANGLES) {
+      /* Hardware doesn't have a quad primitive type -- try to
+       * simulate it using triangle primitive.  This is a win for
+       * gears, but is it useful in the broader world?
+       */
+      LOCAL_VARS;
+      GLuint j;
+
+      INIT(GL_TRIANGLES);
+
+      for (j = start; j < count-3; j += 4) {
+        void *tmp = ALLOC_VERTS( 6 );
+        /* Send v0, v1, v3
+         */
+        tmp = EMIT_VERTS(ctx, j,     2, tmp);
+        tmp = EMIT_VERTS(ctx, j + 3, 1, tmp);
+        /* Send v1, v2, v3
+         */
+        tmp = EMIT_VERTS(ctx, j + 1, 3, tmp);
+      }
+   }
    else {
-      /* Vertices won't fit in a single buffer, fallback.
+      /* Vertices won't fit in a single buffer, should never happen.
        */
-      VERT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -632,7 +654,7 @@ static void TAG(render_noop)( GLcontext *ctx,
 
 
 
-static render_func TAG(render_tab_verts)[GL_POLYGON+2] =
+static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
 {
    TAG(render_points_verts),
    TAG(render_lines_verts),
@@ -673,12 +695,13 @@ static void TAG(render_points_elts)( GLcontext *ctx,
 
       for (j = start; j < count; j += nr ) {
         nr = MIN2( currentsz, count - j );
-        TAG(emit_elts)( ctx, elts+j, nr );
-        NEW_PRIMITIVE();
+        TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+        FLUSH();
         currentsz = dmasz;
       }
    } else {
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -710,12 +733,13 @@ static void TAG(render_lines_elts)( GLcontext *ctx,
 
       for (j = start; j < count; j += nr ) {
         nr = MIN2( currentsz, count - j );
-        TAG(emit_elts)( ctx, elts+j, nr );
-        NEW_PRIMITIVE();
+        TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+        FLUSH();
         currentsz = dmasz;
       }
    } else {
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -732,7 +756,7 @@ static void TAG(render_line_strip_elts)( GLcontext *ctx,
       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
       GLuint j, nr;
 
-      NEW_PRIMITIVE(); /* always a new primitive */
+      FLUSH(); /* always a new primitive */
       ELT_INIT( GL_LINE_STRIP );
 
       currentsz = GET_CURRENT_VB_MAX_ELTS();
@@ -741,14 +765,15 @@ static void TAG(render_line_strip_elts)( GLcontext *ctx,
 
       for (j = start; j + 1 < count; j += nr - 1 ) {
         nr = MIN2( currentsz, count - j );
-        TAG(emit_elts)( ctx, elts+j, nr );
-        NEW_PRIMITIVE();
+        TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+        FLUSH();
         currentsz = dmasz;
       }
    } else {
       /* TODO: Try to emit as indexed lines.
        */
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -765,7 +790,7 @@ static void TAG(render_line_loop_elts)( GLcontext *ctx,
       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
       GLuint j, nr;
 
-      NEW_PRIMITIVE();
+      FLUSH();
       ELT_INIT( GL_LINE_STRIP );
 
       if (flags & PRIM_BEGIN)
@@ -775,7 +800,6 @@ static void TAG(render_line_loop_elts)( GLcontext *ctx,
 
       currentsz = GET_CURRENT_VB_MAX_ELTS();
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
@@ -784,20 +808,38 @@ static void TAG(render_line_loop_elts)( GLcontext *ctx,
       currentsz--;
       dmasz--;
 
-      for ( ; j + 1 < count; j += nr - 1 ) {
-        nr = MIN2( currentsz, count - j );
-/*      NEW_PRIMITIVE(); */
-        TAG(emit_elts)( ctx, elts+j, nr );
-        currentsz = dmasz;
-      }
+      if (j + 1 < count) {
+        for ( ; j + 1 < count; j += nr - 1 ) {
+           nr = MIN2( currentsz, count - j );
+
+           if (j + nr >= count &&
+               start < count - 1 && 
+               (flags & PRIM_END)) 
+           {
+              void *tmp;
+              tmp = ALLOC_ELTS(nr+1);
+              tmp = TAG(emit_elts)( ctx, elts+j, nr, tmp );
+              tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
+           }
+           else {
+              TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+              currentsz = dmasz;
+           }
+        }
 
-      if (flags & PRIM_END)
-        TAG(emit_elts)( ctx, elts+start, 1 );
+      }
+      else if (start + 1 < count && (flags & PRIM_END)) {
+        void *tmp;
+        tmp = ALLOC_ELTS(2);
+        tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
+        tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
+      }
 
-      NEW_PRIMITIVE();
+      FLUSH();
    } else {
       /* TODO: Try to emit as indexed lines */
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -817,7 +859,7 @@ static void TAG(render_triangles_elts)( GLcontext *ctx,
    int currentsz;
    GLuint j, nr;
 
-   NEW_PRIMITIVE();
+   FLUSH();
    ELT_INIT( GL_TRIANGLES );
 
    currentsz = GET_CURRENT_VB_MAX_ELTS();
@@ -832,8 +874,8 @@ static void TAG(render_triangles_elts)( GLcontext *ctx,
 
    for (j = start; j < count; j += nr) {
       nr = MIN2( currentsz, count - j );
-      TAG(emit_elts)( ctx, elts+j, nr );
-      NEW_PRIMITIVE();
+      TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+      FLUSH();
       currentsz = dmasz;
    }
 }
@@ -852,12 +894,11 @@ static void TAG(render_tri_strip_elts)( GLcontext *ctx,
       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
       int currentsz;
 
-      NEW_PRIMITIVE();
+      FLUSH();
       ELT_INIT( GL_TRIANGLE_STRIP );
 
       currentsz = GET_CURRENT_VB_MAX_ELTS();
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
@@ -868,13 +909,14 @@ static void TAG(render_tri_strip_elts)( GLcontext *ctx,
 
       for (j = start ; j + 2 < count; j += nr - 2 ) {
         nr = MIN2( currentsz, count - j );
-        TAG(emit_elts)( ctx, elts+j, nr );
-        NEW_PRIMITIVE();
+        TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+        FLUSH();
         currentsz = dmasz;
       }
    } else {
       /* TODO: try to emit as indexed triangles */
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -890,25 +932,27 @@ static void TAG(render_tri_fan_elts)( GLcontext *ctx,
       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
       int currentsz;
 
-      NEW_PRIMITIVE();
+      FLUSH();
       ELT_INIT( GL_TRIANGLE_FAN );
 
       currentsz = GET_CURRENT_VB_MAX_ELTS();
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
-      for (j = start + 1 ; j + 1 < count; j += nr - 1 ) {
+      for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
+        void *tmp;
         nr = MIN2( currentsz, count - j + 1 );
-        TAG(emit_elts)( ctx, elts+start, 1 );
-        TAG(emit_elts)( ctx, elts+j, nr - 1 );
-        NEW_PRIMITIVE();
+        tmp = ALLOC_ELTS( nr );
+        tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
+        tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
+        FLUSH();
         currentsz = dmasz;
       }
    } else {
       /* TODO: try to emit as indexed triangles */
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -918,32 +962,35 @@ static void TAG(render_poly_elts)( GLcontext *ctx,
                                   GLuint count,
                                   GLuint flags )
 {
-   if (HAVE_POLYGONS && 0) {
-   } else if (HAVE_TRI_FANS && !(ctx->_TriangleCaps & DD_FLATSHADE)) {
+   if (HAVE_POLYGONS) {
       LOCAL_VARS;
       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
       GLuint j, nr;
       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
       int currentsz;
 
-      NEW_PRIMITIVE();
-      ELT_INIT( GL_TRIANGLE_FAN );
+      FLUSH();
+      ELT_INIT( GL_POLYGON );
 
       currentsz = GET_CURRENT_VB_MAX_ELTS();
       if (currentsz < 8) {
-        NEW_BUFFER();
         currentsz = dmasz;
       }
 
-      for (j = start + 1 ; j + 1 < count ; j += nr - 1 ) {
+      for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
+        void *tmp;
         nr = MIN2( currentsz, count - j + 1 );
-        TAG(emit_elts)( ctx, elts+start, 1 );
-        TAG(emit_elts)( ctx, elts+j, nr - 1 );
-        NEW_PRIMITIVE();
+        tmp = ALLOC_ELTS( nr );
+        tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
+        tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
+        FLUSH();
         currentsz = dmasz;
       }
+   } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
+      TAG(render_tri_fan_verts)( ctx, start, count, flags );
    } else {
-      ELT_FALLBACK( ctx, start, count, flags );
+      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
+      return;
    }
 }
 
@@ -961,7 +1008,7 @@ static void TAG(render_quad_strip_elts)( GLcontext *ctx,
       int currentsz;
       GLuint j, nr;
 
-      NEW_PRIMITIVE();
+      FLUSH();
       currentsz = GET_CURRENT_VB_MAX_ELTS();
 
       /* Emit whole number of quads in total, and in each buffer.
@@ -973,7 +1020,7 @@ static void TAG(render_quad_strip_elts)( GLcontext *ctx,
       if (currentsz < 12)
         currentsz = dmasz;
 
-      if (ctx->_TriangleCaps & DD_FLATSHADE) {
+      if (ctx->Light.ShadeModel == GL_FLAT) {
         ELT_INIT( GL_TRIANGLES );
 
         currentsz = currentsz/6*2;
@@ -986,11 +1033,7 @@ static void TAG(render_quad_strip_elts)( GLcontext *ctx,
            {
               GLint i;
               GLint quads = (nr/2)-1;
-              ELTS_VARS;
-
-
-              NEW_PRIMITIVE();
-              ALLOC_ELTS_NEW_PRIMITIVE( quads*6 );
+              ELTS_VARS( ALLOC_ELTS( quads*6 ) );
 
               for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
                  EMIT_TWO_ELTS( 0, elts[0], elts[1] );
@@ -999,7 +1042,7 @@ static void TAG(render_quad_strip_elts)( GLcontext *ctx,
                  INCR_ELTS( 6 );
               }
 
-              NEW_PRIMITIVE();
+              FLUSH();
            }
 
            currentsz = dmasz;
@@ -1010,8 +1053,8 @@ static void TAG(render_quad_strip_elts)( GLcontext *ctx,
 
         for (j = start; j + 3 < count; j += nr - 2 ) {
            nr = MIN2( currentsz, count - j );
-           TAG(emit_elts)( ctx, elts+j, nr );
-           NEW_PRIMITIVE();
+           TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+           FLUSH();
            currentsz = dmasz;
         }
       }
@@ -1024,7 +1067,29 @@ static void TAG(render_quads_elts)( GLcontext *ctx,
                                    GLuint count,
                                    GLuint flags )
 {
-   if (HAVE_QUADS && 0) {
+   if (HAVE_QUADS) {
+      LOCAL_VARS;
+      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
+      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
+      int currentsz;
+      GLuint j, nr;
+
+      FLUSH();
+      ELT_INIT( GL_TRIANGLES );
+
+      currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
+
+      count -= (count-start)%4;
+
+      if (currentsz < 8)
+        currentsz = dmasz;
+
+      for (j = start; j < count; j += nr) {
+        nr = MIN2( currentsz, count - j );
+        TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
+        FLUSH();
+        currentsz = dmasz;
+      }
    } else {
       LOCAL_VARS;
       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
@@ -1056,9 +1121,7 @@ static void TAG(render_quads_elts)( GLcontext *ctx,
         {
            GLint quads = nr/4;
            GLint i;
-           ELTS_VARS;
-           NEW_PRIMITIVE();
-           ALLOC_ELTS_NEW_PRIMITIVE( quads * 6 );
+           ELTS_VARS( ALLOC_ELTS( quads * 6 ) );
 
            for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
               EMIT_TWO_ELTS( 0, elts[0], elts[1] );
@@ -1066,9 +1129,10 @@ static void TAG(render_quads_elts)( GLcontext *ctx,
               EMIT_TWO_ELTS( 4, elts[2], elts[3] );
               INCR_ELTS( 6 );
            }
+
+           FLUSH();
         }
 
-        NEW_PRIMITIVE();
         currentsz = dmasz;
       }
    }
@@ -1076,7 +1140,7 @@ static void TAG(render_quads_elts)( GLcontext *ctx,
 
 
 
-static render_func TAG(render_tab_elts)[GL_POLYGON+2] =
+static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
 {
    TAG(render_points_elts),
    TAG(render_lines_elts),
@@ -1090,4 +1154,104 @@ static render_func TAG(render_tab_elts)[GL_POLYGON+2] =
    TAG(render_poly_elts),
    TAG(render_noop),
 };
+
+
+
 #endif
+
+
+
+/* Pre-check the primitives in the VB to prevent the need for
+ * fallbacks later on.
+ */
+static GLboolean TAG(validate_render)( GLcontext *ctx,
+                                      struct vertex_buffer *VB )
+{
+   GLint i;
+
+   if (VB->ClipOrMask & ~CLIP_CULL_BIT)
+      return GL_FALSE;
+
+   if (VB->Elts && !HAVE_ELTS)
+      return GL_FALSE;
+
+   for (i = 0 ; i < VB->PrimitiveCount ; i++) {
+      GLuint prim = VB->Primitive[i].mode;
+      GLuint count = VB->Primitive[i].count;
+      GLboolean ok = GL_FALSE;
+
+      if (!count)
+        continue;
+
+      switch (prim & PRIM_MODE_MASK) {
+      case GL_POINTS:
+        ok = HAVE_POINTS;
+        break;
+      case GL_LINES:
+        ok = HAVE_LINES && !ctx->Line.StippleFlag;
+        break;
+      case GL_LINE_STRIP:
+        ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
+        break;
+      case GL_LINE_LOOP:
+        ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
+        break;
+      case GL_TRIANGLES:
+        ok = HAVE_TRIANGLES;
+        break;
+      case GL_TRIANGLE_STRIP:
+        ok = HAVE_TRI_STRIPS;
+        break;
+      case GL_TRIANGLE_FAN:
+        ok = HAVE_TRI_FANS;
+        break;
+      case GL_POLYGON:
+        if (HAVE_POLYGONS) {
+           ok = GL_TRUE;
+        }
+        else {
+           ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH);
+         }
+        break;
+      case GL_QUAD_STRIP:
+        if (VB->Elts) {
+           ok = HAVE_TRI_STRIPS;
+        }
+        else if (HAVE_QUAD_STRIPS) {
+           ok = GL_TRUE;
+        } else if (HAVE_TRI_STRIPS && 
+                   ctx->Light.ShadeModel == GL_FLAT &&
+                   VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride != 0) {
+           if (HAVE_ELTS) {
+              ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
+           }
+           else {
+              ok = GL_FALSE;
+           }
+        }
+        else 
+           ok = HAVE_TRI_STRIPS;
+        break;
+      case GL_QUADS:
+        if (HAVE_QUADS) {
+           ok = GL_TRUE;
+        } else if (HAVE_ELTS) {
+           ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
+        }
+        else {
+           ok = HAVE_TRIANGLES; /* flatshading is ok. */
+        }
+        break;
+      default:
+        break;
+      }
+      
+      if (!ok) {
+/*      fprintf(stderr, "not ok %s\n", _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */
+        return GL_FALSE;
+      }
+   }
+
+   return GL_TRUE;
+}
+