static GLboolean vbo_maybe_split(struct gl_context *ctx, const struct gl_client_array **arrays, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index) { struct nouveau_context *nctx = to_nouveau_context(ctx); struct nouveau_render_state *render = to_render_state(ctx); struct nouveau_bufctx *bufctx = nctx->hw.bufctx; unsigned pushbuf_avail = PUSHBUF_DWORDS - 2 * (bufctx->relocs + render->attr_count), vert_avail = get_max_vertices(ctx, NULL, pushbuf_avail), idx_avail = get_max_vertices(ctx, ib, pushbuf_avail); int stride; /* Try to keep client buffers smaller than the scratch BOs. */ if (render->mode == VBO && (stride = get_max_client_stride(ctx, arrays))) vert_avail = MIN2(vert_avail, NOUVEAU_SCRATCH_SIZE / stride); if (max_index - min_index > vert_avail || (ib && ib->count > idx_avail)) { struct split_limits limits = { .max_verts = vert_avail, .max_indices = idx_avail, .max_vb_size = ~0, }; vbo_split_prims(ctx, arrays, prims, nr_prims, ib, min_index, max_index, TAG(vbo_render_prims), &limits); return GL_TRUE; } return GL_FALSE; } /* VBO rendering path. */ static GLboolean check_update_array(struct nouveau_array *a, unsigned offset, struct nouveau_bo *bo, int *pdelta) { int delta = *pdelta; GLboolean dirty; if (a->bo == bo) { if (delta < 0) delta = ((int)offset - (int)a->offset) / a->stride; dirty = (delta < 0 || offset != (a->offset + delta * a->stride)); } else { dirty = GL_TRUE; } *pdelta = (dirty ? 0 : delta); return dirty; }
/* 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 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 available = get_max_vertices(split, prim); GLuint count = prim->count - (prim->count - first) % incr; if (prim->count < first) continue; if ((available < count && !split_inplace) || (available < first && split_inplace)) { flush_vertex(split); available = get_max_vertices(split, prim); } if (available >= count) { struct _mesa_prim *outprim = next_outprim(split); *outprim = *prim; update_index_bounds(split, outprim); } 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; outprim->num_instances = prim->num_instances; outprim->base_instance = prim->base_instance; update_index_bounds(split, outprim); if (nr == remaining) { /* Finished. */ j += nr; } else { /* Wrapped the primitive: */ j += nr - (first - incr); flush_vertex(split); available = get_max_vertices(split, prim); } } } 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; tmpprim.num_instances = 1; tmpprim.base_instance = 0; 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); }