static void replay_elts( struct copy_context *copy ) { GLuint i, j, k; GLboolean split; for (i = 0; i < copy->nr_prims; i++) { const struct _mesa_prim *prim = ©->prim[i]; const GLuint start = prim->start; GLuint first, incr; switch (prim->mode) { case GL_LINE_LOOP: /* Convert to linestrip and emit the final vertex explicitly, * but only in the resultant strip that requires it. */ j = 0; while (j != prim->count) { begin(copy, GL_LINE_STRIP, prim->begin && j == 0); for (split = GL_FALSE; j != prim->count && !split; j++) split = elt(copy, start + j); if (j == prim->count) { /* Done, emit final line. Split doesn't matter as * it is always raised a bit early so we can emit * the last verts if necessary! */ if (prim->end) (void)elt(copy, start + 0); end(copy, prim->end); } else { /* Wrap */ assert(split); end(copy, 0); j--; } } break; case GL_TRIANGLE_FAN: case GL_POLYGON: j = 2; while (j != prim->count) { begin(copy, prim->mode, prim->begin && j == 0); split = elt(copy, start+0); assert(!split); split = elt(copy, start+j-1); assert(!split); for (; j != prim->count && !split; j++) split = elt(copy, start+j); end(copy, prim->end && j == prim->count); if (j != prim->count) { /* Wrapped the primitive, need to repeat some vertices: */ j -= 1; } } break; default: (void)split_prim_inplace(prim->mode, &first, &incr); j = 0; while (j != prim->count) { begin(copy, prim->mode, prim->begin && j == 0); split = 0; for (k = 0; k < first; k++, j++) split |= elt(copy, start+j); assert(!split); for (; j != prim->count && !split; ) for (k = 0; k < incr; k++, j++) split |= elt(copy, start+j); end(copy, prim->end && j == prim->count); if (j != prim->count) { /* Wrapped the primitive, need to repeat some vertices: */ assert(j > first - incr); j -= (first - incr); } } break; } } if (copy->dstprim_nr) flush(copy); }
/* 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); }