Mesa (primitive-restart): draw: redo primitive restart

Brian Paul brianp at kemper.freedesktop.org
Sat Jul 17 13:39:17 UTC 2010


Module: Mesa
Branch: primitive-restart
Commit: f8e58886a9d87d6f0de2d1bfe5bc1c75bfbc935b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f8e58886a9d87d6f0de2d1bfe5bc1c75bfbc935b

Author: Brian Paul <brianp at vmware.com>
Date:   Sat Jul 17 07:28:01 2010 -0600

draw: redo primitive restart

Instead of testing for restart elements at the point/line/triangle
level, do it up at the very top of the draw-arrays code.  Scan the
elements array for restart indexes and simply draw the runs of
elements between the restarts.

All prim types (including tri fans) should work now.  Also, this
avoids the difficulty of flipping the triangle parity when restarting
tri strips.

---

 src/gallium/auxiliary/draw/draw_pipe.c      |  242 ++++++++++++++-------------
 src/gallium/auxiliary/draw/draw_pt.c        |  100 +++++++++++-
 src/gallium/auxiliary/draw/draw_pt_vcache.c |   30 +---
 3 files changed, 226 insertions(+), 146 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_pipe.c b/src/gallium/auxiliary/draw/draw_pipe.c
index c5d27c2..8cd75ec 100644
--- a/src/gallium/auxiliary/draw/draw_pipe.c
+++ b/src/gallium/auxiliary/draw/draw_pipe.c
@@ -109,74 +109,61 @@ void draw_pipeline_destroy( struct draw_context *draw )
 
 
 /**
- * Build primitive to render a point with vertex element e0.
+ * Build primitive to render a point with vertex at v0.
  */
-static INLINE void
-do_point(struct draw_context *draw,
-         char *buf, int stride, int e0)
-         
+static void do_point( struct draw_context *draw,
+		      const char *v0 )
 {
    struct prim_header prim;
    
    prim.flags = 0;
    prim.pad = 0;
-   prim.v[0] = (struct vertex_header *) (buf + stride * e0);
+   prim.v[0] = (struct vertex_header *)v0;
 
    draw->pipeline.first->point( draw->pipeline.first, &prim );
 }
 
 
 /**
- * Build primitive to render a line with vertex elements e0, e1.
+ * Build primitive to render a line with vertices at v0, v1.
  * \param flags  bitmask of DRAW_PIPE_EDGE_x, DRAW_PIPE_RESET_STIPPLE
  */
-static INLINE void
-do_line(struct draw_context *draw, ushort flags,
-        char *buf, int stride, int e0, int e1)
+static void do_line( struct draw_context *draw,
+                     ushort flags,
+		     const char *v0,
+		     const char *v1 )
 {
-   /* skip this prim if any vertex index is the restart index */
-   if (!(draw->primitive_restart &&
-         (e0 == draw->restart_index ||
-          e1 == draw->restart_index))) {
-      struct prim_header prim;
-
-      prim.flags = flags;
-      prim.pad = 0;
-      prim.v[0] = (struct vertex_header *) (buf + stride * e0);
-      prim.v[1] = (struct vertex_header *) (buf + stride * e1);
-
-      draw->pipeline.first->line( draw->pipeline.first, &prim );
-   }
+   struct prim_header prim;
+   
+   prim.flags = flags;
+   prim.pad = 0;
+   prim.v[0] = (struct vertex_header *)v0;
+   prim.v[1] = (struct vertex_header *)v1;
+
+   draw->pipeline.first->line( draw->pipeline.first, &prim );
 }
 
 
 /**
- * Build primitive to render a triangle with vertex elements e0, e1, e2.
+ * Build primitive to render a triangle with vertices at v0, v1, v2.
  * \param flags  bitmask of DRAW_PIPE_EDGE_x, DRAW_PIPE_RESET_STIPPLE
  */
-static INLINE void
-do_triangle(struct draw_context *draw, ushort flags,
-            char *buf, int stride, int e0, int e1, int e2)
+static void do_triangle( struct draw_context *draw,
+                         ushort flags,
+			 char *v0,
+			 char *v1,
+			 char *v2 )
 {
-   /* skip this prim if any vertex index is the restart index */
-   if (!(draw->primitive_restart &&
-         (e0 == draw->restart_index ||
-          e1 == draw->restart_index ||
-          e2 == draw->restart_index))) {
-      struct prim_header prim;
-
-      prim.v[0] = (struct vertex_header *) (buf + stride * e0);
-      prim.v[1] = (struct vertex_header *) (buf + stride * e1);
-      prim.v[2] = (struct vertex_header *) (buf + stride * e2);
-      prim.flags = flags;
-      prim.pad = 0;
-
-      draw->pipeline.first->tri( draw->pipeline.first, &prim );
-   }
-}
-
+   struct prim_header prim;
+   
+   prim.v[0] = (struct vertex_header *)v0;
+   prim.v[1] = (struct vertex_header *)v1;
+   prim.v[2] = (struct vertex_header *)v2;
+   prim.flags = flags;
+   prim.pad = 0;
 
-#define UNMASK(e) ((e) & ~DRAW_PIPE_FLAG_MASK)
+   draw->pipeline.first->tri( draw->pipeline.first, &prim );
+}
 
 
 /*
@@ -185,46 +172,53 @@ do_triangle(struct draw_context *draw, ushort flags,
  */
 
 /* 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,                                         \
-               UNMASK(elts[i0]), UNMASK(elts[i1]), UNMASK(elts[i2])); \
-   do_triangle(draw,                                                  \
-               (DRAW_PIPE_EDGE_FLAG_1 |                               \
-                DRAW_PIPE_EDGE_FLAG_2 ),                              \
-               verts, stride,                                         \
-               UNMASK(elts[i0]), UNMASK(elts[i2]), UNMASK(elts[i3]))
+#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] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK));    \
+   do_triangle( draw,                           \
+                ( DRAW_PIPE_EDGE_FLAG_1 |       \
+                  DRAW_PIPE_EDGE_FLAG_2 ),      \
+                verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i3] & ~DRAW_PIPE_FLAG_MASK))
 
 /* 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 |                               \
-                DRAW_PIPE_EDGE_FLAG_2),                               \
-               verts, stride,                                         \
-               UNMASK(elts[i0]), UNMASK(elts[i1]), UNMASK(elts[i3])); \
-   do_triangle(draw,                                                  \
-               (DRAW_PIPE_EDGE_FLAG_0 |                               \
-                DRAW_PIPE_EDGE_FLAG_1),                               \
-               verts, stride,                                         \
-               UNMASK(elts[i1]), UNMASK(elts[i2]), UNMASK(elts[i3]))
-
-#define TRIANGLE(flags, i0, i1, i2)                                   \
-   do_triangle(draw,                                                  \
-               elts[i0], /* flags */                                  \
-               verts, stride,                                         \
-               UNMASK(elts[i0]), UNMASK(elts[i1]), UNMASK(elts[i2]))
-
-#define LINE(flags, i0, i1)                        \
-   do_line(draw,                                   \
-           elts[i0], /* flags */                   \
-           verts, stride,                          \
-           UNMASK(elts[i0]), UNMASK(elts[i1]))
-
-#define POINT(i0)  do_point(draw, verts, stride, UNMASK(elts[i0]))
+#define QUAD_LAST_PV(i0,i1,i2,i3)               \
+   do_triangle( draw,                           \
+                ( DRAW_PIPE_RESET_STIPPLE |     \
+                  DRAW_PIPE_EDGE_FLAG_0 |       \
+                  DRAW_PIPE_EDGE_FLAG_2 ),      \
+                verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i3] & ~DRAW_PIPE_FLAG_MASK));    \
+   do_triangle( draw,                           \
+                ( DRAW_PIPE_EDGE_FLAG_0 |       \
+                  DRAW_PIPE_EDGE_FLAG_1 ),      \
+                verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i3] & ~DRAW_PIPE_FLAG_MASK))
+
+#define TRIANGLE(flags,i0,i1,i2)                                        \
+   do_triangle( draw,                                                   \
+                elts[i0],  /* flags */                                  \
+                verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK),     \
+                verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK) );
+
+#define LINE(flags,i0,i1)                                       \
+   do_line( draw,                                               \
+            elts[i0],                                           \
+            verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK), \
+            verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK) );
+
+#define POINT(i0)                               \
+   do_point( draw,                              \
+             verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK) )
 
 #define FUNC pipe_run
 #define ARGS                                    \
@@ -296,45 +290,53 @@ void draw_pipeline_run( struct draw_context *draw,
  */
 
 /* 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,                                \
-                UNMASK(i0), UNMASK(i1), UNMASK(i2));          \
-   do_triangle(draw,                                          \
-               (DRAW_PIPE_EDGE_FLAG_1 |                       \
-                DRAW_PIPE_EDGE_FLAG_2),                       \
-               verts, stride,                                 \
-               UNMASK(i0), UNMASK(i2), UNMASK(i3))
+#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) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK)); \
+   do_triangle( draw,                                            \
+                ( DRAW_PIPE_EDGE_FLAG_1 |                        \
+                  DRAW_PIPE_EDGE_FLAG_2 ),                       \
+                verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i3) & ~DRAW_PIPE_FLAG_MASK))
 
 /* 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 |                       \
-                DRAW_PIPE_EDGE_FLAG_2),                       \
-               verts, stride,                                 \
-               UNMASK(i0), UNMASK(i1), UNMASK(i3));           \
-   do_triangle(draw,                                          \
-               (DRAW_PIPE_EDGE_FLAG_0 |                       \
-                DRAW_PIPE_EDGE_FLAG_1),                       \
-               verts, stride,                                 \
-               UNMASK(i1), UNMASK(i2), UNMASK(i3))
-
-#define TRIANGLE(flags, i0, i1, i2)                           \
-   do_triangle(draw,                                          \
-               flags, /* flags */                             \
-               verts, stride,                                 \
-               UNMASK(i0), UNMASK(i1), UNMASK(i2))
-
-#define LINE(flags, i0, i1)                                \
-   do_line(draw,                                           \
-           flags, /* flags */                              \
-           verts, stride, UNMASK(i0), UNMASK(i1))
-
-#define POINT(i0)  do_point(draw, verts, stride, UNMASK(i0))
+#define QUAD_LAST_PV(i0,i1,i2,i3)                                \
+   do_triangle( draw,                                            \
+                ( DRAW_PIPE_RESET_STIPPLE |                      \
+                  DRAW_PIPE_EDGE_FLAG_0 |                        \
+                  DRAW_PIPE_EDGE_FLAG_2 ),                       \
+                verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i3) & ~DRAW_PIPE_FLAG_MASK)); \
+   do_triangle( draw,                                            \
+                ( DRAW_PIPE_EDGE_FLAG_0 |                        \
+                  DRAW_PIPE_EDGE_FLAG_1 ),                       \
+                verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i3) & ~DRAW_PIPE_FLAG_MASK))
+
+#define TRIANGLE(flags,i0,i1,i2)                                 \
+   do_triangle( draw,                                            \
+                flags,  /* flags */                              \
+                verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK),  \
+                verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK))
+
+#define LINE(flags,i0,i1)                                   \
+   do_line( draw,                                           \
+            flags,                                          \
+            verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK), \
+            verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK))
+
+#define POINT(i0)                               \
+   do_point( draw,                              \
+             verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK) )
 
 #define FUNC pipe_run_linear
 #define ARGS                                    \
diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c
index 1c8c861..45f5d3a 100644
--- a/src/gallium/auxiliary/draw/draw_pt.c
+++ b/src/gallium/auxiliary/draw/draw_pt.c
@@ -89,9 +89,6 @@ draw_pt_arrays(struct draw_context *draw,
          opt |= PT_PIPELINE;
       }
 
-      if (draw->primitive_restart)
-         opt |= PT_PIPELINE;
-
       if (draw_need_pipeline(draw,
                              draw->rasterizer,
                              gs_out_prim)) {
@@ -299,6 +296,92 @@ draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count)
 }
 
 
+static void
+draw_elements_restart(struct draw_context *draw, unsigned prim,
+                      unsigned start, unsigned count)
+{
+   /* XXX use a macro to consolidate the redundant code below. */
+   switch (draw->pt.user.eltSize) {
+   case 1:
+      {
+         const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts;
+         unsigned i, cur_start = start, cur_count = 0;
+
+         for (i = start; i < count; i++) {
+            if (elt_ub[i] == draw->restart_index) {
+               if (cur_count > 0) {
+                  /* draw elts up to prev pos */
+                  draw_pt_arrays(draw, prim, cur_start, cur_count);
+               }
+               /* begin new prim at next elt */
+               cur_start = i + 1;
+               cur_count = 0;
+            }
+            else {
+               cur_count++;
+            }
+         }
+         if (cur_count > 0) {
+            draw_pt_arrays(draw, prim, cur_start, cur_count);
+         }
+      }
+      break;
+   case 2:
+      {
+         const ushort *elt_us = (const ushort *) draw->pt.user.elts;
+         unsigned i, cur_start = start, cur_count = 0;
+
+         for (i = start; i < count; i++) {
+            if (elt_us[i] == draw->restart_index) {
+               if (cur_count > 0) {
+                  /* draw elts up to prev pos */
+                  draw_pt_arrays(draw, prim, cur_start, cur_count);
+               }
+               /* begin new prim at next elt */
+               cur_start = i + 1;
+               cur_count = 0;
+            }
+            else {
+               cur_count++;
+            }
+         }
+         if (cur_count > 0) {
+            draw_pt_arrays(draw, prim, cur_start, cur_count);
+         }
+      }
+      break;
+   case 4:
+      {
+         const uint *elt_ui = (const uint *) draw->pt.user.elts;
+         unsigned i, cur_start = start, cur_count = 0;
+
+         for (i = start; i < count; i++) {
+            if (elt_ui[i] == draw->restart_index) {
+               if (cur_count > 0) {
+                  /* draw elts up to prev pos */
+                  draw_pt_arrays(draw, prim, cur_start, cur_count);
+               }
+               /* begin new prim at next elt */
+               cur_start = i + 1;
+               cur_count = 0;
+            }
+            else {
+               cur_count++;
+            }
+         }
+         if (cur_count > 0) {
+            draw_pt_arrays(draw, prim, cur_start, cur_count);
+         }
+      }
+      break;
+   default:
+      assert(0 && "bad eltSize in draw_arrays()");
+      return;
+   }
+}
+
+
+
 /**
  * Draw vertex arrays
  * This is the main entrypoint into the drawing module.
@@ -355,6 +438,15 @@ draw_arrays_instanced(struct draw_context *draw,
 
    for (instance = 0; instance < instanceCount; instance++) {
       draw->instance_id = instance + startInstance;
-      draw_pt_arrays(draw, mode, start, count);
+
+      /* Check if primitive restart is enabled and we're drawing an
+       * indexed primitive.
+       */
+      if (draw->primitive_restart && draw->pt.user.elts) {
+         draw_elements_restart(draw, mode, start, count);
+      }
+      else {
+         draw_pt_arrays(draw, mode, start, count);
+      }
    }
 }
diff --git a/src/gallium/auxiliary/draw/draw_pt_vcache.c b/src/gallium/auxiliary/draw/draw_pt_vcache.c
index 2ae4ef5..20fa0fe 100644
--- a/src/gallium/auxiliary/draw/draw_pt_vcache.c
+++ b/src/gallium/auxiliary/draw/draw_pt_vcache.c
@@ -139,17 +139,10 @@ vcache_triangle_flags( struct vcache_frontend *vcache,
                        unsigned i1,
                        unsigned i2 )
 {
-   const struct draw_context *draw = vcache->draw;
-   /* skip this prim if any vertex index is the restart index */
-   if (!(draw->primitive_restart &&
-         (i0 == draw->restart_index ||
-          i1 == draw->restart_index ||
-          i2 == draw->restart_index))) {
-      vcache_elt(vcache, i0, flags);
-      vcache_elt(vcache, i1, 0);
-      vcache_elt(vcache, i2, 0);
-      vcache_check_flush(vcache);
-   }
+   vcache_elt(vcache, i0, flags);
+   vcache_elt(vcache, i1, 0);
+   vcache_elt(vcache, i2, 0);
+   vcache_check_flush(vcache);
 }
 
 static INLINE void 
@@ -169,15 +162,9 @@ vcache_line_flags( struct vcache_frontend *vcache,
                    unsigned i0,
                    unsigned i1 )
 {
-   const struct draw_context *draw = vcache->draw;
-   /* skip this prim if any vertex index is the restart index */
-   if (!(draw->primitive_restart &&
-         (i0 == draw->restart_index ||
-          i1 == draw->restart_index))) {
-      vcache_elt(vcache, i0, flags);
-      vcache_elt(vcache, i1, 0);
-      vcache_check_flush(vcache);
-   }
+   vcache_elt(vcache, i0, flags);
+   vcache_elt(vcache, i1, 0);
+   vcache_check_flush(vcache);
 }
 
 
@@ -376,8 +363,7 @@ vcache_check_run( struct draw_pt_front_end *frontend,
 
    if (elt_bias + max_index >= DRAW_PIPE_MAX_VERTICES ||
        fetch_count >= UNDEFINED_VERTEX_ID ||
-       fetch_count > draw_count ||
-       (draw->primitive_restart && draw->restart_index >= DRAW_PIPE_MAX_VERTICES)) {
+       fetch_count > draw_count) {
       if (0) debug_printf("fail\n");
       goto fail;
    }




More information about the mesa-commit mailing list