summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@vmware.com>2011-04-15 21:13:04 +0100
committerBrian Paul <brianp@vmware.com>2011-10-19 10:10:12 -0600
commit72bd2b603bc400371a92d34ab59dbb2d2ef7a123 (patch)
treeebac56def7878c680232e7574e8e52524cad0550
parentd3561bd0bc4a88ee0500460f8e0830a818e456a9 (diff)
st/mesa: Implement primitive restart in software
-rw-r--r--src/mesa/state_tracker/st_context.h1
-rw-r--r--src/mesa/state_tracker/st_draw.c129
-rw-r--r--src/mesa/state_tracker/st_extensions.c5
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 0a322022149..c6078098963 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 5748020842f..f027aea150f 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 a1f029089d0..37f36de9381 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)) {