From 0791fdff6fe87cf9a29ddf4a716f1881c367c7de Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 23 Jan 2009 11:26:30 -0700 Subject: mesa: update tnl module for GL_EXT_vertex_array_bgra Add special case for GLubyte/GL_BGRA color arrays in _tnl_import_array() --- src/mesa/tnl/t_draw.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'src/mesa/tnl/t_draw.c') diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c index fd647c1f4a..2ec65d5323 100644 --- a/src/mesa/tnl/t_draw.c +++ b/src/mesa/tnl/t_draw.c @@ -88,6 +88,29 @@ static void free_space(GLcontext *ctx) } while (0) +/** + * Convert array of BGRA/GLubyte[4] values to RGBA/float[4] + * \param ptr input/ubyte array + * \param fptr output/float array + */ +static void +convert_bgra_to_float(const struct gl_client_array *input, + const GLubyte *ptr, GLfloat *fptr, + GLuint count ) +{ + GLuint i; + assert(input->Normalized); + assert(input->Size == 4); + for (i = 0; i < count; i++) { + const GLubyte *in = (GLubyte *) ptr; /* in is in BGRA order */ + *fptr++ = UBYTE_TO_FLOAT(in[2]); /* red */ + *fptr++ = UBYTE_TO_FLOAT(in[1]); /* green */ + *fptr++ = UBYTE_TO_FLOAT(in[0]); /* blue */ + *fptr++ = UBYTE_TO_FLOAT(in[3]); /* alpha */ + ptr += input->StrideB; + } +} + /* Adjust pointer to point at first requested element, convert to * floating point, populate VB->AttribPtr[]. @@ -112,7 +135,13 @@ static void _tnl_import_array( GLcontext *ctx, CONVERT(GLbyte, BYTE_TO_FLOAT); break; case GL_UNSIGNED_BYTE: - CONVERT(GLubyte, UBYTE_TO_FLOAT); + if (input->Format == GL_BGRA) { + /* See GL_EXT_vertex_array_bgra */ + convert_bgra_to_float(input, ptr, fptr, count); + } + else { + CONVERT(GLubyte, UBYTE_TO_FLOAT); + } break; case GL_SHORT: CONVERT(GLshort, SHORT_TO_FLOAT); -- cgit v1.2.3 From 2708ddfb06a36d8568e2aa130bf1f7d551fcd309 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 11 Aug 2009 12:31:01 -0700 Subject: vbo: Avoid extra validation of DrawElements. This saves mapping the index buffer to get a bounds on the indices that drivers just drop on the floor in the VBO case (cache win), saves a bonus walk of the indices in the CheckArrayBounds case, and other miscellaneous validation. On intel it's a particularly a large win (50-100% in my app) because even though we let the indices stay in both CPU and GPU caches, we still end up waiting for the GPU to be done with the buffer before reading from it. Drivers that want the min/max_index fields must now check index_bounds_valid and use vbo_get_minmax_index before using them. --- src/mesa/drivers/dri/i965/brw_draw.c | 53 +++------- src/mesa/drivers/dri/i965/brw_draw.h | 1 + src/mesa/drivers/dri/r300/r300_draw.c | 7 ++ src/mesa/state_tracker/st_cb_rasterpos.c | 2 +- src/mesa/state_tracker/st_draw.c | 5 + src/mesa/state_tracker/st_draw.h | 2 + src/mesa/state_tracker/st_draw_feedback.c | 4 + src/mesa/tnl/t_context.c | 2 +- src/mesa/tnl/t_draw.c | 18 +++- src/mesa/tnl/tnl.h | 10 ++ src/mesa/vbo/vbo.h | 6 +- src/mesa/vbo/vbo_exec_array.c | 158 ++++++++++++++++-------------- src/mesa/vbo/vbo_exec_draw.c | 1 + src/mesa/vbo/vbo_rebase.c | 1 + src/mesa/vbo/vbo_save_draw.c | 1 + src/mesa/vbo/vbo_split_copy.c | 1 + src/mesa/vbo/vbo_split_inplace.c | 1 + 17 files changed, 156 insertions(+), 117 deletions(-) (limited to 'src/mesa/tnl/t_draw.c') diff --git a/src/mesa/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c index 5152c3f3a5..8c94c904c1 100644 --- a/src/mesa/drivers/dri/i965/brw_draw.c +++ b/src/mesa/drivers/dri/i965/brw_draw.c @@ -422,54 +422,31 @@ static GLboolean brw_try_draw_prims( GLcontext *ctx, return retval; } -static GLboolean brw_need_rebase( GLcontext *ctx, - const struct gl_client_array *arrays[], - const struct _mesa_index_buffer *ib, - GLuint min_index ) -{ - if (min_index == 0) - return GL_FALSE; - - if (ib) { - if (!vbo_all_varyings_in_vbos(arrays)) - return GL_TRUE; - else - return GL_FALSE; - } - else { - /* Hmm. This isn't quite what I wanted. BRW can actually - * handle the mixed case well enough that we shouldn't need to - * rebase. However, it's probably not very common, nor hugely - * expensive to do it this way: - */ - if (!vbo_all_varyings_in_vbos(arrays)) - return GL_TRUE; - else - return GL_FALSE; - } -} - - void brw_draw_prims( GLcontext *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index ) { GLboolean retval; - /* Decide if we want to rebase. If so we end up recursing once - * only into this function. - */ - if (brw_need_rebase( ctx, arrays, ib, min_index )) { - vbo_rebase_prims( ctx, arrays, - prim, nr_prims, - ib, min_index, max_index, - brw_draw_prims ); - - return; + if (!vbo_all_varyings_in_vbos(arrays)) { + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index); + + /* Decide if we want to rebase. If so we end up recursing once + * only into this function. + */ + if (min_index != 0) { + vbo_rebase_prims(ctx, arrays, + prim, nr_prims, + ib, min_index, max_index, + brw_draw_prims ); + return; + } } /* Make a first attempt at drawing: diff --git a/src/mesa/drivers/dri/i965/brw_draw.h b/src/mesa/drivers/dri/i965/brw_draw.h index 9aebbdb1b8..2a14db217f 100644 --- a/src/mesa/drivers/dri/i965/brw_draw.h +++ b/src/mesa/drivers/dri/i965/brw_draw.h @@ -39,6 +39,7 @@ void brw_draw_prims( GLcontext *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index ); diff --git a/src/mesa/drivers/dri/r300/r300_draw.c b/src/mesa/drivers/dri/r300/r300_draw.c index fcfd309933..aedc6cfb2a 100644 --- a/src/mesa/drivers/dri/r300/r300_draw.c +++ b/src/mesa/drivers/dri/r300/r300_draw.c @@ -462,6 +462,7 @@ static void r300DrawPrims(GLcontext *ctx, const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index) { @@ -476,6 +477,12 @@ static void r300DrawPrims(GLcontext *ctx, limits.max_indices = 65535; limits.max_vb_size = 1024*1024; + /* This check should get folded into just the places that + * min/max index are really needed. + */ + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index); + if (min_index) { vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, min_index, max_index, r300DrawPrims ); return; diff --git a/src/mesa/state_tracker/st_cb_rasterpos.c b/src/mesa/state_tracker/st_cb_rasterpos.c index 3bcccd0df4..d82b2a2035 100644 --- a/src/mesa/state_tracker/st_cb_rasterpos.c +++ b/src/mesa/state_tracker/st_cb_rasterpos.c @@ -251,7 +251,7 @@ st_RasterPos(GLcontext *ctx, const GLfloat v[4]) rs->array[0].Ptr = (GLubyte *) v; /* draw the point */ - st_feedback_draw_vbo(ctx, rs->arrays, &rs->prim, 1, NULL, 0, 1); + st_feedback_draw_vbo(ctx, rs->arrays, &rs->prim, 1, NULL, GL_TRUE, 0, 1); } diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index 914a507bef..503a5f34a3 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -533,6 +533,7 @@ st_draw_vbo(GLcontext *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index) { @@ -545,6 +546,10 @@ st_draw_vbo(GLcontext *ctx, unsigned num_vbuffers, num_velements; GLboolean userSpace; + /* Gallium probably doesn't want this in some cases. */ + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); + /* sanity check for pointer arithmetic below */ assert(sizeof(arrays[0]->Ptr[0]) == 1); diff --git a/src/mesa/state_tracker/st_draw.h b/src/mesa/state_tracker/st_draw.h index dcfe7e1536..3e0face656 100644 --- a/src/mesa/state_tracker/st_draw.h +++ b/src/mesa/state_tracker/st_draw.h @@ -47,6 +47,7 @@ st_draw_vbo(GLcontext *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index); @@ -56,6 +57,7 @@ st_feedback_draw_vbo(GLcontext *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index); diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c index 2712c131c0..b2d682ef64 100644 --- a/src/mesa/state_tracker/st_draw_feedback.c +++ b/src/mesa/state_tracker/st_draw_feedback.c @@ -96,6 +96,7 @@ st_feedback_draw_vbo(GLcontext *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index) { @@ -114,6 +115,9 @@ st_feedback_draw_vbo(GLcontext *ctx, st_validate_state(ctx->st); + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); + /* must get these after state validation! */ vp = ctx->st->vp; vs = &st->vp->state; diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c index f69b122046..f2771cde09 100644 --- a/src/mesa/tnl/t_context.c +++ b/src/mesa/tnl/t_context.c @@ -81,7 +81,7 @@ _tnl_CreateContext( GLcontext *ctx ) tnl->nr_blocks = 0; /* plug in the VBO drawing function */ - vbo_set_draw_func(ctx, _tnl_draw_prims); + vbo_set_draw_func(ctx, _tnl_vbo_draw_prims); _math_init_transformation(); _math_init_translate(); diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c index 2ec65d5323..c64c2c2077 100644 --- a/src/mesa/tnl/t_draw.c +++ b/src/mesa/tnl/t_draw.c @@ -360,6 +360,20 @@ static void unmap_vbos( GLcontext *ctx, } +void _tnl_vbo_draw_prims(GLcontext *ctx, + const struct gl_client_array *arrays[], + const struct _mesa_prim *prim, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index) +{ + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index); + + _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); +} /* This is the main entrypoint into the slimmed-down software tnl * module. In a regular swtnl driver, this can be plugged straight @@ -393,7 +407,7 @@ void _tnl_draw_prims( GLcontext *ctx, */ vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, min_index, max_index, - _tnl_draw_prims ); + _tnl_vbo_draw_prims ); return; } else if (max_index > max) { @@ -411,7 +425,7 @@ void _tnl_draw_prims( GLcontext *ctx, */ vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 0, max_index, - _tnl_draw_prims, + _tnl_vbo_draw_prims, &limits ); } else { diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h index 4d628aa9a6..9c66d3b019 100644 --- a/src/mesa/tnl/tnl.h +++ b/src/mesa/tnl/tnl.h @@ -81,6 +81,16 @@ _tnl_draw_prims( GLcontext *ctx, GLuint min_index, GLuint max_index); +void +_tnl_vbo_draw_prims( GLcontext *ctx, + const struct gl_client_array *arrays[], + const struct _mesa_prim *prim, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index); + extern void _mesa_load_tracked_matrices(GLcontext *ctx); diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h index 5362226c2f..5986e93576 100644 --- a/src/mesa/vbo/vbo.h +++ b/src/mesa/vbo/vbo.h @@ -69,6 +69,7 @@ typedef void (*vbo_draw_func)( GLcontext *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, GLuint min_index, GLuint max_index ); @@ -112,7 +113,10 @@ void vbo_rebase_prims( GLcontext *ctx, GLuint min_index, GLuint max_index, vbo_draw_func draw ); - +void +vbo_get_minmax_index(GLcontext *ctx, const struct _mesa_prim *prim, + const struct _mesa_index_buffer *ib, + GLuint *min_index, GLuint *max_index); void vbo_use_buffer_objects(GLcontext *ctx); diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index f4b9b2f744..4fb4845f6b 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -41,15 +41,29 @@ /** * Compute min and max elements for glDraw[Range]Elements() calls. */ -static void -get_minmax_index(GLuint count, GLuint type, const GLvoid *indices, - GLuint *min_index, GLuint *max_index) +void +vbo_get_minmax_index(GLcontext *ctx, + const struct _mesa_prim *prim, + const struct _mesa_index_buffer *ib, + GLuint *min_index, GLuint *max_index) { GLuint i; + GLsizei count = prim->count; + const void *indices; + + if (ib->obj->Name) { + const GLvoid *map = ctx->Driver.MapBuffer(ctx, + GL_ELEMENT_ARRAY_BUFFER_ARB, + GL_READ_ONLY, + ib->obj); + indices = ADD_POINTERS(map, ib->ptr); + } else { + indices = ib->ptr; + } - switch(type) { + switch (ib->type) { case GL_UNSIGNED_INT: { - const GLuint *ui_indices = (const GLuint *)indices; + const GLuint *ui_indices = (const GLuint *)ib->ptr; GLuint max_ui = ui_indices[count-1]; GLuint min_ui = ui_indices[0]; for (i = 0; i < count; i++) { @@ -88,6 +102,12 @@ get_minmax_index(GLuint count, GLuint type, const GLvoid *indices, assert(0); break; } + + if (ib->obj->Name != 0) { + ctx->Driver.UnmapBuffer(ctx, + GL_ELEMENT_ARRAY_BUFFER_ARB, + ib->obj); + } } @@ -500,7 +520,7 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) prim[0].indexed = 0; vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, - start, start + count - 1 ); + GL_TRUE, start, start + count - 1 ); #if 0 print_draw_arrays(ctx, exec, mode, start, count); @@ -566,53 +586,19 @@ dump_element_buffer(GLcontext *ctx, GLenum type) ctx->Array.ElementArrayBufferObj); } - -static void GLAPIENTRY -vbo_exec_DrawRangeElements(GLenum mode, - GLuint start, GLuint end, - GLsizei count, GLenum type, const GLvoid *indices) +/* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */ +static void +vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, + GLboolean index_bounds_valid, + GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices) { - GET_CURRENT_CONTEXT(ctx); struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_index_buffer ib; struct _mesa_prim prim[1]; - if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, - type, indices )) - return; - - if (end >= ctx->Array.ArrayObj->_MaxElement) { - /* the max element is out of bounds of one or more enabled arrays */ - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " - "type 0x%x, indices=%p)\n" - "\tindex=%u is out of bounds (max=%u) " - "Element Buffer %u (size %d)", - start, end, count, type, indices, end, - ctx->Array.ArrayObj->_MaxElement - 1, - ctx->Array.ElementArrayBufferObj->Name, - ctx->Array.ElementArrayBufferObj->Size); - - if (0) - dump_element_buffer(ctx, type); - - if (0) - _mesa_print_arrays(ctx); - return; - } - else if (0) { - _mesa_printf("glDraw[Range]Elements" - "(start %u, end %u, type 0x%x, count %d) ElemBuf %u\n", - start, end, type, count, - ctx->Array.ElementArrayBufferObj->Name); - } - -#if 0 - check_draw_elements_data(ctx, count, type, indices); -#else - (void) check_draw_elements_data; -#endif - FLUSH_CURRENT( ctx, 0 ); if (ctx->NewState) @@ -623,13 +609,13 @@ vbo_exec_DrawRangeElements(GLenum mode, return; } - bind_arrays( ctx ); - if (ctx->NewState) _mesa_update_state( ctx ); + bind_arrays( ctx ); + ib.count = count; - ib.type = type; + ib.type = type; ib.obj = ctx->Array.ElementArrayBufferObj; ib.ptr = indices; @@ -673,44 +659,68 @@ vbo_exec_DrawRangeElements(GLenum mode, * for the latter case elsewhere. */ - vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, start, end ); + vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, + index_bounds_valid, start, end ); } - static void GLAPIENTRY -vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices) +vbo_exec_DrawRangeElements(GLenum mode, + GLuint start, GLuint end, + GLsizei count, GLenum type, const GLvoid *indices) { GET_CURRENT_CONTEXT(ctx); - GLuint min_index = 0; - GLuint max_index = 0; - if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) + if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, + type, indices )) return; - if (!vbo_validate_shaders(ctx)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawElements(bad shader)"); + if (end >= ctx->Array.ArrayObj->_MaxElement) { + /* the max element is out of bounds of one or more enabled arrays */ + _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " + "type 0x%x, indices=%p)\n" + "\tindex=%u is out of bounds (max=%u) " + "Element Buffer %u (size %d)", + start, end, count, type, indices, end, + ctx->Array.ArrayObj->_MaxElement - 1, + ctx->Array.ElementArrayBufferObj->Name, + ctx->Array.ElementArrayBufferObj->Size); + + if (0) + dump_element_buffer(ctx, type); + + if (0) + _mesa_print_arrays(ctx); return; } + else if (0) { + _mesa_printf("glDraw[Range]Elements" + "(start %u, end %u, type 0x%x, count %d) ElemBuf %u\n", + start, end, type, count, + ctx->Array.ElementArrayBufferObj->Name); + } - if (ctx->Array.ElementArrayBufferObj->Name) { - const GLvoid *map = ctx->Driver.MapBuffer(ctx, - GL_ELEMENT_ARRAY_BUFFER_ARB, - GL_READ_ONLY, - ctx->Array.ElementArrayBufferObj); +#if 0 + check_draw_elements_data(ctx, count, type, indices); +#else + (void) check_draw_elements_data; +#endif + + vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, + count, type, indices); +} - get_minmax_index(count, type, ADD_POINTERS(map, indices), - &min_index, &max_index); - ctx->Driver.UnmapBuffer(ctx, - GL_ELEMENT_ARRAY_BUFFER_ARB, - ctx->Array.ElementArrayBufferObj); - } - else { - get_minmax_index(count, type, indices, &min_index, &max_index); - } +static void GLAPIENTRY +vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices) +{ + GET_CURRENT_CONTEXT(ctx); + + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) + return; - vbo_exec_DrawRangeElements(mode, min_index, max_index, count, type, indices); + vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, + count, type, indices); } diff --git a/src/mesa/vbo/vbo_exec_draw.c b/src/mesa/vbo/vbo_exec_draw.c index 18419928b2..a988424d21 100644 --- a/src/mesa/vbo/vbo_exec_draw.c +++ b/src/mesa/vbo/vbo_exec_draw.c @@ -378,6 +378,7 @@ vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ) exec->vtx.prim, exec->vtx.prim_count, NULL, + GL_TRUE, 0, exec->vtx.vert_count - 1); diff --git a/src/mesa/vbo/vbo_rebase.c b/src/mesa/vbo/vbo_rebase.c index ea87dede64..3bf7ef580f 100644 --- a/src/mesa/vbo/vbo_rebase.c +++ b/src/mesa/vbo/vbo_rebase.c @@ -208,6 +208,7 @@ void vbo_rebase_prims( GLcontext *ctx, prim, nr_prims, ib, + GL_TRUE, 0, max_index - min_index ); diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c index 5110648c28..d834fa1f2e 100644 --- a/src/mesa/vbo/vbo_save_draw.c +++ b/src/mesa/vbo/vbo_save_draw.c @@ -279,6 +279,7 @@ void vbo_save_playback_vertex_list( GLcontext *ctx, void *data ) node->prim, node->prim_count, NULL, + GL_TRUE, 0, /* Node is a VBO, so this is ok */ node->count - 1); } diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c index d7ffebf607..3f8a222805 100644 --- a/src/mesa/vbo/vbo_split_copy.c +++ b/src/mesa/vbo/vbo_split_copy.c @@ -194,6 +194,7 @@ flush( struct copy_context *copy ) copy->dstprim, copy->dstprim_nr, ©->dstib, + GL_TRUE, 0, copy->dstbuf_nr ); diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c index 9628227e7c..da84eaa6ea 100644 --- a/src/mesa/vbo/vbo_split_inplace.c +++ b/src/mesa/vbo/vbo_split_inplace.c @@ -85,6 +85,7 @@ static void flush_vertex( struct split_context *split ) split->dstprim, split->dstprim_nr, NULL, + GL_TRUE, min_index, max_index); -- cgit v1.2.3 From 92d7ed8a20d4a018ce5324e6537ae7b478b9e5bf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 27 Aug 2009 10:09:24 -0700 Subject: mesa: Add support for ARB_draw_elements_base_vertex. --- src/mesa/drivers/dri/swrast/swrast.c | 2 + src/mesa/drivers/x11/xm_api.c | 2 + src/mesa/main/api_noop.c | 78 ++++++++++++++++++++- src/mesa/main/api_noop.h | 7 ++ src/mesa/main/api_validate.c | 108 +++++++++++------------------ src/mesa/main/api_validate.h | 4 +- src/mesa/main/dd.h | 17 ++++- src/mesa/main/dlist.c | 3 + src/mesa/main/extensions.c | 2 + src/mesa/main/mtypes.h | 1 + src/mesa/main/varray.h | 15 ++++ src/mesa/main/vtxfmt.c | 3 + src/mesa/main/vtxfmt_tmp.h | 41 +++++++++++ src/mesa/tnl/t_draw.c | 58 +++++++++++----- src/mesa/vbo/vbo.h | 1 + src/mesa/vbo/vbo_exec_array.c | 131 ++++++++++++++++++++++++++++++----- src/mesa/vbo/vbo_rebase.c | 15 +++- src/mesa/vbo/vbo_save_api.c | 36 +++++++++- src/mesa/vbo/vbo_split.c | 8 ++- src/mesa/vbo/vbo_split_copy.c | 52 ++++++++------ 20 files changed, 453 insertions(+), 131 deletions(-) (limited to 'src/mesa/tnl/t_draw.c') diff --git a/src/mesa/drivers/dri/swrast/swrast.c b/src/mesa/drivers/dri/swrast/swrast.c index 2d2aa5e0f1..3016987d56 100644 --- a/src/mesa/drivers/dri/swrast/swrast.c +++ b/src/mesa/drivers/dri/swrast/swrast.c @@ -62,6 +62,7 @@ #define need_GL_SGI_color_table /* sw extensions not associated with some GL version */ +#define need_GL_ARB_draw_elements_base_vertex #define need_GL_ARB_shader_objects #define need_GL_ARB_vertex_array_object #define need_GL_ARB_vertex_program @@ -96,6 +97,7 @@ const struct dri_extension card_extensions[] = { "GL_SGI_color_table", GL_SGI_color_table_functions }, { "GL_ARB_depth_clamp", NULL }, + { "GL_ARB_draw_elements_base_vertex", GL_ARB_draw_elements_base_vertex_functions }, { "GL_ARB_shader_objects", GL_ARB_shader_objects_functions }, { "GL_ARB_vertex_array_object", GL_ARB_vertex_array_object_functions }, { "GL_ARB_vertex_program", GL_ARB_vertex_program_functions }, diff --git a/src/mesa/drivers/x11/xm_api.c b/src/mesa/drivers/x11/xm_api.c index 777635b783..662c61ae7e 100644 --- a/src/mesa/drivers/x11/xm_api.c +++ b/src/mesa/drivers/x11/xm_api.c @@ -1317,6 +1317,7 @@ xmesa_convert_from_x_visual_type( int visualType ) #define need_GL_SGI_color_table /* sw extensions not associated with some GL version */ +#define need_GL_ARB_draw_elements_base_vertex #define need_GL_ARB_shader_objects #define need_GL_ARB_sync #define need_GL_ARB_vertex_program @@ -1348,6 +1349,7 @@ const struct dri_extension card_extensions[] = { "GL_SGI_color_table", GL_SGI_color_table_functions }, { "GL_ARB_depth_clamp", NULL }, + { "GL_ARB_draw_elements_base_vertex", GL_ARB_draw_elements_base_vertex_functions }, { "GL_ARB_shader_objects", GL_ARB_shader_objects_functions }, { "GL_ARB_sync", GL_ARB_sync_functions }, { "GL_ARB_vertex_program", GL_ARB_vertex_program_functions }, diff --git a/src/mesa/main/api_noop.c b/src/mesa/main/api_noop.c index 09ba7e5062..0b669e7e7f 100644 --- a/src/mesa/main/api_noop.c +++ b/src/mesa/main/api_noop.c @@ -731,7 +731,7 @@ _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type, GET_CURRENT_CONTEXT(ctx); GLint i; - if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) return; CALL_Begin(GET_DISPATCH(), (mode)); @@ -757,6 +757,43 @@ _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type, CALL_End(GET_DISPATCH(), ()); } +static void GLAPIENTRY +_mesa_noop_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, + basevertex )) + return; + + CALL_Begin(GET_DISPATCH(), (mode)); + + switch (type) { + case GL_UNSIGNED_BYTE: + for (i = 0 ; i < count ; i++) + CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] + + basevertex)); + break; + case GL_UNSIGNED_SHORT: + for (i = 0 ; i < count ; i++) + CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] + + basevertex )); + break; + case GL_UNSIGNED_INT: + for (i = 0 ; i < count ; i++) + CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] + + basevertex )); + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElementsBaseVertex(type)" ); + break; + } + + CALL_End(GET_DISPATCH(), ()); +} + static void GLAPIENTRY _mesa_noop_DrawRangeElements(GLenum mode, @@ -768,7 +805,7 @@ _mesa_noop_DrawRangeElements(GLenum mode, if (_mesa_validate_DrawRangeElements( ctx, mode, start, end, - count, type, indices )) + count, type, indices, 0 )) CALL_DrawElements(GET_DISPATCH(), (mode, count, type, indices)); } @@ -786,6 +823,40 @@ _mesa_noop_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, } } +static void GLAPIENTRY +_mesa_noop_DrawRangeElementsBaseVertex(GLenum mode, + GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex) +{ + GET_CURRENT_CONTEXT(ctx); + + if (_mesa_validate_DrawRangeElements( ctx, mode, + start, end, + count, type, indices, basevertex )) + CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count, type, indices, + basevertex)); +} + +/* GL_EXT_multi_draw_arrays */ +void GLAPIENTRY +_mesa_noop_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, + GLenum type, + const GLvoid **indices, + GLsizei primcount, + const GLint *basevertex) +{ + GLsizei i; + + for (i = 0; i < primcount; i++) { + if (count[i] > 0) { + CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type, + indices[i], + basevertex[i])); + } + } +} + /* * Eval Mesh */ @@ -995,6 +1066,9 @@ _mesa_noop_vtxfmt_init( GLvertexformat *vfmt ) vfmt->DrawElements = _mesa_noop_DrawElements; vfmt->DrawRangeElements = _mesa_noop_DrawRangeElements; vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; + vfmt->DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex; + vfmt->DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex; + vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; vfmt->EvalMesh1 = _mesa_noop_EvalMesh1; vfmt->EvalMesh2 = _mesa_noop_EvalMesh2; } diff --git a/src/mesa/main/api_noop.h b/src/mesa/main/api_noop.h index a7956d00b3..1150984d64 100644 --- a/src/mesa/main/api_noop.h +++ b/src/mesa/main/api_noop.h @@ -44,6 +44,13 @@ extern void GLAPIENTRY _mesa_noop_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount); +extern void GLAPIENTRY +_mesa_noop_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, + GLenum type, + const GLvoid **indices, + GLsizei primcount, + const GLint *basevertex); + extern void _mesa_noop_vtxfmt_init(GLvertexformat *vfmt); diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 2df4f17389..4a1448deee 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -29,7 +29,7 @@ #include "imports.h" #include "mtypes.h" #include "state.h" - +#include "vbo/vbo.h" /** @@ -51,51 +51,6 @@ index_bytes(GLenum type, GLsizei count) } -/** - * Find the max index in the given element/index buffer - */ -static GLuint -max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, - const void *indices, - struct gl_buffer_object *elementBuf) -{ - const GLubyte *map = NULL; - GLuint max = 0; - GLuint i; - - if (_mesa_is_bufferobj(elementBuf)) { - /* elements are in a user-defined buffer object. need to map it */ - map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, - GL_READ_ONLY, elementBuf); - /* Actual address is the sum of pointers */ - indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); - } - - if (type == GL_UNSIGNED_INT) { - for (i = 0; i < count; i++) - if (((GLuint *) indices)[i] > max) - max = ((GLuint *) indices)[i]; - } - else if (type == GL_UNSIGNED_SHORT) { - for (i = 0; i < count; i++) - if (((GLushort *) indices)[i] > max) - max = ((GLushort *) indices)[i]; - } - else { - ASSERT(type == GL_UNSIGNED_BYTE); - for (i = 0; i < count; i++) - if (((GLubyte *) indices)[i] > max) - max = ((GLubyte *) indices)[i]; - } - - if (map) { - ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); - } - - return max; -} - - /** * Check if OK to draw arrays/elements. */ @@ -124,6 +79,40 @@ check_valid_to_render(GLcontext *ctx, const char *function) return GL_TRUE; } +static GLboolean +check_index_bounds(GLcontext *ctx, GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex) +{ + struct _mesa_prim prim; + struct _mesa_index_buffer ib; + GLuint min, max; + + /* Only the X Server needs to do this -- otherwise, accessing outside + * array/BO bounds allows application termination. + */ + if (!ctx->Const.CheckArrayBounds) + return GL_TRUE; + + memset(&prim, 0, sizeof(prim)); + prim.count = count; + + memset(&ib, 0, sizeof(ib)); + ib.type = type; + ib.ptr = indices; + ib.obj = ctx->Array.ElementArrayBufferObj; + + vbo_get_minmax_index(ctx, &prim, &ib, &min, &max); + + if (min + basevertex < 0 || + max + basevertex > ctx->Array.ArrayObj->_MaxElement) { + /* the max element is out of bounds of one or more enabled arrays */ + _mesa_warning(ctx, "glDrawElements() index=%u is " + "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); + return GL_FALSE; + } + + return GL_TRUE; +} /** * Error checking for glDrawElements(). Includes parameter checking @@ -133,7 +122,7 @@ check_valid_to_render(GLcontext *ctx, const char *function) GLboolean _mesa_validate_DrawElements(GLcontext *ctx, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices) + const GLvoid *indices, GLint basevertex) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); @@ -177,17 +166,8 @@ _mesa_validate_DrawElements(GLcontext *ctx, return GL_FALSE; } - if (ctx->Const.CheckArrayBounds) { - /* find max array index */ - GLuint max = max_buffer_index(ctx, count, type, indices, - ctx->Array.ElementArrayBufferObj); - if (max >= ctx->Array.ArrayObj->_MaxElement) { - /* the max element is out of bounds of one or more enabled arrays */ - _mesa_warning(ctx, "glDrawElements() index=%u is " - "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); - return GL_FALSE; - } - } + if (!check_index_bounds(ctx, count, type, indices, basevertex)) + return GL_FALSE; return GL_TRUE; } @@ -202,7 +182,7 @@ GLboolean _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, - const GLvoid *indices) + const GLvoid *indices, GLint basevertex) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); @@ -250,14 +230,8 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, return GL_FALSE; } - if (ctx->Const.CheckArrayBounds) { - GLuint max = max_buffer_index(ctx, count, type, indices, - ctx->Array.ElementArrayBufferObj); - if (max >= ctx->Array.ArrayObj->_MaxElement) { - /* the max element is out of bounds of one or more enabled arrays */ - return GL_FALSE; - } - } + if (!check_index_bounds(ctx, count, type, indices, basevertex)) + return GL_FALSE; return GL_TRUE; } diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h index 10f0c34e66..1d3ae157d7 100644 --- a/src/mesa/main/api_validate.h +++ b/src/mesa/main/api_validate.h @@ -37,13 +37,13 @@ _mesa_validate_DrawArrays(GLcontext *ctx, extern GLboolean _mesa_validate_DrawElements(GLcontext *ctx, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices); + const GLvoid *indices, GLint basevertex); extern GLboolean _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, - const GLvoid *indices); + const GLvoid *indices, GLint basevertex); #endif diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 4a700b5cb4..ce5e158626 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -1172,7 +1172,22 @@ typedef struct { GLenum type, const GLvoid **indices, GLsizei primcount); - /*@}*/ + void (GLAPIENTRYP DrawElementsBaseVertex)( GLenum mode, GLsizei count, + GLenum type, + const GLvoid *indices, + GLint basevertex ); + void (GLAPIENTRYP DrawRangeElementsBaseVertex)( GLenum mode, GLuint start, + GLuint end, GLsizei count, + GLenum type, + const GLvoid *indices, + GLint basevertex); + void (GLAPIENTRYP MultiDrawElementsBaseVertex)( GLenum mode, + const GLsizei *count, + GLenum type, + const GLvoid **indices, + GLsizei primcount, + const GLint *basevertex); + /*@}*/ /** * \name Eval diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c index 8cff9ea64a..d721f699fd 100644 --- a/src/mesa/main/dlist.c +++ b/src/mesa/main/dlist.c @@ -8711,6 +8711,9 @@ _mesa_save_vtxfmt_init(GLvertexformat * vfmt) vfmt->DrawElements = 0; vfmt->DrawRangeElements = 0; vfmt->MultiDrawElemementsEXT = 0; + vfmt->DrawElementsBaseVertex = 0; + vfmt->DrawRangeElementsBaseVertex = 0; + vfmt->MultiDrawElemementsBaseVertex = 0; #endif } diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index d0e77bafdd..2ad66de7dd 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -49,6 +49,7 @@ static const struct { { OFF, "GL_ARB_depth_texture", F(ARB_depth_texture) }, { OFF, "GL_ARB_depth_clamp", F(ARB_depth_clamp) }, { ON, "GL_ARB_draw_buffers", F(ARB_draw_buffers) }, + { OFF, "GL_ARB_draw_elements_base_vertex", F(ARB_draw_elements_base_vertex) }, { OFF, "GL_ARB_fragment_program", F(ARB_fragment_program) }, { OFF, "GL_ARB_fragment_program_shadow", F(ARB_fragment_program_shadow) }, { OFF, "GL_ARB_fragment_shader", F(ARB_fragment_shader) }, @@ -197,6 +198,7 @@ _mesa_enable_sw_extensions(GLcontext *ctx) ctx->Extensions.ARB_depth_clamp = GL_TRUE; ctx->Extensions.ARB_depth_texture = GL_TRUE; /*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/ + ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE; #if FEATURE_ARB_fragment_program ctx->Extensions.ARB_fragment_program = GL_TRUE; ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE; diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 20cd3aa5c0..ae169fb9db 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2478,6 +2478,7 @@ struct gl_extensions GLboolean ARB_depth_texture; GLboolean ARB_depth_clamp; GLboolean ARB_draw_buffers; + GLboolean ARB_draw_elements_base_vertex; GLboolean ARB_fragment_program; GLboolean ARB_fragment_program_shadow; GLboolean ARB_fragment_shader; diff --git a/src/mesa/main/varray.h b/src/mesa/main/varray.h index becc67c29d..ef790c504e 100644 --- a/src/mesa/main/varray.h +++ b/src/mesa/main/varray.h @@ -129,6 +129,11 @@ extern void GLAPIENTRY _mesa_MultiDrawElementsEXT( GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount ); +extern void GLAPIENTRY +_mesa_MultiDrawElementsBaseVertex( GLenum mode, + const GLsizei *count, GLenum type, + const GLvoid **indices, GLsizei primcount, + const GLint *basevertex); extern void GLAPIENTRY _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first, @@ -159,6 +164,16 @@ extern void GLAPIENTRY _mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +extern void GLAPIENTRY +_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex); + +extern void GLAPIENTRY +_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices, + GLint basevertex); + extern void _mesa_copy_client_array(GLcontext *ctx, diff --git a/src/mesa/main/vtxfmt.c b/src/mesa/main/vtxfmt.c index 8d6f560a80..91412f138a 100644 --- a/src/mesa/main/vtxfmt.c +++ b/src/mesa/main/vtxfmt.c @@ -134,6 +134,9 @@ install_vtxfmt( struct _glapi_table *tab, const GLvertexformat *vfmt ) SET_DrawElements(tab, vfmt->DrawElements); SET_DrawRangeElements(tab, vfmt->DrawRangeElements); SET_MultiDrawElementsEXT(tab, vfmt->MultiDrawElementsEXT); + SET_DrawElementsBaseVertex(tab, vfmt->DrawElementsBaseVertex); + SET_DrawRangeElementsBaseVertex(tab, vfmt->DrawRangeElementsBaseVertex); + SET_MultiDrawElementsBaseVertex(tab, vfmt->MultiDrawElementsBaseVertex); SET_EvalMesh1(tab, vfmt->EvalMesh1); SET_EvalMesh2(tab, vfmt->EvalMesh2); ASSERT(tab->EvalMesh2); diff --git a/src/mesa/main/vtxfmt_tmp.h b/src/mesa/main/vtxfmt_tmp.h index 1308d0aa46..d56a2bb95e 100644 --- a/src/mesa/main/vtxfmt_tmp.h +++ b/src/mesa/main/vtxfmt_tmp.h @@ -354,6 +354,44 @@ static void GLAPIENTRY TAG(DrawRangeElements)( GLenum mode, GLuint start, CALL_DrawRangeElements(GET_DISPATCH(), ( mode, start, end, count, type, indices )); } +static void GLAPIENTRY TAG(DrawElementsBaseVertex)( GLenum mode, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLint basevertex) +{ + PRE_LOOPBACK( DrawElementsBaseVertex ); + CALL_DrawElementsBaseVertex(GET_DISPATCH(), ( mode, count, type, + indices, basevertex )); +} + +static void GLAPIENTRY TAG(DrawRangeElementsBaseVertex)( GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLint basevertex) +{ + PRE_LOOPBACK( DrawRangeElementsBaseVertex ); + CALL_DrawRangeElementsBaseVertex(GET_DISPATCH(), ( mode, start, end, + count, type, indices, + basevertex )); +} + +static void GLAPIENTRY TAG(MultiDrawElementsBaseVertex)( GLenum mode, + const GLsizei *count, + GLenum type, + const GLvoid **indices, + GLsizei primcount, + const GLint *basevertex) +{ + PRE_LOOPBACK( MultiDrawElementsBaseVertex ); + CALL_MultiDrawElementsBaseVertex(GET_DISPATCH(), ( mode, count, type, + indices, + primcount, basevertex )); +} + static void GLAPIENTRY TAG(EvalMesh1)( GLenum mode, GLint i1, GLint i2 ) { PRE_LOOPBACK( EvalMesh1 ); @@ -534,6 +572,9 @@ static GLvertexformat TAG(vtxfmt) = { TAG(DrawElements), TAG(DrawRangeElements), TAG(MultiDrawElementsEXT), + TAG(DrawElementsBaseVertex), + TAG(DrawRangeElementsBaseVertex), + TAG(MultiDrawElementsBaseVertex), TAG(EvalMesh1), TAG(EvalMesh2) }; diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c index c64c2c2077..04fa106300 100644 --- a/src/mesa/tnl/t_draw.c +++ b/src/mesa/tnl/t_draw.c @@ -316,22 +316,27 @@ static void bind_indices( GLcontext *ctx, ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr); - if (ib->type == GL_UNSIGNED_INT) { + if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) { VB->Elts = (GLuint *) ptr; } else { GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint)); VB->Elts = elts; - if (ib->type == GL_UNSIGNED_SHORT) { + if (ib->type == GL_UNSIGNED_INT) { + const GLuint *in = (GLuint *)ptr; + for (i = 0; i < ib->count; i++) + *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; + } + else if (ib->type == GL_UNSIGNED_SHORT) { const GLushort *in = (GLushort *)ptr; for (i = 0; i < ib->count; i++) - *elts++ = (GLuint)(*in++); + *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } else { const GLubyte *in = (GLubyte *)ptr; for (i = 0; i < ib->count; i++) - *elts++ = (GLuint)(*in++); + *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } } } @@ -390,10 +395,14 @@ void _tnl_draw_prims( GLcontext *ctx, TNLcontext *tnl = TNL_CONTEXT(ctx); const GLuint TEST_SPLIT = 0; const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES; + GLuint max_basevertex = prim->basevertex; + GLuint i; + + for (i = 1; i < nr_prims; i++) + max_basevertex = MAX2(max_basevertex, prim[i].basevertex); 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, @@ -410,7 +419,7 @@ void _tnl_draw_prims( GLcontext *ctx, _tnl_vbo_draw_prims ); return; } - else if (max_index > max) { + else if (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. @@ -424,7 +433,7 @@ void _tnl_draw_prims( GLcontext *ctx, * recursively call back into this function. */ vbo_split_prims( ctx, arrays, prim, nr_prims, ib, - 0, max_index, + 0, max_index + prim->basevertex, _tnl_vbo_draw_prims, &limits ); } @@ -435,17 +444,34 @@ void _tnl_draw_prims( GLcontext *ctx, 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 ); + 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; + } + + /* Binding inputs may imply mapping some vertex buffer objects. + * They will need to be unmapped below. + */ + 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_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); + + i += this_nr_prims; + } } } diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h index 5986e93576..b24ecfd7cd 100644 --- a/src/mesa/vbo/vbo.h +++ b/src/mesa/vbo/vbo.h @@ -44,6 +44,7 @@ struct _mesa_prim { GLuint start; GLuint count; + GLint basevertex; }; /* Would like to call this a "vbo_index_buffer", but this would be diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index 12911f5750..b9550d6106 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -181,7 +181,7 @@ unmap_array_buffer(GLcontext *ctx, struct gl_client_array *array) */ static void check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType, - const void *elements) + const void *elements, GLint basevertex) { struct gl_array_object *arrayObj = ctx->Array.ArrayObj; const void *elemMap; @@ -518,6 +518,7 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) prim[0].start = start; prim[0].count = count; prim[0].indexed = 0; + prim[0].basevertex = 0; vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, GL_TRUE, start, start + count - 1 ); @@ -592,7 +593,8 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, GLboolean index_bounds_valid, GLuint start, GLuint end, GLsizei count, GLenum type, - const GLvoid *indices) + const GLvoid *indices, + GLint basevertex) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; @@ -626,6 +628,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, prim[0].start = 0; prim[0].count = count; prim[0].indexed = 1; + prim[0].basevertex = basevertex; /* Need to give special consideration to rendering a range of * indices starting somewhere above zero. Typically the @@ -663,23 +666,25 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, } static void GLAPIENTRY -vbo_exec_DrawRangeElements(GLenum mode, - GLuint start, GLuint end, - GLsizei count, GLenum type, const GLvoid *indices) +vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, + GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices, + GLint basevertex) { GET_CURRENT_CONTEXT(ctx); if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, - type, indices )) + type, indices, basevertex )) return; if (end >= ctx->Array.ArrayObj->_MaxElement) { /* the max element is out of bounds of one or more enabled arrays */ - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " - "type 0x%x, indices=%p)\n" + _mesa_warning(ctx, "glDraw[Range]Elements{,BaseVertex}(start %u, end %u, " + "count %d, type 0x%x, indices=%p, base=%d)\n" "\tindex=%u is out of bounds (max=%u) " "Element Buffer %u (size %d)", - start, end, count, type, indices, end, + start, end, count, type, indices, end, basevertex, ctx->Array.ArrayObj->_MaxElement - 1, ctx->Array.ElementArrayBufferObj->Name, ctx->Array.ElementArrayBufferObj->Size); @@ -692,10 +697,12 @@ vbo_exec_DrawRangeElements(GLenum mode, return; } else if (0) { - _mesa_printf("glDraw[Range]Elements" - "(start %u, end %u, type 0x%x, count %d) ElemBuf %u\n", + _mesa_printf("glDraw[Range]Elements{,BaseVertex}" + "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " + "base %d\n", start, end, type, count, - ctx->Array.ElementArrayBufferObj->Name); + ctx->Array.ElementArrayBufferObj->Name, + basevertex); } #if 0 @@ -705,7 +712,17 @@ vbo_exec_DrawRangeElements(GLenum mode, #endif vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, - count, type, indices); + count, type, indices, basevertex); +} + +static void GLAPIENTRY +vbo_exec_DrawRangeElements(GLenum mode, + GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices) +{ + vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, + indices, 0); } @@ -715,18 +732,33 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, { GET_CURRENT_CONTEXT(ctx); - if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) + return; + + vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, + count, type, indices, 0); +} + +static void GLAPIENTRY +vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex) +{ + GET_CURRENT_CONTEXT(ctx); + + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, + basevertex )) return; vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices); + count, type, indices, basevertex); } /* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */ static void vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, const GLsizei *count, GLenum type, - const GLvoid **indices, GLsizei primcount) + const GLvoid **indices, GLsizei primcount, + const GLint *basevertex) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; @@ -820,6 +852,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; prim[i].count = count[i]; prim[i].indexed = 1; + if (basevertex != NULL) + prim[i].basevertex = basevertex[i]; + else + prim[i].basevertex = 0; } vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, @@ -840,6 +876,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, prim[0].start = 0; prim[0].count = count[i]; prim[0].indexed = 1; + if (basevertex != NULL) + prim[0].basevertex = basevertex[i]; + else + prim[0].basevertex = 0; } vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, @@ -860,13 +900,36 @@ vbo_exec_MultiDrawElements(GLenum mode, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); for (i = 0; i < primcount; i++) { - if (!_mesa_validate_DrawElements( ctx, mode, count[i], type, indices[i] )) + if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], + 0)) return; } - vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount); + vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, + NULL); } +static void GLAPIENTRY +vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, + const GLsizei *count, GLenum type, + const GLvoid **indices, + GLsizei primcount, + const GLsizei *basevertex) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + for (i = 0; i < primcount; i++) { + if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], + basevertex[i])) + return; + } + + vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, + basevertex); +} /*********************************************************************** @@ -881,11 +944,17 @@ vbo_exec_array_init( struct vbo_exec_context *exec ) exec->vtxfmt.DrawElements = vbo_exec_DrawElements; exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; + exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; + exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; + exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; #else exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays; exec->vtxfmt.DrawElements = _mesa_noop_DrawElements; exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements; exec->vtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; + exec->vtxfmt.DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex; + exec->vtxfmt.DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex; + exec->vtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; #endif } @@ -913,6 +982,13 @@ _mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, vbo_exec_DrawElements(mode, count, type, indices); } +void GLAPIENTRY +_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex) +{ + vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex); +} + /* This API entrypoint is not ordinarily used */ void GLAPIENTRY @@ -922,6 +998,15 @@ _mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); } +void GLAPIENTRY +_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices, GLint basevertex) +{ + vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, + indices, basevertex); +} + /* GL_EXT_multi_draw_arrays */ void GLAPIENTRY _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, @@ -929,3 +1014,13 @@ _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, { vbo_exec_MultiDrawElements(mode, count, type, indices, primcount); } + +void GLAPIENTRY +_mesa_MultiDrawElementsBaseVertex(GLenum mode, + const GLsizei *count, GLenum type, + const GLvoid **indices, GLsizei primcount, + const GLint *basevertex) +{ + vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, + primcount, basevertex); +} diff --git a/src/mesa/vbo/vbo_rebase.c b/src/mesa/vbo/vbo_rebase.c index 3bf7ef580f..799a25fc1c 100644 --- a/src/mesa/vbo/vbo_rebase.c +++ b/src/mesa/vbo/vbo_rebase.c @@ -126,7 +126,20 @@ void vbo_rebase_prims( GLcontext *ctx, if (0) _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); - if (ib) { + + if (ib && ctx->Extensions.ARB_draw_elements_base_vertex) { + /* If we can just tell the hardware or the TNL to interpret our + * indices with a different base, do so. + */ + tmp_prims = (struct _mesa_prim *)_mesa_malloc(sizeof(*prim) * nr_prims); + + for (i = 0; i < nr_prims; i++) { + tmp_prims[i] = prim[i]; + tmp_prims[i].basevertex -= min_index; + } + + prim = tmp_prims; + } else if (ib) { /* Unfortunately need to adjust each index individually. */ GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer; diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c index 1771510d84..41cd21d04b 100644 --- a/src/mesa/vbo/vbo_save_api.c +++ b/src/mesa/vbo/vbo_save_api.c @@ -826,6 +826,33 @@ static void GLAPIENTRY _save_DrawRangeElements(GLenum mode, _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); } +static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLint basevertex) +{ + GET_CURRENT_CONTEXT(ctx); + (void) mode; (void) count; (void) type; (void) indices; (void)basevertex; + + _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); +} + +static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLint basevertex) +{ + GET_CURRENT_CONTEXT(ctx); + (void) mode; (void) start; (void) end; (void) count; (void) type; + (void) indices; (void)basevertex; + + _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); +} + static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count) { GET_CURRENT_CONTEXT(ctx); @@ -907,7 +934,7 @@ static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum GET_CURRENT_CONTEXT(ctx); GLint i; - if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) return; _ae_map_vbos( ctx ); @@ -948,7 +975,7 @@ static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode, GET_CURRENT_CONTEXT(ctx); if (_mesa_validate_DrawRangeElements( ctx, mode, start, end, - count, type, indices )) + count, type, indices, 0 )) _save_OBE_DrawElements( mode, count, type, indices ); } @@ -1039,9 +1066,11 @@ static void _save_vtxfmt_init( GLcontext *ctx ) vfmt->DrawArrays = _save_DrawArrays; vfmt->DrawElements = _save_DrawElements; vfmt->DrawRangeElements = _save_DrawRangeElements; + vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; + vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; /* Loops back into vfmt->DrawElements */ vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; - + vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; } @@ -1233,6 +1262,7 @@ void vbo_save_api_init( struct vbo_save_context *save ) ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; /* loops back into _save_OBE_DrawElements */ ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; + ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); } diff --git a/src/mesa/vbo/vbo_split.c b/src/mesa/vbo/vbo_split.c index 58e879628d..c445acca7d 100644 --- a/src/mesa/vbo/vbo_split.c +++ b/src/mesa/vbo/vbo_split.c @@ -50,6 +50,7 @@ #include "main/glheader.h" #include "main/imports.h" #include "main/mtypes.h" +#include "main/macros.h" #include "vbo_split.h" #include "vbo.h" @@ -107,7 +108,12 @@ void vbo_split_prims( GLcontext *ctx, vbo_draw_func draw, const struct split_limits *limits ) { - + GLuint max_basevertex = prim->basevertex; + GLuint i; + + for (i = 1; i < nr_prims; i++) + max_basevertex = MAX2(max_basevertex, prim[i].basevertex); + if (ib) { if (limits->max_indices == 0) { /* Could traverse the indices, re-emitting vertices in turn. diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c index 8ec180d550..c45190b9dd 100644 --- a/src/mesa/vbo/vbo_split_copy.c +++ b/src/mesa/vbo/vbo_split_copy.c @@ -589,28 +589,40 @@ void vbo_split_copy( GLcontext *ctx, const struct split_limits *limits ) { struct copy_context copy; - GLuint i; + GLuint i, this_nr_prims; + + for (i = 0; i < 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; + } - memset(©, 0, sizeof(copy)); + memset(©, 0, sizeof(copy)); - /* Require indexed primitives: - */ - assert(ib); - - copy.ctx = ctx; - copy.array = arrays; - copy.prim = prim; - copy.nr_prims = nr_prims; - copy.ib = ib; - copy.draw = draw; - copy.limits = limits; + /* Require indexed primitives: + */ + assert(ib); - /* Clear the vertex cache: - */ - for (i = 0; i < ELT_TABLE_SIZE; i++) - copy.vert_cache[i].in = ~0; + copy.ctx = ctx; + copy.array = arrays; + copy.prim = &prim[i]; + copy.nr_prims = this_nr_prims; + copy.ib = ib; + copy.draw = draw; + copy.limits = limits; - replay_init(©); - replay_elts(©); - replay_finish(©); + /* Clear the vertex cache: + */ + for (i = 0; i < ELT_TABLE_SIZE; i++) + copy.vert_cache[i].in = ~0; + + replay_init(©); + replay_elts(©); + replay_finish(©); + } } -- cgit v1.2.3