void vbo_split_prims(struct gl_context *ctx, const struct gl_vertex_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index, vbo_draw_func draw, const struct split_limits *limits) { if (ib) { if (limits->max_indices == 0) { /* Could traverse the indices, re-emitting vertices in turn. * But it's hard to see why this case would be needed - for * software tnl, it is better to convert to non-indexed * rendering after transformation is complete. Are there any devices * with hardware tnl that cannot do indexed rendering? * * For now, this path is disabled. */ assert(0); } else if (max_index - min_index >= limits->max_verts) { /* The vertex buffers are too large for hardware (or the * swtnl module). Traverse the indices, re-emitting vertices * in turn. Use a vertex cache to preserve some of the * sharing from the original index list. */ vbo_split_copy(ctx, arrays, prim, nr_prims, ib, draw, limits); } else if (ib->count > limits->max_indices) { /* The index buffer is too large for hardware. Try to split * on whole-primitive boundaries, otherwise try to split the * individual primitives. */ vbo_split_inplace(ctx, arrays, prim, nr_prims, ib, min_index, max_index, draw, limits); } else { /* Why were we called? */ assert(0); } } else { if (max_index - min_index >= limits->max_verts) { /* The vertex buffer is too large for hardware (or the swtnl * module). Try to split on whole-primitive boundaries, * otherwise try to split the individual primitives. */ vbo_split_inplace(ctx, arrays, prim, nr_prims, ib, min_index, max_index, draw, limits); } else { /* Why were we called? */ assert(0); } } }
/* Break large primitives into smaller ones. If not possible, convert * the primitive to indexed and pass to split_elts(). */ static void split_prims( struct split_context *split) { GLuint csr = 0; GLuint i; for (i = 0; i < split->nr_prims; i++) { const struct _mesa_prim *prim = &split->prim[i]; GLuint first, incr; GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr); GLuint count; /* Always wrap on an even numbered vertex to avoid problems with * triangle strips. */ GLuint available = align(split->limits->max_verts - csr - 1, 2); assert(split->limits->max_verts >= csr); if (prim->count < first) continue; count = prim->count - (prim->count - first) % incr; if ((available < count && !split_inplace) || (available < first && split_inplace)) { flush_vertex(split); csr = 0; available = align(split->limits->max_verts - csr - 1, 2); } if (available >= count) { struct _mesa_prim *outprim = next_outprim(split); *outprim = *prim; csr += prim->count; available = align(split->limits->max_verts - csr - 1, 2); } else if (split_inplace) { GLuint j, nr; for (j = 0 ; j < count ; ) { GLuint remaining = count - j; struct _mesa_prim *outprim = next_outprim(split); nr = MIN2( available, remaining ); nr -= (nr - first) % incr; outprim->mode = prim->mode; outprim->begin = (j == 0 && prim->begin); outprim->end = (nr == remaining && prim->end); outprim->start = prim->start + j; outprim->count = nr; if (nr == remaining) { /* Finished. */ j += nr; csr += nr; available = align(split->limits->max_verts - csr - 1, 2); } else { /* Wrapped the primitive: */ j += nr - (first - incr); flush_vertex(split); csr = 0; available = align(split->limits->max_verts - csr - 1, 2); } } } else if (split->ib == NULL) { /* XXX: could at least send the first max_verts off from the * inplace buffers. */ /* else convert to indexed primitive and pass to split_elts, * which will do the necessary copying and turn it back into a * vertex primitive for rendering... */ struct _mesa_index_buffer ib; struct _mesa_prim tmpprim; GLuint *elts = malloc(count * sizeof(GLuint)); GLuint j; for (j = 0; j < count; j++) elts[j] = prim->start + j; ib.count = count; ib.type = GL_UNSIGNED_INT; ib.obj = split->ctx->Shared->NullBufferObj; ib.ptr = elts; tmpprim = *prim; tmpprim.indexed = 1; tmpprim.start = 0; tmpprim.count = count; flush_vertex(split); vbo_split_copy(split->ctx, split->array, &tmpprim, 1, &ib, split->draw, split->limits); free(elts); } else { flush_vertex(split); vbo_split_copy(split->ctx, split->array, prim, 1, split->ib, split->draw, split->limits); } } flush_vertex(split); }