#include "state.h"
#include "mtypes.h"
#include "macros.h"
+#include "enums.h"
#include "t_context.h"
#include "t_pipeline.h"
static void bind_inputs( GLcontext *ctx,
const struct gl_client_array *inputs[],
- GLint start, GLint end,
+ GLint min_index, GLint max_index,
struct gl_buffer_object **bo,
GLuint *nr_bo )
{
ptr = inputs[i]->Ptr;
/* Just make sure the array is floating point, otherwise convert to
- * temporary storage. Rebase arrays so that 'start' becomes
+ * temporary storage. Rebase arrays so that 'min_index' becomes
* element zero.
*
* XXX: remove the GLvector4f type at some stage and just use
* client arrays.
*/
- _tnl_import_array(ctx, i, start, end, inputs[i], ptr);
+ _tnl_import_array(ctx, i, min_index, max_index, inputs[i], ptr);
}
+ /* We process only the vertices between min & max index:
+ */
+ VB->Count = max_index - min_index;
+
+
/* Legacy pointers -- remove one day.
*/
VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
/* Translate indices to GLuints and store in VB->Elts.
*/
-static void bind_indicies( GLcontext *ctx,
- const struct _mesa_index_buffer *ib,
- struct gl_buffer_object **bo,
- GLuint *nr_bo)
+static void bind_indices( GLcontext *ctx,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ struct gl_buffer_object **bo,
+ GLuint *nr_bo)
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
- if (ib->type == GL_UNSIGNED_INT) {
+ if (ib->type == GL_UNSIGNED_INT && min_index == 0) {
VB->Elts = (GLuint *) ptr;
VB->Elts += ib->rebase;
}
VB->Elts = elts;
switch (ib->type) {
+ case GL_UNSIGNED_INT: {
+ const GLuint *in = ((GLuint *)ptr) + ib->rebase;
+ for (i = 0; i < ib->count; i++)
+ *elts++ = *in++ - min_index;
+ break;
+ }
case GL_UNSIGNED_SHORT: {
const GLushort *in = ((GLushort *)ptr) + ib->rebase;
for (i = 0; i < ib->count; i++)
- *elts++ = *in++;
+ *elts++ = (GLuint)(*in++) - min_index;
break;
}
case GL_UNSIGNED_BYTE: {
const GLubyte *in = ((GLubyte *)ptr) + ib->rebase;
for (i = 0; i < ib->count; i++)
- *elts++ = *in++;
+ *elts++ = (GLuint)(*in++) - min_index;
break;
}
}
}
}
+static void bind_prims( GLcontext *ctx,
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ GLuint min_index )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+
+ if (min_index != 0) {
+ struct _mesa_prim *tmp = (struct _mesa_prim *)get_space(ctx, nr_prims * sizeof(*prim));
+
+ for (i = 0; i < nr_prims; i++) {
+ tmp[i] = prim[i];
+ tmp[i].start -= min_index;
+ }
+
+ VB->Primitive = tmp;
+ }
+ else {
+ VB->Primitive = prim;
+ }
+
+ VB->PrimitiveCount = nr_prims;
+}
+
static void unmap_vbos( GLcontext *ctx,
struct gl_buffer_object **bo,
GLuint nr_bo )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
+ GLint max = VB->Size;
+ GLuint i;
- /* May need to map a vertex buffer object for every attribute plus
- * one for the index buffer.
- */
- struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
- GLuint nr_bo = 0;
-
- /* Binding inputs may imply mapping some vertex buffer objects.
- * They will need to be unmapped below.
+#ifdef TEST_SPLIT
+ max = 8 + MAX_CLIPPED_VERTICES;
+#endif
+
+ assert(max_index > min_index);
+ assert(!(max_index & 0x80000000));
+
+ VB->Elts = NULL;
+
+#if 0
+ _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+ for (i = 0; i < nr_prims; i++)
+ _mesa_printf("prim %d: %s start %d count %d\n", i,
+ _mesa_lookup_enum_by_nr(prim[i].mode),
+ prim[i].start,
+ prim[i].count);
+#endif
+
+ /* The software TNL pipeline has a fixed amount of storage for
+ * vertices and it is necessary to split incoming drawing commands
+ * if they exceed that limit.
*/
- bind_inputs(ctx, arrays, min_index, max_index, bo, &nr_bo);
- bind_indicies(ctx, ib, bo, &nr_bo);
+ if (max_index - min_index >= max - MAX_CLIPPED_VERTICES) {
+ struct split_limits limits;
+ limits.max_verts = max - MAX_CLIPPED_VERTICES;
+ limits.max_vb_size = ~0;
+ limits.max_indices = ~0;
+
+ /* This will split the buffers one way or another and
+ * recursively call back into this function.
+ */
+ vbo_split_prims( ctx, arrays, prim, nr_prims, ib,
+ min_index, max_index,
+ _tnl_draw_prims,
+ &limits );
+ }
+ else {
+ /* May need to map a vertex buffer object for every attribute plus
+ * one for the index buffer.
+ */
+ struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
+ GLuint nr_bo = 0;
- VB->Primitive = prim;
- VB->PrimitiveCount = nr_prims;
- VB->Count = max_index - min_index;
+ /* Binding inputs may imply mapping some vertex buffer objects.
+ * They will need to be unmapped below.
+ */
+ bind_inputs(ctx, arrays, min_index, max_index+1, bo, &nr_bo);
+ bind_indices(ctx, ib, min_index, bo, &nr_bo);
+ bind_prims(ctx, prim, nr_prims, VB->Elts ? 0 : min_index );
- TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
+ TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
- unmap_vbos(ctx, bo, nr_bo);
- free_space(ctx);
+ unmap_vbos(ctx, bo, nr_bo);
+ free_space(ctx);
+ }
}