/* This is the main entrypoint into the slimmed-down software tnl * module. In a regular swtnl driver, this can be plugged straight * into the vbo->Driver.DrawPrims() callback. */ void _tnl_draw_prims( struct gl_context *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index) { TNLcontext *tnl = TNL_CONTEXT(ctx); const GLuint TEST_SPLIT = 0; const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES; GLint max_basevertex = prim->basevertex; GLuint i; /* Mesa core state should have been validated already */ assert(ctx->NewState == 0x0); if (!_mesa_check_conditional_render(ctx)) return; /* don't draw */ for (i = 1; i < nr_prims; i++) max_basevertex = MAX2(max_basevertex, prim[i].basevertex); if (0) { printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); for (i = 0; i < nr_prims; i++) printf("prim %d: %s start %d count %d\n", i, _mesa_lookup_enum_by_nr(prim[i].mode), prim[i].start, prim[i].count); } if (min_index) { /* We always translate away calls with min_index != 0. */ vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, min_index, max_index, _tnl_vbo_draw_prims ); return; } else if ((GLint)max_index + max_basevertex > max) { /* 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. */ struct split_limits limits; limits.max_verts = max; 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, 0, max_index + prim->basevertex, _tnl_vbo_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; GLuint inst; for (i = 0; i < nr_prims;) { GLuint this_nr_prims; /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices * will rebase the elements to the basevertex, and we'll only * emit strings of prims with the same basevertex in one draw call. */ for (this_nr_prims = 1; i + this_nr_prims < nr_prims; this_nr_prims++) { if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) break; } assert(prim[i].num_instances > 0); /* Binding inputs may imply mapping some vertex buffer objects. * They will need to be unmapped below. */ for (inst = 0; inst < prim[i].num_instances; inst++) { bind_prims(ctx, &prim[i], this_nr_prims); bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1, bo, &nr_bo); bind_indices(ctx, ib, bo, &nr_bo); tnl->CurInstance = inst; TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); unmap_vbos(ctx, bo, nr_bo); free_space(ctx); } i += this_nr_prims; } } }
/* This is the main entrypoint into the slimmed-down software tnl * module. In a regular swtnl driver, this can be plugged straight * into the vbo->Driver.DrawPrims() callback. */ void _tnl_draw_prims( GLcontext *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index) { TNLcontext *tnl = TNL_CONTEXT(ctx); const GLuint TEST_SPLIT = 0; const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES; if (0) { GLuint i; _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); } if (min_index) { /* We always translate away calls with min_index != 0. */ vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, min_index, max_index, _tnl_draw_prims ); return; } else if (max_index >= max) { /* 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. */ struct split_limits limits; limits.max_verts = max; 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, 0, 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; /* Binding inputs may imply mapping some vertex buffer objects. * They will need to be unmapped below. */ bind_inputs(ctx, arrays, max_index+1, bo, &nr_bo); bind_indices(ctx, ib, bo, &nr_bo); bind_prims(ctx, prim, nr_prims ); TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); unmap_vbos(ctx, bo, nr_bo); free_space(ctx); } }