[Mesa-dev] [PATCH] st/mesa: rewrite the primitive restart fallback code
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
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
- 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