[Mesa-dev] [PATCH] st/mesa: rewrite the primitive restart fallback code

2011-11-16 Thread Brian Paul
Previously we were mapping/unmapping the index buffer each time we
found the restart index in the buffer.  This is bad when the restart
index is frequently used.  Now just map the index buffer once, scan
it to produce a list of sub-primitives, unmap the buffer, then draw
the sub-primitives.

Also, clean up the logic of testing for indexed primitives and calling
handle_fallback_primitive_restart().  Don't call it for non-indexed
primitives.
---
 src/mesa/state_tracker/st_draw.c |  224 +-
 1 files changed, 124 insertions(+), 100 deletions(-)

diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index cb518e1..bb7decf 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -648,45 +648,89 @@ check_uniforms(struct gl_context *ctx)
}
 }
 
-/** Helper code for primitive restart fallback */
-#define DO_DRAW(pipe, cur_start, cur_count) \
-   do { \
-  info.start = cur_start; \
-  info.count = cur_count; \
-  if (u_trim_pipe_prim(info.mode, &info.count)) { \
- if (transfer) \
-pipe_buffer_unmap(pipe, transfer); \
- pipe->draw_vbo(pipe, &info); \
- if (transfer) { \
-ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, 
&transfer); \
-assert(ptr != NULL); \
-ptr = ADD_POINTERS(ptr, ibuffer->offset); \
- } \
-  } \
-   } while(0)
-  
-/** More helper code for primitive restart fallback */
-#define PRIM_RESTART_LOOP(elements) \
-   do { \
-  for (i = start; i < end; i++) { \
- if (elements[i] == info.restart_index) { \
-if (cur_count > 0) { \
-   /* draw elts up to prev pos */ \
-   DO_DRAW(pipe, cur_start, cur_count); \
-} \
-/* begin new prim at next elt */ \
-cur_start = i + 1; \
-cur_count = 0; \
- } \
- else { \
-cur_count++; \
+
+struct sub_primitive
+{
+   unsigned start, count;
+};
+
+
+/**
+ * Scan the elements array to find restart indexes.  Return a list
+ * of primitive (start,count) pairs to indicate how to draw the sub-
+ * primitives delineated by the restart index.
+ */
+static struct sub_primitive *
+find_sub_primitives(const void *elements, unsigned element_size,
+unsigned start, unsigned end, unsigned restart_index,
+unsigned *num_sub_prims)
+{
+   const unsigned max_prims = end - start;
+   struct sub_primitive *sub_prims;
+   unsigned i, cur_start, cur_count, num;
+
+   sub_prims = (struct sub_primitive *)
+  malloc(max_prims * sizeof(struct sub_primitive));
+
+   if (!sub_prims) {
+  *num_sub_prims = 0;
+  return NULL;
+   }
+
+   cur_start = start;
+   cur_count = 0;
+   num = 0;
+
+#define SCAN_ELEMENTS(TYPE) \
+   for (i = start; i < end; i++) { \
+  if (((const TYPE *) elements)[i] == restart_index) { \
+ if (cur_count > 0) { \
+assert(num < max_prims); \
+sub_prims[num].start = cur_start; \
+sub_prims[num].count = cur_count; \
+num++; \
  } \
+ cur_start = i + 1; \
+ cur_count = 0; \
   } \
-  if (cur_count > 0) { \
- DO_DRAW(pipe, cur_start, cur_count); \
+  else { \
+ cur_count++; \
   } \
-   } while (0)
+   } \
+   if (cur_count > 0) { \
+  assert(num < max_prims); \
+  sub_prims[num].start = cur_start; \
+  sub_prims[num].count = cur_count; \
+  num++; \
+   }
 
+   switch (element_size) {
+   case 1:
+  SCAN_ELEMENTS(ubyte);
+  break;
+   case 2:
+  SCAN_ELEMENTS(ushort);
+  break;
+   case 4:
+  SCAN_ELEMENTS(uint);
+  break;
+   default:
+  assert(0 && "bad index_size in find_sub_primitives()");
+   }
+
+#undef SCAN_ELEMENTS
+
+   *num_sub_prims = num;
+
+   return sub_prims;
+}
+
+
+/**
+ * For gallium drivers that don't support the primitive restart
+ * feature, handle it here by breaking up the indexed primitive into
+ * sub-primitives.
+ */
 static void
 handle_fallback_primitive_restart(struct pipe_context *pipe,
   const struct _mesa_index_buffer *ib,
@@ -698,75 +742,57 @@ handle_fallback_primitive_restart(struct pipe_context 
*pipe,
const unsigned end = start + count;
struct pipe_draw_info info = *orig_info;
struct pipe_transfer *transfer = NULL;
-   unsigned instance, i, cur_start, cur_count;
-   const void *ptr;
-
-   info.primitive_restart = FALSE;
+   unsigned instance, i;
+   const void *ptr = NULL;
+   struct sub_primitive *sub_prims;
+   unsigned num_sub_prims;
 
-   if (!info.indexed) {
-  /* Splitting the draw arrays call is handled by the VBO module */
-  if (u_trim_pipe_prim(info.mode, &info.count))
- pipe->draw_vbo(pipe, &info);
+   assert(info.indexed);
+   assert(ibuffer->buffer);
+   assert(ib);
 
+   if (!ibuffer->buffer || !ib)
   return;
-   }
 
-   /* info.i

[Mesa-dev] [PATCH] st/mesa: rewrite the primitive restart fallback code

2011-11-17 Thread Brian Paul
Previously we were mapping/unmapping the index buffer each time we
found the restart index in the buffer.  This is bad when the restart
index is frequently used.  Now just map the index buffer once, scan
it to produce a list of sub-primitives, unmap the buffer, then draw
the sub-primitives.

Also, clean up the logic of testing for indexed primitives and calling
handle_fallback_primitive_restart().  Don't call it for non-indexed
primitives.

v2: per Jose, only map the relevant part of the index buffer with
pipe_buffer_map_range()
---
 src/mesa/state_tracker/st_draw.c |  227 +-
 1 files changed, 126 insertions(+), 101 deletions(-)

diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index cb518e1..6aa0bb6 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -648,45 +648,89 @@ check_uniforms(struct gl_context *ctx)
}
 }
 
-/** Helper code for primitive restart fallback */
-#define DO_DRAW(pipe, cur_start, cur_count) \
-   do { \
-  info.start = cur_start; \
-  info.count = cur_count; \
-  if (u_trim_pipe_prim(info.mode, &info.count)) { \
- if (transfer) \
-pipe_buffer_unmap(pipe, transfer); \
- pipe->draw_vbo(pipe, &info); \
- if (transfer) { \
-ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, 
&transfer); \
-assert(ptr != NULL); \
-ptr = ADD_POINTERS(ptr, ibuffer->offset); \
- } \
-  } \
-   } while(0)
-  
-/** More helper code for primitive restart fallback */
-#define PRIM_RESTART_LOOP(elements) \
-   do { \
-  for (i = start; i < end; i++) { \
- if (elements[i] == info.restart_index) { \
-if (cur_count > 0) { \
-   /* draw elts up to prev pos */ \
-   DO_DRAW(pipe, cur_start, cur_count); \
-} \
-/* begin new prim at next elt */ \
-cur_start = i + 1; \
-cur_count = 0; \
- } \
- else { \
-cur_count++; \
+
+struct sub_primitive
+{
+   unsigned start, count;
+};
+
+
+/**
+ * Scan the elements array to find restart indexes.  Return a list
+ * of primitive (start,count) pairs to indicate how to draw the sub-
+ * primitives delineated by the restart index.
+ */
+static struct sub_primitive *
+find_sub_primitives(const void *elements, unsigned element_size,
+unsigned start, unsigned end, unsigned restart_index,
+unsigned *num_sub_prims)
+{
+   const unsigned max_prims = end - start;
+   struct sub_primitive *sub_prims;
+   unsigned i, cur_start, cur_count, num;
+
+   sub_prims = (struct sub_primitive *)
+  malloc(max_prims * sizeof(struct sub_primitive));
+
+   if (!sub_prims) {
+  *num_sub_prims = 0;
+  return NULL;
+   }
+
+   cur_start = start;
+   cur_count = 0;
+   num = 0;
+
+#define SCAN_ELEMENTS(TYPE) \
+   for (i = start; i < end; i++) { \
+  if (((const TYPE *) elements)[i] == restart_index) { \
+ if (cur_count > 0) { \
+assert(num < max_prims); \
+sub_prims[num].start = cur_start; \
+sub_prims[num].count = cur_count; \
+num++; \
  } \
+ cur_start = i + 1; \
+ cur_count = 0; \
   } \
-  if (cur_count > 0) { \
- DO_DRAW(pipe, cur_start, cur_count); \
+  else { \
+ cur_count++; \
   } \
-   } while (0)
+   } \
+   if (cur_count > 0) { \
+  assert(num < max_prims); \
+  sub_prims[num].start = cur_start; \
+  sub_prims[num].count = cur_count; \
+  num++; \
+   }
 
+   switch (element_size) {
+   case 1:
+  SCAN_ELEMENTS(ubyte);
+  break;
+   case 2:
+  SCAN_ELEMENTS(ushort);
+  break;
+   case 4:
+  SCAN_ELEMENTS(uint);
+  break;
+   default:
+  assert(0 && "bad index_size in find_sub_primitives()");
+   }
+
+#undef SCAN_ELEMENTS
+
+   *num_sub_prims = num;
+
+   return sub_prims;
+}
+
+
+/**
+ * For gallium drivers that don't support the primitive restart
+ * feature, handle it here by breaking up the indexed primitive into
+ * sub-primitives.
+ */
 static void
 handle_fallback_primitive_restart(struct pipe_context *pipe,
   const struct _mesa_index_buffer *ib,
@@ -695,78 +739,61 @@ handle_fallback_primitive_restart(struct pipe_context 
*pipe,
 {
const unsigned start = orig_info->start;
const unsigned count = orig_info->count;
-   const unsigned end = start + count;
struct pipe_draw_info info = *orig_info;
struct pipe_transfer *transfer = NULL;
-   unsigned instance, i, cur_start, cur_count;
-   const void *ptr;
-
-   info.primitive_restart = FALSE;
+   unsigned instance, i;
+   const void *ptr = NULL;
+   struct sub_primitive *sub_prims;
+   unsigned num_sub_prims;
 
-   if (!info.indexed) {
-  /* Splitting the draw arrays call is handled by the VBO module */
-  if (u_trim_pipe_prim(info.mode, &info.count

Re: [Mesa-dev] [PATCH] st/mesa: rewrite the primitive restart fallback code

2011-11-18 Thread Jose Fonseca
- Original Message -
> Previously we were mapping/unmapping the index buffer each time we
> found the restart index in the buffer.  This is bad when the restart
> index is frequently used.  Now just map the index buffer once, scan
> it to produce a list of sub-primitives, unmap the buffer, then draw
> the sub-primitives.
> 
> Also, clean up the logic of testing for indexed primitives and
> calling
> handle_fallback_primitive_restart().  Don't call it for non-indexed
> primitives.
> 
> v2: per Jose, only map the relevant part of the index buffer with
> pipe_buffer_map_range()

Looks good Brian.

Before committing, could please just add a comment with the possible 
improvements (i.e., cache the restart indices when index buffer is not modified 
between calls, and use triangle strips w/ dummy zero-area triangles as 
suggested in 
http://msdn.microsoft.com/en-us/library/windows/desktop/bb206274(v=vs.85).aspx 
) for future reference.

These are actually nice projects for newbies BTW.

Jose
___
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev