Mesa (master): draw: fix edge flag handling in clipper (for unfilled tris/ quads/polygons)

Brian Paul brianp at kemper.freedesktop.org
Wed Jun 8 14:14:57 UTC 2011


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

Author: Brian Paul <brianp at vmware.com>
Date:   Wed Jun  8 08:05:40 2011 -0600

draw: fix edge flag handling in clipper (for unfilled tris/quads/polygons)

Previously, we were errantly drawing some interior edges of clipped
polygons and quads.  Also, we were introducing extra edges where
polygons intersected the view frustum clip planes.

The main problem was that we were ignoring the edgeflags encoded in
the primitive header's 'flags' field which are set during polygon/quad
->tri decomposition.  We need to observe those during clipping.  Since
we can't modify the existing vert's edgeflag fields, we need to store
them in a parallel array.

Edge flags also need to be handled differently for view frustum planes
vs. user-defined clip planes.  In the former case we don't want to draw
new clip edges but in the later case we do.  This matches NVIDIA's
behaviour and it just looks right.

Finally, note that the LLVM draw code does not properly set vertex
edge flags.  It's OK on the regular software path though.

---

 src/gallium/auxiliary/draw/draw_pipe_clip.c |   62 ++++++++++++++++++++++++--
 1 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c
index a10d8e9..b49502c 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_clip.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c
@@ -163,6 +163,7 @@ static void interp( const struct clip_stage *clip,
  */
 static void emit_poly( struct draw_stage *stage,
 		       struct vertex_header **inlist,
+                       const boolean *edgeflags,
 		       unsigned n,
 		       const struct prim_header *origPrim)
 {
@@ -181,6 +182,9 @@ static void emit_poly( struct draw_stage *stage,
       edge_last   = DRAW_PIPE_EDGE_FLAG_1;
    }
 
+   if (!edgeflags[0])
+      edge_first = 0;
+
    /* later stages may need the determinant, but only the sign matters */
    header.det = origPrim->det;
    header.flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle;
@@ -199,7 +203,11 @@ static void emit_poly( struct draw_stage *stage,
          header.v[2] = inlist[0];  /* the provoking vertex */
       }
 
-      if (i == n-1)
+      if (!edgeflags[i-1]) {
+         header.flags &= ~edge_middle;
+      }
+
+      if (i == n - 1 && edgeflags[i])
          header.flags |= edge_last;
 
       if (0) {
@@ -248,15 +256,33 @@ do_clip_tri( struct draw_stage *stage,
    unsigned tmpnr = 0;
    unsigned n = 3;
    unsigned i;
+   boolean aEdges[MAX_CLIPPED_VERTICES];
+   boolean bEdges[MAX_CLIPPED_VERTICES];
+   boolean *inEdges = aEdges;
+   boolean *outEdges = bEdges;
 
    inlist[0] = header->v[0];
    inlist[1] = header->v[1];
    inlist[2] = header->v[2];
 
+   /*
+    * Note: at this point we can't just use the per-vertex edge flags.
+    * We have to observe the edge flag bits set in header->flags which
+    * were set during primitive decomposition.  Put those flags into
+    * an edge flags array which parallels the vertex array.
+    * Later, in the 'unfilled' pipeline stage we'll draw the edge if both
+    * the header.flags bit is set AND the per-vertex edgeflag field is set.
+    */
+   inEdges[0] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_0);
+   inEdges[1] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_1);
+   inEdges[2] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_2);
+
    while (clipmask && n >= 3) {
       const unsigned plane_idx = ffs(clipmask)-1;
+      const boolean is_user_clip_plane = plane_idx >= 6;
       const float *plane = clipper->plane[plane_idx];
       struct vertex_header *vert_prev = inlist[0];
+      boolean *edge_prev = &inEdges[0];
       float dp_prev = dot4( vert_prev->clip, plane );
       unsigned outcount = 0;
 
@@ -266,9 +292,11 @@ do_clip_tri( struct draw_stage *stage,
       if (n >= MAX_CLIPPED_VERTICES)
          return;
       inlist[n] = inlist[0]; /* prevent rotation of vertices */
+      inEdges[n] = inEdges[0];
 
       for (i = 1; i <= n; i++) {
 	 struct vertex_header *vert = inlist[i];
+         boolean *edge = &inEdges[i];
 
 	 float dp = dot4( vert->clip, plane );
 
@@ -276,11 +304,13 @@ do_clip_tri( struct draw_stage *stage,
             assert(outcount < MAX_CLIPPED_VERTICES);
             if (outcount >= MAX_CLIPPED_VERTICES)
                return;
+            outEdges[outcount] = *edge_prev;
 	    outlist[outcount++] = vert_prev;
 	 }
 
 	 if (DIFFERENT_SIGNS(dp, dp_prev)) {
 	    struct vertex_header *new_vert;
+            boolean *new_edge;
 
             assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
             if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
@@ -290,6 +320,8 @@ do_clip_tri( struct draw_stage *stage,
             assert(outcount < MAX_CLIPPED_VERTICES);
             if (outcount >= MAX_CLIPPED_VERTICES)
                return;
+
+            new_edge = &outEdges[outcount];
 	    outlist[outcount++] = new_vert;
 
 	    if (IS_NEGATIVE(dp)) {
@@ -299,10 +331,22 @@ do_clip_tri( struct draw_stage *stage,
 	       float t = dp / (dp - dp_prev);
 	       interp( clipper, new_vert, t, vert, vert_prev );
 	       
-	       /* Force edgeflag true in this case:
+	       /* Whether or not to set edge flag for the new vert depends
+                * on whether it's a user-defined clipping plane.  We're
+                * copying NVIDIA's behaviour here.
 		*/
-	       new_vert->edgeflag = 1;
-	    } else {
+               if (is_user_clip_plane) {
+                  /* we want to see an edge along the clip plane */
+                  *new_edge = TRUE;
+                  new_vert->edgeflag = TRUE;
+               }
+               else {
+                  /* we don't want to see an edge along the frustum clip plane */
+                  *new_edge = *edge_prev;
+                  new_vert->edgeflag = FALSE;
+               }
+	    }
+            else {
 	       /* Coming back in.
 		*/
 	       float t = dp_prev / (dp_prev - dp);
@@ -311,10 +355,12 @@ do_clip_tri( struct draw_stage *stage,
 	       /* Copy starting vert's edgeflag:
 		*/
 	       new_vert->edgeflag = vert_prev->edgeflag;
+               *new_edge = *edge_prev;
 	    }
 	 }
 
 	 vert_prev = vert;
+         edge_prev = edge;
 	 dp_prev = dp;
       }
 
@@ -325,6 +371,12 @@ do_clip_tri( struct draw_stage *stage,
 	 outlist = tmp;
 	 n = outcount;
       }
+      {
+         boolean *tmp = inEdges;
+         inEdges = outEdges;
+         outEdges = tmp;
+      }
+
    }
 
    /* If flat-shading, copy provoking vertex color to polygon vertex[0]
@@ -353,7 +405,7 @@ do_clip_tri( struct draw_stage *stage,
       
       /* Emit the polygon as triangles to the setup stage:
        */
-      emit_poly( stage, inlist, n, header );
+      emit_poly( stage, inlist, inEdges, n, header );
    }
 }
 




More information about the mesa-commit mailing list