diff options
Diffstat (limited to 'src/mesa/vbo/vbo_exec_array.c')
-rw-r--r-- | src/mesa/vbo/vbo_exec_array.c | 282 |
1 files changed, 267 insertions, 15 deletions
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index 4148469ef4..b9550d6106 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -33,6 +33,7 @@ #include "main/api_noop.h" #include "main/varray.h" #include "main/bufferobj.h" +#include "main/macros.h" #include "glapi/dispatch.h" #include "vbo_context.h" @@ -180,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; @@ -517,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 ); @@ -591,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; @@ -625,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 @@ -662,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); @@ -691,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 @@ -704,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); } @@ -714,11 +732,203 @@ 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 GLint *basevertex) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim *prim; + unsigned int index_type_size = 0; + uintptr_t min_index_ptr, max_index_ptr; + GLboolean fallback = GL_FALSE; + int i; + + if (primcount == 0) + return; + + FLUSH_CURRENT( ctx, 0 ); + + if (ctx->NewState) + _mesa_update_state( ctx ); + + if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) { + return; + } + + if (ctx->NewState) + _mesa_update_state( ctx ); + + prim = _mesa_calloc(primcount * sizeof(*prim)); + if (prim == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); + return; + } + + /* Decide if we can do this all as one set of primitives sharing the + * same index buffer, or if we have to reset the index pointer per primitive. + */ + bind_arrays( ctx ); + + switch (type) { + case GL_UNSIGNED_INT: + index_type_size = 4; + break; + case GL_UNSIGNED_SHORT: + index_type_size = 2; + break; + case GL_UNSIGNED_BYTE: + index_type_size = 1; + break; + default: + assert(0); + } + + min_index_ptr = (uintptr_t)indices[0]; + max_index_ptr = 0; + for (i = 0; i < primcount; i++) { + min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]); + max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] + + index_type_size * count[i]); + } + + /* Check if we can handle this thing as a bunch of index offsets from the + * same index pointer. If we can't, then we have to fall back to doing + * a draw_prims per primitive. + */ + if (index_type_size != 1) { + for (i = 0; i < primcount; i++) { + if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) { + fallback = GL_TRUE; + break; + } + } + } + + /* If the index buffer isn't in a VBO, then treating the application's + * subranges of the index buffer as one large index buffer may lead to + * us reading unmapped memory. + */ + if (!_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) + fallback = GL_TRUE; + + if (!fallback) { + ib.count = (max_index_ptr - min_index_ptr) / index_type_size; + ib.type = type; + ib.obj = ctx->Array.ElementArrayBufferObj; + ib.ptr = (void *)min_index_ptr; + + for (i = 0; i < primcount; i++) { + prim[i].begin = (i == 0); + prim[i].end = (i == primcount - 1); + prim[i].weak = 0; + prim[i].pad = 0; + prim[i].mode = 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, + GL_FALSE, ~0, ~0); + } else { + for (i = 0; i < primcount; i++) { + ib.count = count[i]; + ib.type = type; + ib.obj = ctx->Array.ElementArrayBufferObj; + ib.ptr = indices[i]; + + + prim[0].begin = 1; + prim[0].end = 1; + prim[0].weak = 0; + prim[0].pad = 0; + prim[0].mode = 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, + GL_FALSE, ~0, ~0); + } + _mesa_free(prim); +} + +static void GLAPIENTRY +vbo_exec_MultiDrawElements(GLenum mode, + const GLsizei *count, GLenum type, + const GLvoid **indices, + GLsizei primcount) +{ + 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], + 0)) + return; + } + + 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); } @@ -733,10 +943,18 @@ vbo_exec_array_init( struct vbo_exec_context *exec ) exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; 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 } @@ -764,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 @@ -772,3 +997,30 @@ _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, + const GLvoid **indices, GLsizei primcount) +{ + 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); +} |