From 72bd2b603bc400371a92d34ab59dbb2d2ef7a123 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 15 Apr 2011 21:13:04 +0100 Subject: [PATCH] st/mesa: Implement primitive restart in software --- src/mesa/state_tracker/st_context.h | 1 + src/mesa/state_tracker/st_draw.c | 129 ++++++++++++++++++++++++++++++++- src/mesa/state_tracker/st_extensions.c | 5 +- 3 files changed, 132 insertions(+), 3 deletions(-) diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index 0a32202..c607809 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -75,6 +75,7 @@ struct st_context struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */ struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */ struct draw_stage *rastpos_stage; /**< For glRasterPos */ + GLboolean sw_primitive_restart; /* On old libGL's for linux we need to invalidate the drawables diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index 5748020..f027aea 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -582,6 +582,118 @@ 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)) \ + pipe->draw_vbo(pipe, &info); \ + } 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++; \ + } \ + } \ + if (cur_count > 0) { \ + DO_DRAW(pipe, cur_start, cur_count); \ + } \ + } while (0) + +static void +handle_fallback_primitive_restart(struct pipe_context *pipe, + struct pipe_index_buffer *ibuffer, + struct pipe_draw_info *orig_info) +{ + 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; + unsigned instance, i, cur_start, cur_count; + void *ptr; + + info.primitive_restart = FALSE; + + /* split the draw_arrays calls into two */ + if (!info.indexed) { +#if 0 + /* handled by VBO */ + if (info.restart_index >= info.min_index) { + info.count = MIN(info.restart_index-1, info.max_index) - info.start + 1; + if (u_trim_pipe_prim(info.mode, &info.count)) + pipe->draw_vbo(pipe, &info); + } + + if (info.restart_index <= info.max_index) { + info.start = MAX(info.min_index, info.restart_index + 1); + info.count = info.max_index - info.start + 1; + if (u_trim_pipe_prim(info.mode, &info.count)) + pipe->draw_vbo(pipe, &info); + } +#endif + if (u_trim_pipe_prim(info.mode, &info.count)) + pipe->draw_vbo(pipe, &info); + + return; + } + + /* info.indexed == TRUE */ + assert(ibuffer); + assert(ibuffer->buffer); + + ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, &transfer); + if (!ptr) + return; + ptr = ADD_POINTERS(ptr, ibuffer->offset); + + /* Need to loop over instances as well to preserve draw order */ + for (instance = 0; instance < orig_info->instance_count; instance++) { + info.start_instance = instance + orig_info->start_instance; + info.instance_count = 1; + cur_start = start; + cur_count = 0; + + switch (ibuffer->index_size) { + case 1: + { + const ubyte *elt_ub = (const ubyte *)ptr; + PRIM_RESTART_LOOP(elt_ub); + } + break; + case 2: + { + const ushort *elt_us = (const ushort *)ptr; + PRIM_RESTART_LOOP(elt_us); + } + break; + case 4: + { + const uint *elt_ui = (const uint *)ptr; + PRIM_RESTART_LOOP(elt_ui); + } + break; + default: + assert(0 && "bad index_size in handle_fallback_primitive_restart()"); + } + } + + pipe_buffer_unmap(pipe, transfer); +} + /** * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to @@ -794,7 +906,22 @@ st_draw_vbo(struct gl_context *ctx, info.max_index = info.start + info.count - 1; } - if (u_trim_pipe_prim(info.mode, &info.count)) + if (info.primitive_restart) { + /* + * Handle primitive restart for drivers that doesn't support it. + * + * The VBO module handles restart inside of draw_arrays for us, + * but we should still remove the primitive_restart flag on the + * info struct, the fallback function does this for us. Just + * remove the flag for all drivers in this case as well. + */ + if (st->sw_primitive_restart || !info.indexed) + handle_fallback_primitive_restart(pipe, &ibuffer, &info); + else + /* don't trim, restarts might be inside index list */ + pipe->draw_vbo(pipe, &info); + } + else if (u_trim_pipe_prim(info.mode, &info.count)) pipe->draw_vbo(pipe, &info); } diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index a1f0290..37f36de 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -555,8 +555,9 @@ void st_init_extensions(struct st_context *st) #endif } - if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) { - ctx->Extensions.NV_primitive_restart = GL_TRUE; + ctx->Extensions.NV_primitive_restart = GL_TRUE; + if (!screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) { + st->sw_primitive_restart = GL_TRUE; } if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) { -- 2.7.4