st/mesa: Implement primitive restart in software
This commit is contained in:

committed by
Brian Paul

parent
d3561bd0bc
commit
72bd2b603b
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
if (!screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) {
|
||||
st->sw_primitive_restart = GL_TRUE;
|
||||
}
|
||||
|
||||
if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) {
|
||||
|
Reference in New Issue
Block a user