Mesa (master): gallium: rework provoking vertex code

Brian Paul brianp at kemper.freedesktop.org
Thu May 6 00:26:25 UTC 2010


Module: Mesa
Branch: master
Commit: cb136a93aba4dc64db7e446b0fbc36c9172e4017
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=cb136a93aba4dc64db7e446b0fbc36c9172e4017

Author: Brian Paul <brianp at vmware.com>
Date:   Wed May  5 18:19:06 2010 -0600

gallium: rework provoking vertex code

Builds on commit ddb0e18f6c5582d4d2cc59ffd16ad9c4639ed059 and fixes
regressions in glean clipFlat test.

We assume that Gallium drivers observe flatshade_first for all triangles
and that all the assorted per-triangle calls in the 'draw' module also
follow flatshade_first.  Everything else builds on those rules.

Gallium does not use follow flatshade_first for GL quads, quad strips
and polygons; the "last" vertex is always the provoking vertex for those
prims.  So now there are separate QUAD_FIRST_PV and QUAD_LAST_PV macros
in the draw primitive decomposition code instead of one QUAD macro.

---

 src/gallium/auxiliary/draw/draw_pipe.c         |   42 +++-
 src/gallium/auxiliary/draw/draw_pipe_clip.c    |   36 ++-
 src/gallium/auxiliary/draw/draw_pipe_vbuf.c    |   15 +-
 src/gallium/auxiliary/draw/draw_pt_decompose.h |   71 +++++--
 src/gallium/auxiliary/draw/draw_pt_vcache.c    |    8 +-
 src/gallium/drivers/softpipe/sp_prim_vbuf.c    |  308 +++++++++++++++---------
 src/gallium/drivers/softpipe/sp_setup.c        |    5 +-
 7 files changed, 321 insertions(+), 164 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_pipe.c b/src/gallium/auxiliary/draw/draw_pipe.c
index 64c3502..7ea04e3 100644
--- a/src/gallium/auxiliary/draw/draw_pipe.c
+++ b/src/gallium/auxiliary/draw/draw_pipe.c
@@ -170,7 +170,25 @@ static void do_triangle( struct draw_context *draw,
  * Set up macros for draw_pt_decompose.h template code.
  * This code uses vertex indexes / elements.
  */
-#define QUAD(i0,i1,i2,i3)                       \
+
+/* emit first quad vertex as first vertex in triangles */
+#define QUAD_FIRST_PV(i0,i1,i2,i3)              \
+   do_triangle( draw,                           \
+                ( DRAW_PIPE_RESET_STIPPLE |     \
+                  DRAW_PIPE_EDGE_FLAG_0 |       \
+                  DRAW_PIPE_EDGE_FLAG_1 ),      \
+                verts + stride * elts[i0],      \
+                verts + stride * elts[i1],      \
+                verts + stride * elts[i2]);     \
+   do_triangle( draw,                           \
+                ( DRAW_PIPE_EDGE_FLAG_1 |       \
+                  DRAW_PIPE_EDGE_FLAG_2 ),      \
+                verts + stride * elts[i0],      \
+                verts + stride * elts[i2],      \
+                verts + stride * elts[i3])
+
+/* emit last quad vertex as last vertex in triangles */
+#define QUAD_LAST_PV(i0,i1,i2,i3)               \
    do_triangle( draw,                           \
                 ( DRAW_PIPE_RESET_STIPPLE |     \
                   DRAW_PIPE_EDGE_FLAG_0 |       \
@@ -261,9 +279,27 @@ void draw_pipeline_run( struct draw_context *draw,
 
 /*
  * Set up macros for draw_pt_decompose.h template code.
- * This code is for non-indexed rendering (no elts).
+ * This code is for non-indexed (aka linear) rendering (no elts).
  */
-#define QUAD(i0,i1,i2,i3)                                        \
+
+/* emit first quad vertex as first vertex in triangles */
+#define QUAD_FIRST_PV(i0,i1,i2,i3)                               \
+   do_triangle( draw,                                            \
+                ( DRAW_PIPE_RESET_STIPPLE |                      \
+                  DRAW_PIPE_EDGE_FLAG_0 |                        \
+                  DRAW_PIPE_EDGE_FLAG_1 ),                       \
+                verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * (i1),                           \
+                verts + stride * (i2));                          \
+   do_triangle( draw,                                            \
+                ( DRAW_PIPE_EDGE_FLAG_1 |                        \
+                  DRAW_PIPE_EDGE_FLAG_2 ),                       \
+                verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * (i2),                           \
+                verts + stride * (i3))
+
+/* emit last quad vertex as last vertex in triangles */
+#define QUAD_LAST_PV(i0,i1,i2,i3)                                \
    do_triangle( draw,                                            \
                 ( DRAW_PIPE_RESET_STIPPLE |                      \
                   DRAW_PIPE_EDGE_FLAG_0 |                        \
diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c
index 428ef4e..d0532cb 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_clip.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c
@@ -164,10 +164,18 @@ static void emit_poly( struct draw_stage *stage,
 {
    struct prim_header header;
    unsigned i;
+   ushort edge_first, edge_middle, edge_last;
 
-   const ushort edge_first  = DRAW_PIPE_EDGE_FLAG_2;
-   const ushort edge_middle = DRAW_PIPE_EDGE_FLAG_0;
-   const ushort edge_last   = DRAW_PIPE_EDGE_FLAG_1;
+   if (stage->draw->rasterizer->flatshade_first) {
+      edge_first  = DRAW_PIPE_EDGE_FLAG_0;
+      edge_middle = DRAW_PIPE_EDGE_FLAG_1;
+      edge_last   = DRAW_PIPE_EDGE_FLAG_2;
+   }
+   else {
+      edge_first  = DRAW_PIPE_EDGE_FLAG_2;
+      edge_middle = DRAW_PIPE_EDGE_FLAG_0;
+      edge_last   = DRAW_PIPE_EDGE_FLAG_1;
+   }
 
    /* later stages may need the determinant, but only the sign matters */
    header.det = origPrim->det;
@@ -301,21 +309,21 @@ do_clip_tri( struct draw_stage *stage,
 
    /* If flat-shading, copy color to new provoking vertex.
     */
-   if (stage->draw->rasterizer->flatshade_first) {
-      if (clipper->flat && inlist[0] != header->v[0]) {
-         inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
-
-         copy_colors(stage, inlist[0], header->v[0]);
+   if (clipper->flat) {
+      if (stage->draw->rasterizer->flatshade_first) {
+         if (inlist[0] != header->v[0]) {
+            inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
+            copy_colors(stage, inlist[0], header->v[0]);
+         }
       }
-   } else {
-      if (clipper->flat && inlist[0] != header->v[2]) {
-         inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
-
-         copy_colors(stage, inlist[0], header->v[2]);
+      else {
+         if (inlist[0] != header->v[2]) {
+            inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
+            copy_colors(stage, inlist[0], header->v[2]);
+         }
       }
    }
 
-
    /* Emit the polygon as triangles to the setup stage:
     */
    if (n >= 3)
diff --git a/src/gallium/auxiliary/draw/draw_pipe_vbuf.c b/src/gallium/auxiliary/draw/draw_pipe_vbuf.c
index abbf624..1fd083e 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_vbuf.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_vbuf.c
@@ -159,19 +159,8 @@ vbuf_tri( struct draw_stage *stage,
 
    check_space( vbuf, 3 );
 
-   if (vbuf->stage.draw->rasterizer->flatshade_first) {
-      /* Put provoking vertex in position expected by the driver.
-       * Emit last provoking vertex in first pos.
-       * Swap verts 0 & 1 to preserve polygon winding.
-       */
-      vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[2] );
-      vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
-      vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[1] );
-   }
-   else {
-      for (i = 0; i < 3; i++) {
-         vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
-      }
+   for (i = 0; i < 3; i++) {
+      vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
    }
 }
 
diff --git a/src/gallium/auxiliary/draw/draw_pt_decompose.h b/src/gallium/auxiliary/draw/draw_pt_decompose.h
index 02567d9..52f9593 100644
--- a/src/gallium/auxiliary/draw/draw_pt_decompose.h
+++ b/src/gallium/auxiliary/draw/draw_pt_decompose.h
@@ -57,6 +57,7 @@ static void FUNC( ARGS,
    case PIPE_PRIM_TRIANGLE_STRIP:
       if (flatfirst) {
          for (i = 0; i+2 < count; i++) {
+            /* Emit first triangle vertex as first triangle vertex */
             TRIANGLE( DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL,
                       (i + 0),
                       (i + 1 + (i&1)),
@@ -65,6 +66,7 @@ static void FUNC( ARGS,
       }
       else {
          for (i = 0; i+2 < count; i++) {
+            /* Emit last triangle vertex as last triangle vertex */
             TRIANGLE( DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL,
                       (i + 0 + (i&1)),
                       (i + 1 - (i&1)),
@@ -96,24 +98,52 @@ static void FUNC( ARGS,
 
 
    case PIPE_PRIM_QUADS:
-      for (i = 0; i+3 < count; i += 4) {
-         QUAD( (i + 0),
-               (i + 1),
-               (i + 2),
-               (i + 3));
+      /* GL quads don't follow provoking vertex convention */
+      if (flatfirst) {
+         for (i = 0; i+3 < count; i += 4) {
+            /* emit last quad vertex as first triangle vertex */
+            QUAD_FIRST_PV( (i + 3),
+                           (i + 0),
+                           (i + 1),
+                           (i + 2) );
+         }
+      }
+      else {
+         for (i = 0; i+3 < count; i += 4) {
+            /* emit last quad vertex as last triangle vertex */
+            QUAD_LAST_PV( (i + 0),
+                          (i + 1),
+                          (i + 2),
+                          (i + 3) );
+         }
       }
       break;
 
    case PIPE_PRIM_QUAD_STRIP:
-      for (i = 0; i+3 < count; i += 2) {
-         QUAD( (i + 2),
-               (i + 0),
-               (i + 1),
-               (i + 3));
+      /* GL quad strips don't follow provoking vertex convention */
+      if (flatfirst) {
+         for (i = 0; i+3 < count; i += 2) {
+            /* emit last quad vertex as first triangle vertex */
+            QUAD_FIRST_PV( (i + 3),
+                           (i + 2),
+                           (i + 0),
+                           (i + 1) );
+
+         }
+      }
+      else {
+         for (i = 0; i+3 < count; i += 2) {
+            /* emit last quad vertex as last triangle vertex */
+            QUAD_LAST_PV( (i + 2),
+                          (i + 0),
+                          (i + 1),
+                          (i + 3) );
+         }
       }
       break;
 
    case PIPE_PRIM_POLYGON:
+      /* GL polygons don't follow provoking vertex convention */
       {
          /* These bitflags look a little odd because we submit the
           * vertices as (1,2,0) to satisfy flatshade requirements.
@@ -129,10 +159,20 @@ static void FUNC( ARGS,
             if (i + 3 == count)
                flags |= edge_last;
 
-	    TRIANGLE( flags,
-                      (i + 1),
-                      (i + 2),
-                      (0));
+            if (flatfirst) {
+               /* emit first polygon vertex as first triangle vertex */
+               TRIANGLE( flags,
+                         (0),
+                         (i + 1),
+                         (i + 2) );
+            }
+            else {
+               /* emit first polygon vertex as last triangle vertex */
+               TRIANGLE( flags,
+                         (i + 1),
+                         (i + 2),
+                         (0));
+            }
 	 }
       }
       break;
@@ -147,7 +187,8 @@ static void FUNC( ARGS,
 
 
 #undef TRIANGLE
-#undef QUAD
+#undef QUAD_FIRST_PV
+#undef QUAD_LAST_PV
 #undef POINT
 #undef LINE
 #undef FUNC
diff --git a/src/gallium/auxiliary/draw/draw_pt_vcache.c b/src/gallium/auxiliary/draw/draw_pt_vcache.c
index 37ffbac..bfcd709 100644
--- a/src/gallium/auxiliary/draw/draw_pt_vcache.c
+++ b/src/gallium/auxiliary/draw/draw_pt_vcache.c
@@ -199,12 +199,12 @@ vcache_ef_quad( struct vcache_frontend *vcache,
                              ( DRAW_PIPE_RESET_STIPPLE |
                                DRAW_PIPE_EDGE_FLAG_0 |
                                DRAW_PIPE_EDGE_FLAG_1 ),
-                             i0, i1, i2 );
+                             i3, i0, i1 );
 
       vcache_triangle_flags( vcache,
-                             ( DRAW_PIPE_EDGE_FLAG_2 |
-                               DRAW_PIPE_EDGE_FLAG_1 ),
-                             i0, i2, i3 );
+                             ( DRAW_PIPE_EDGE_FLAG_1 |
+                               DRAW_PIPE_EDGE_FLAG_2 ),
+                             i3, i1, i2 );
    }
    else {
       vcache_triangle_flags( vcache,
diff --git a/src/gallium/drivers/softpipe/sp_prim_vbuf.c b/src/gallium/drivers/softpipe/sp_prim_vbuf.c
index a58bc10..0168b32 100644
--- a/src/gallium/drivers/softpipe/sp_prim_vbuf.c
+++ b/src/gallium/drivers/softpipe/sp_prim_vbuf.c
@@ -164,20 +164,21 @@ sp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
    struct softpipe_context *softpipe = cvbr->softpipe;
    const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float);
    const void *vertex_buffer = cvbr->vertex_buffer;
-   struct setup_context *setup_ctx = cvbr->setup;
+   struct setup_context *setup = cvbr->setup;
+   const boolean flatshade_first = softpipe->rasterizer->flatshade_first;
    unsigned i;
 
    switch (cvbr->prim) {
    case PIPE_PRIM_POINTS:
       for (i = 0; i < nr; i++) {
-         sp_setup_point( setup_ctx,
+         sp_setup_point( setup,
                          get_vert(vertex_buffer, indices[i-0], stride) );
       }
       break;
 
    case PIPE_PRIM_LINES:
       for (i = 1; i < nr; i += 2) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, indices[i-1], stride),
                         get_vert(vertex_buffer, indices[i-0], stride) );
       }
@@ -185,7 +186,7 @@ sp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
 
    case PIPE_PRIM_LINE_STRIP:
       for (i = 1; i < nr; i ++) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, indices[i-1], stride),
                         get_vert(vertex_buffer, indices[i-0], stride) );
       }
@@ -193,48 +194,41 @@ sp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
 
    case PIPE_PRIM_LINE_LOOP:
       for (i = 1; i < nr; i ++) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, indices[i-1], stride),
                         get_vert(vertex_buffer, indices[i-0], stride) );
       }
       if (nr) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, indices[nr-1], stride),
                         get_vert(vertex_buffer, indices[0], stride) );
       }
       break;
 
    case PIPE_PRIM_TRIANGLES:
-      if (softpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 3) {
-            sp_setup_tri( setup_ctx,
-                          get_vert(vertex_buffer, indices[i-1], stride),
-                          get_vert(vertex_buffer, indices[i-0], stride),
-                          get_vert(vertex_buffer, indices[i-2], stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 3) {
-            sp_setup_tri( setup_ctx,
-                          get_vert(vertex_buffer, indices[i-2], stride),
-                          get_vert(vertex_buffer, indices[i-1], stride),
-                          get_vert(vertex_buffer, indices[i-0], stride) );
-         }
+      for (i = 2; i < nr; i += 3) {
+         sp_setup_tri( setup,
+                       get_vert(vertex_buffer, indices[i-2], stride),
+                       get_vert(vertex_buffer, indices[i-1], stride),
+                       get_vert(vertex_buffer, indices[i-0], stride) );
       }
       break;
 
    case PIPE_PRIM_TRIANGLE_STRIP:
-      if (softpipe->rasterizer->flatshade_first) {
+      if (flatshade_first) {
          for (i = 2; i < nr; i += 1) {
-            sp_setup_tri( setup_ctx,
+            /* emit first triangle vertex as first triangle vertex */
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-2], stride),
                           get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
-                          get_vert(vertex_buffer, indices[i-(i&1)], stride),
-                          get_vert(vertex_buffer, indices[i-2], stride) );
+                          get_vert(vertex_buffer, indices[i-(i&1)], stride) );
+
          }
       }
       else {
          for (i = 2; i < nr; i += 1) {
-            sp_setup_tri( setup_ctx,
+            /* emit last triangle vertex as last triangle vertex */
+            sp_setup_tri( setup,
                           get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
                           get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
                           get_vert(vertex_buffer, indices[i-0], stride) );
@@ -243,17 +237,19 @@ sp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
       break;
 
    case PIPE_PRIM_TRIANGLE_FAN:
-      if (softpipe->rasterizer->flatshade_first) {
+      if (flatshade_first) {
          for (i = 2; i < nr; i += 1) {
-            sp_setup_tri( setup_ctx,
+            /* emit first non-spoke vertex as first vertex */
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-1], stride),
                           get_vert(vertex_buffer, indices[i-0], stride),
-                          get_vert(vertex_buffer, indices[0], stride),
-                          get_vert(vertex_buffer, indices[i-1], stride) );
+                          get_vert(vertex_buffer, indices[0], stride) );
          }
       }
       else {
          for (i = 2; i < nr; i += 1) {
-            sp_setup_tri( setup_ctx,
+            /* emit last non-spoke vertex as last vertex */
+            sp_setup_tri( setup,
                           get_vert(vertex_buffer, indices[0], stride),
                           get_vert(vertex_buffer, indices[i-1], stride),
                           get_vert(vertex_buffer, indices[i-0], stride) );
@@ -262,43 +258,88 @@ sp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
       break;
 
    case PIPE_PRIM_QUADS:
-      for (i = 3; i < nr; i += 4) {
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-3], stride),
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
+      /* GL quads don't follow provoking vertex convention */
+      if (flatshade_first) { 
+         /* emit last quad vertex as first triangle vertex */
+         for (i = 3; i < nr; i += 4) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-0], stride),
+                          get_vert(vertex_buffer, indices[i-3], stride),
+                          get_vert(vertex_buffer, indices[i-2], stride) );
 
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-0], stride),
+                          get_vert(vertex_buffer, indices[i-2], stride),
+                          get_vert(vertex_buffer, indices[i-1], stride) );
+         }
+      }
+      else {
+         /* emit last quad vertex as last triangle vertex */
+         for (i = 3; i < nr; i += 4) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-3], stride),
+                          get_vert(vertex_buffer, indices[i-2], stride),
+                          get_vert(vertex_buffer, indices[i-0], stride) );
+
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-2], stride),
+                          get_vert(vertex_buffer, indices[i-1], stride),
+                          get_vert(vertex_buffer, indices[i-0], stride) );
+         }
       }
       break;
 
    case PIPE_PRIM_QUAD_STRIP:
-      for (i = 3; i < nr; i += 2) {
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-3], stride),
-                       get_vert(vertex_buffer, indices[i-2], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[i-3], stride),
-                       get_vert(vertex_buffer, indices[i-0], stride) );
+      /* GL quad strips don't follow provoking vertex convention */
+      if (flatshade_first) { 
+         /* emit last quad vertex as first triangle vertex */
+         for (i = 3; i < nr; i += 2) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-0], stride),
+                          get_vert(vertex_buffer, indices[i-3], stride),
+                          get_vert(vertex_buffer, indices[i-2], stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-0], stride),
+                          get_vert(vertex_buffer, indices[i-1], stride),
+                          get_vert(vertex_buffer, indices[i-3], stride) );
+         }
+      }
+      else {
+         /* emit last quad vertex as last triangle vertex */
+         for (i = 3; i < nr; i += 2) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-3], stride),
+                          get_vert(vertex_buffer, indices[i-2], stride),
+                          get_vert(vertex_buffer, indices[i-0], stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-1], stride),
+                          get_vert(vertex_buffer, indices[i-3], stride),
+                          get_vert(vertex_buffer, indices[i-0], stride) );
+         }
       }
       break;
 
    case PIPE_PRIM_POLYGON:
       /* Almost same as tri fan but the _first_ vertex specifies the flat
-       * shading color.  Note that the first polygon vertex is passed as
-       * the last triangle vertex here.
-       * flatshade_first state makes no difference.
+       * shading color.
        */
-      for (i = 2; i < nr; i += 1) {
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, indices[i-0], stride),
-                       get_vert(vertex_buffer, indices[i-1], stride),
-                       get_vert(vertex_buffer, indices[0], stride) );
+      if (flatshade_first) { 
+         /* emit first polygon  vertex as first triangle vertex */
+         for (i = 2; i < nr; i += 1) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[0], stride),
+                          get_vert(vertex_buffer, indices[i-1], stride),
+                          get_vert(vertex_buffer, indices[i-0], stride) );
+         }
+      }
+      else {
+         /* emit first polygon  vertex as last triangle vertex */
+         for (i = 2; i < nr; i += 1) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, indices[i-1], stride),
+                          get_vert(vertex_buffer, indices[i-0], stride),
+                          get_vert(vertex_buffer, indices[0], stride) );
+         }
       }
       break;
 
@@ -317,23 +358,24 @@ sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
 {
    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
    struct softpipe_context *softpipe = cvbr->softpipe;
-   struct setup_context *setup_ctx = cvbr->setup;
+   struct setup_context *setup = cvbr->setup;
    const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float);
    const void *vertex_buffer =
       (void *) get_vert(cvbr->vertex_buffer, start, stride);
+   const boolean flatshade_first = softpipe->rasterizer->flatshade_first;
    unsigned i;
 
    switch (cvbr->prim) {
    case PIPE_PRIM_POINTS:
       for (i = 0; i < nr; i++) {
-         sp_setup_point( setup_ctx,
+         sp_setup_point( setup,
                          get_vert(vertex_buffer, i-0, stride) );
       }
       break;
 
    case PIPE_PRIM_LINES:
       for (i = 1; i < nr; i += 2) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, i-1, stride),
                         get_vert(vertex_buffer, i-0, stride) );
       }
@@ -341,7 +383,7 @@ sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
 
    case PIPE_PRIM_LINE_STRIP:
       for (i = 1; i < nr; i ++) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                      get_vert(vertex_buffer, i-1, stride),
                      get_vert(vertex_buffer, i-0, stride) );
       }
@@ -349,48 +391,40 @@ sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
 
    case PIPE_PRIM_LINE_LOOP:
       for (i = 1; i < nr; i ++) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, i-1, stride),
                         get_vert(vertex_buffer, i-0, stride) );
       }
       if (nr) {
-         sp_setup_line( setup_ctx,
+         sp_setup_line( setup,
                         get_vert(vertex_buffer, nr-1, stride),
                         get_vert(vertex_buffer, 0, stride) );
       }
       break;
 
    case PIPE_PRIM_TRIANGLES:
-      if (softpipe->rasterizer->flatshade_first) {
-         for (i = 2; i < nr; i += 3) {
-            sp_setup_tri( setup_ctx,
-                          get_vert(vertex_buffer, i-1, stride),
-                          get_vert(vertex_buffer, i-0, stride),
-                          get_vert(vertex_buffer, i-2, stride) );
-         }
-      }
-      else {
-         for (i = 2; i < nr; i += 3) {
-            sp_setup_tri( setup_ctx,
-                          get_vert(vertex_buffer, i-2, stride),
-                          get_vert(vertex_buffer, i-1, stride),
-                          get_vert(vertex_buffer, i-0, stride) );
-         }
+      for (i = 2; i < nr; i += 3) {
+         sp_setup_tri( setup,
+                       get_vert(vertex_buffer, i-2, stride),
+                       get_vert(vertex_buffer, i-1, stride),
+                       get_vert(vertex_buffer, i-0, stride) );
       }
       break;
 
    case PIPE_PRIM_TRIANGLE_STRIP:
-      if (softpipe->rasterizer->flatshade_first) {
+      if (flatshade_first) {
          for (i = 2; i < nr; i++) {
-            sp_setup_tri( setup_ctx,
+            /* emit first triangle vertex as first triangle vertex */
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-2, stride),
                           get_vert(vertex_buffer, i+(i&1)-1, stride),
-                          get_vert(vertex_buffer, i-(i&1), stride),
-                          get_vert(vertex_buffer, i-2, stride) );
+                          get_vert(vertex_buffer, i-(i&1), stride) );
          }
       }
       else {
          for (i = 2; i < nr; i++) {
-            sp_setup_tri( setup_ctx,
+            /* emit last triangle vertex as last triangle vertex */
+            sp_setup_tri( setup,
                           get_vert(vertex_buffer, i+(i&1)-2, stride),
                           get_vert(vertex_buffer, i-(i&1)-1, stride),
                           get_vert(vertex_buffer, i-0, stride) );
@@ -399,17 +433,19 @@ sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
       break;
 
    case PIPE_PRIM_TRIANGLE_FAN:
-      if (softpipe->rasterizer->flatshade_first) {
+      if (flatshade_first) {
          for (i = 2; i < nr; i += 1) {
-            sp_setup_tri( setup_ctx,
+            /* emit first non-spoke vertex as first vertex */
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-1, stride),
                           get_vert(vertex_buffer, i-0, stride),
-                          get_vert(vertex_buffer, 0, stride),
-                          get_vert(vertex_buffer, i-1, stride) );
+                          get_vert(vertex_buffer, 0, stride)  );
          }
       }
       else {
          for (i = 2; i < nr; i += 1) {
-            sp_setup_tri( setup_ctx,
+            /* emit last non-spoke vertex as last vertex */
+            sp_setup_tri( setup,
                           get_vert(vertex_buffer, 0, stride),
                           get_vert(vertex_buffer, i-1, stride),
                           get_vert(vertex_buffer, i-0, stride) );
@@ -418,42 +454,86 @@ sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
       break;
 
    case PIPE_PRIM_QUADS:
-      for (i = 3; i < nr; i += 4) {
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-3, stride),
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
+      /* GL quads don't follow provoking vertex convention */
+      if (flatshade_first) { 
+         /* emit last quad vertex as first triangle vertex */
+         for (i = 3; i < nr; i += 4) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-0, stride),
+                          get_vert(vertex_buffer, i-3, stride),
+                          get_vert(vertex_buffer, i-2, stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-0, stride),
+                          get_vert(vertex_buffer, i-2, stride),
+                          get_vert(vertex_buffer, i-1, stride) );
+         }
+      }
+      else {
+         /* emit last quad vertex as last triangle vertex */
+         for (i = 3; i < nr; i += 4) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-3, stride),
+                          get_vert(vertex_buffer, i-2, stride),
+                          get_vert(vertex_buffer, i-0, stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-2, stride),
+                          get_vert(vertex_buffer, i-1, stride),
+                          get_vert(vertex_buffer, i-0, stride) );
+         }
       }
       break;
 
    case PIPE_PRIM_QUAD_STRIP:
-      for (i = 3; i < nr; i += 2) {
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-3, stride),
-                       get_vert(vertex_buffer, i-2, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-3, stride),
-                       get_vert(vertex_buffer, i-0, stride) );
+      /* GL quad strips don't follow provoking vertex convention */
+      if (flatshade_first) { 
+         /* emit last quad vertex as first triangle vertex */
+         for (i = 3; i < nr; i += 2) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-0, stride),
+                          get_vert(vertex_buffer, i-3, stride),
+                          get_vert(vertex_buffer, i-2, stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-0, stride),
+                          get_vert(vertex_buffer, i-1, stride),
+                          get_vert(vertex_buffer, i-3, stride) );
+         }
+      }
+      else {
+         /* emit last quad vertex as last triangle vertex */
+         for (i = 3; i < nr; i += 2) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-3, stride),
+                          get_vert(vertex_buffer, i-2, stride),
+                          get_vert(vertex_buffer, i-0, stride) );
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-1, stride),
+                          get_vert(vertex_buffer, i-3, stride),
+                          get_vert(vertex_buffer, i-0, stride) );
+         }
       }
       break;
 
    case PIPE_PRIM_POLYGON:
       /* Almost same as tri fan but the _first_ vertex specifies the flat
-       * shading color.  Note that the first polygon vertex is passed as
-       * the last triangle vertex here.
-       * flatshade_first state makes no difference.
+       * shading color.
        */
-      for (i = 2; i < nr; i += 1) {
-         sp_setup_tri( setup_ctx,
-                       get_vert(vertex_buffer, i-1, stride),
-                       get_vert(vertex_buffer, i-0, stride),
-                       get_vert(vertex_buffer, 0, stride) );
+      if (flatshade_first) { 
+         /* emit first polygon  vertex as first triangle vertex */
+         for (i = 2; i < nr; i += 1) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, 0, stride),
+                          get_vert(vertex_buffer, i-1, stride),
+                          get_vert(vertex_buffer, i-0, stride) );
+         }
+      }
+      else {
+         /* emit first polygon  vertex as last triangle vertex */
+         for (i = 2; i < nr; i += 1) {
+            sp_setup_tri( setup,
+                          get_vert(vertex_buffer, i-1, stride),
+                          get_vert(vertex_buffer, i-0, stride),
+                          get_vert(vertex_buffer, 0, stride) );
+         }
       }
       break;
 
diff --git a/src/gallium/drivers/softpipe/sp_setup.c b/src/gallium/drivers/softpipe/sp_setup.c
index 8635466..35ef9e6 100644
--- a/src/gallium/drivers/softpipe/sp_setup.c
+++ b/src/gallium/drivers/softpipe/sp_setup.c
@@ -304,7 +304,10 @@ setup_sort_vertices(struct setup_context *setup,
                     const float (*v1)[4],
                     const float (*v2)[4])
 {
-   setup->vprovoke = v2;
+   if (setup->softpipe->rasterizer->flatshade_first)
+      setup->vprovoke = v0;
+   else
+      setup->vprovoke = v2;
 
    /* determine bottom to top order of vertices */
    {




More information about the mesa-commit mailing list