+/*
+ * Notes on primitive restart:
+ * The code below is used when the gallium driver does not support primitive
+ * restart itself. We map the index buffer, find the restart indexes, unmap
+ * the index buffer then draw the sub-primitives delineated by the restarts.
+ * A couple possible optimizations:
+ * 1. Save the list of sub-primitive (start, count) values in a list attached
+ * to the index buffer for re-use in subsequent draws. The list would be
+ * invalidated when the contents of the buffer changed.
+ * 2. If drawing triangle strips or quad strips, create a new index buffer
+ * that uses duplicated vertices to render the disjoint strips as one
+ * long strip. We'd have to be careful to avoid using too much memory
+ * for this.
+ * Finally, some apps might perform better if they don't use primitive restart
+ * at all rather than this fallback path. Set MESA_EXTENSION_OVERRIDE to
+ * "-GL_NV_primitive_restart" to test that.
+ */
+
+
+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; \
+ } \
+ else { \
+ cur_count++; \
+ } \
+ } \
+ 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 cso_context *cso,
+ struct pipe_context *pipe,
+ const struct _mesa_index_buffer *ib,
+ struct pipe_index_buffer *ibuffer,
+ struct pipe_draw_info *orig_info)
+{
+ const unsigned start = orig_info->start;
+ const unsigned count = orig_info->count;
+ struct pipe_draw_info info = *orig_info;
+ struct pipe_transfer *transfer = NULL;
+ unsigned instance, i;
+ const void *ptr = NULL;
+ struct sub_primitive *sub_prims;
+ unsigned num_sub_prims;
+
+ assert(info.indexed);
+ assert(ibuffer->buffer || ibuffer->user_buffer);
+ assert(ib);
+
+ if (!ibuffer->buffer || !ibuffer->user_buffer || !ib)
+ return;
+
+ info.primitive_restart = FALSE;
+ info.instance_count = 1;
+
+ if (_mesa_is_bufferobj(ib->obj)) {
+ ptr = pipe_buffer_map_range(pipe, ibuffer->buffer,
+ start * ibuffer->index_size, /* start */
+ count * ibuffer->index_size, /* length */
+ PIPE_TRANSFER_READ, &transfer);
+ if (!ptr)
+ return;
+
+ ptr = (uint8_t*)ptr + (ibuffer->offset - start * ibuffer->index_size);
+ }
+ else {
+ ptr = ib->ptr;
+ if (!ptr)
+ return;
+ }
+
+ sub_prims = find_sub_primitives(ptr, ibuffer->index_size,
+ 0, count, orig_info->restart_index,
+ &num_sub_prims);
+
+ if (transfer)
+ pipe_buffer_unmap(pipe, transfer);
+
+ /* Now draw the sub primitives.
+ * 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;
+ for (i = 0; i < num_sub_prims; i++) {
+ info.start = sub_prims[i].start;
+ info.count = sub_prims[i].count;
+ if (u_trim_pipe_prim(info.mode, &info.count)) {
+ cso_draw_vbo(cso, &info);
+ }
+ }
+ }
+
+ if (sub_prims)
+ free(sub_prims);
+}
+
+