X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fdraw.c;h=5bb254e00d2621191b064096518ecca22afca963;hb=e630271e0ec3eee7d921d76d3924873f6ee6b59b;hp=9f314dadebe2ec8ea8c5923dcf597116bba3ddc4;hpb=3c98dccd405cf57cbc5a8534e93d7ba020d0e055;p=mesa.git diff --git a/src/mesa/main/draw.c b/src/mesa/main/draw.c index 9f314dadebe..5bb254e00d2 100644 --- a/src/mesa/main/draw.c +++ b/src/mesa/main/draw.c @@ -90,7 +90,7 @@ check_array_data(struct gl_context *ctx, struct gl_vertex_array_object *vao, array->Format.Type, array->Format.Size, binding->Stride); printf(" Address/offset %p in Buffer Object %u\n", - array->Ptr, bo->Name); + array->Ptr, bo ? bo->Name : 0); f[k] = 1.0F; /* XXX replace the bad value! */ } /*assert(!IS_INF_OR_NAN(f[k])); */ @@ -104,21 +104,18 @@ check_array_data(struct gl_context *ctx, struct gl_vertex_array_object *vao, } -static inline int -sizeof_ib_type(GLenum type) +static inline void +get_index_size(GLenum type, struct _mesa_index_buffer *ib) { - switch (type) { - case GL_UNSIGNED_INT: - return sizeof(GLuint); - case GL_UNSIGNED_SHORT: - return sizeof(GLushort); - case GL_UNSIGNED_BYTE: - return sizeof(GLubyte); - default: - assert(!"unsupported index data type"); - /* In case assert is turned off */ - return 0; - } + /* The type is already validated, so use a fast conversion. + * + * GL_UNSIGNED_BYTE - GL_UNSIGNED_BYTE = 0 + * GL_UNSIGNED_SHORT - GL_UNSIGNED_BYTE = 2 + * GL_UNSIGNED_INT - GL_UNSIGNED_BYTE = 4 + * + * Divide by 2 to get 0,1,2. + */ + ib->index_size_shift = (type - GL_UNSIGNED_BYTE) >> 1; } /** @@ -258,7 +255,7 @@ print_draw_arrays(struct gl_context *ctx, "ptr %p Bufobj %u\n", gl_vert_attrib_name((gl_vert_attrib) i), array->Format.Size, binding->Stride, - array->Ptr, bufObj->Name); + array->Ptr, bufObj ? bufObj->Name : 0); if (_mesa_is_bufferobj(bufObj)) { GLubyte *p = bufObj->Mappings[MAP_INTERNAL].Pointer; @@ -352,26 +349,24 @@ _mesa_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, GLsizei count, GLuint numInstances, GLuint baseInstance, GLuint drawID) { - struct _mesa_prim prim; - if (skip_validated_draw(ctx)) return; /* OpenGL 4.5 says that primitive restart is ignored with non-indexed * draws. */ - memset(&prim, 0, sizeof(prim)); - prim.begin = 1; - prim.end = 1; - prim.mode = mode; - prim.num_instances = numInstances; - prim.base_instance = baseInstance; - prim.draw_id = drawID; - prim.start = start; - prim.count = count; + struct _mesa_prim prim = { + .begin = 1, + .end = 1, + .mode = mode, + .draw_id = drawID, + .start = start, + .count = count, + }; ctx->Driver.Draw(ctx, &prim, 1, NULL, - GL_TRUE, start, start + count - 1, NULL, 0, NULL); + GL_TRUE, start, start + count - 1, + numInstances, baseInstance, NULL, 0); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); @@ -610,6 +605,28 @@ _mesa_exec_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, } +#define MAX_ALLOCA_PRIMS (50000 / sizeof(*prim)) + +/* Use calloc for large allocations and alloca for small allocations. */ +/* We have to use a macro because alloca is local within the function. */ +#define ALLOC_PRIMS(prim, primcount, func) do { \ + if (unlikely(primcount > MAX_ALLOCA_PRIMS)) { \ + prim = calloc(primcount, sizeof(*prim)); \ + if (!prim) { \ + _mesa_error(ctx, GL_OUT_OF_MEMORY, func); \ + return; \ + } \ + } else { \ + prim = alloca(primcount * sizeof(*prim)); \ + } \ +} while (0) + +#define FREE_PRIMS(prim, primcount) do { \ + if (primcount > MAX_ALLOCA_PRIMS) \ + free(prim); \ +} while (0) + + /** * Called from glMultiDrawArrays when in immediate mode. */ @@ -637,24 +654,30 @@ _mesa_exec_MultiDrawArrays(GLenum mode, const GLint *first, return; } - for (i = 0; i < primcount; i++) { - if (count[i] > 0) { - if (0) - check_draw_arrays_data(ctx, first[i], count[i]); - - /* The GL_ARB_shader_draw_parameters spec adds the following after the - * pseudo-code describing glMultiDrawArrays: - * - * "The index of the draw ( in the above pseudo-code) may be - * read by a vertex shader as , as described in - * Section 11.1.3.9." - */ - _mesa_draw_arrays(ctx, mode, first[i], count[i], 1, 0, i); + if (skip_validated_draw(ctx)) + return; - if (0) - print_draw_arrays(ctx, mode, first[i], count[i]); - } + struct _mesa_prim *prim; + + ALLOC_PRIMS(prim, primcount, "glMultiDrawElements"); + + for (i = 0; i < primcount; i++) { + prim[i].begin = 1; + prim[i].end = 1; + prim[i].mode = mode; + prim[i].draw_id = i; + prim[i].start = first[i]; + prim[i].count = count[i]; + prim[i].basevertex = 0; } + + ctx->Driver.Draw(ctx, prim, primcount, NULL, GL_FALSE, 0, 0, 1, 0, + NULL, 0); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); + + FREE_PRIMS(prim, primcount); } @@ -764,19 +787,16 @@ _mesa_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, return; ib.count = count; - ib.index_size = sizeof_ib_type(type); ib.obj = ctx->Array.VAO->IndexBufferObj; ib.ptr = indices; + get_index_size(type, &ib); prim.begin = 1; prim.end = 1; prim.mode = mode; prim.start = 0; prim.count = count; - prim.indexed = 1; prim.basevertex = basevertex; - prim.num_instances = numInstances; - prim.base_instance = baseInstance; prim.draw_id = 0; /* Need to give special consideration to rendering a range of @@ -811,7 +831,8 @@ _mesa_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, */ ctx->Driver.Draw(ctx, &prim, 1, &ib, - index_bounds_valid, start, end, NULL, 0, NULL); + index_bounds_valid, start, end, + numInstances, baseInstance, NULL, 0); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); @@ -1162,8 +1183,6 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode, GLsizei primcount, const GLint *basevertex) { struct _mesa_index_buffer ib; - struct _mesa_prim *prim; - unsigned int index_type_size = sizeof_ib_type(type); uintptr_t min_index_ptr, max_index_ptr; GLboolean fallback = GL_FALSE; int i; @@ -1171,18 +1190,14 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode, if (primcount == 0) return; - prim = calloc(primcount, sizeof(*prim)); - if (prim == NULL) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); - return; - } + get_index_size(type, &ib); 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]); + (count[i] << ib.index_size_shift)); } /* Check if we can handle this thing as a bunch of index offsets from the @@ -1191,49 +1206,45 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode, * Check that the difference between each prim's indexes is a multiple of * the index/element size. */ - if (index_type_size != 1) { + if (ib.index_size_shift) { for (i = 0; i < primcount; i++) { - if ((((uintptr_t) indices[i] - min_index_ptr) % index_type_size) != - 0) { + if ((((uintptr_t) indices[i] - min_index_ptr) & + ((1 << ib.index_size_shift) - 1)) != 0) { fallback = GL_TRUE; break; } } } - /* Draw primitives individually if one count is zero, so we can easily skip - * that primitive. - */ - for (i = 0; i < primcount; i++) { - if (count[i] == 0) { + if (ctx->Const.MultiDrawWithUserIndices) { + /* Check whether prim[i].start would overflow. */ + if (((max_index_ptr - min_index_ptr) >> ib.index_size_shift) > UINT_MAX) + fallback = GL_TRUE; + } else { + /* 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.VAO->IndexBufferObj)) 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.VAO->IndexBufferObj)) - fallback = GL_TRUE; - if (!fallback) { - ib.count = (max_index_ptr - min_index_ptr) / index_type_size; - ib.index_size = sizeof_ib_type(type); + struct _mesa_prim *prim; + + ALLOC_PRIMS(prim, primcount, "glMultiDrawElements"); + + ib.count = (max_index_ptr - min_index_ptr) >> ib.index_size_shift; ib.obj = ctx->Array.VAO->IndexBufferObj; 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].begin = 1; + prim[i].end = 1; prim[i].mode = mode; prim[i].start = - ((uintptr_t) indices[i] - min_index_ptr) / index_type_size; + ((uintptr_t) indices[i] - min_index_ptr) >> ib.index_size_shift; prim[i].count = count[i]; - prim[i].indexed = 1; - prim[i].num_instances = 1; - prim[i].base_instance = 0; prim[i].draw_id = i; if (basevertex != NULL) prim[i].basevertex = basevertex[i]; @@ -1242,38 +1253,35 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode, } ctx->Driver.Draw(ctx, prim, primcount, &ib, - false, 0, ~0, NULL, 0, NULL); + false, 0, ~0, 1, 0, NULL, 0); + FREE_PRIMS(prim, primcount); } else { /* render one prim at a time */ for (i = 0; i < primcount; i++) { if (count[i] == 0) continue; + ib.count = count[i]; - ib.index_size = sizeof_ib_type(type); ib.obj = ctx->Array.VAO->IndexBufferObj; ib.ptr = indices[i]; - prim[0].begin = 1; - prim[0].end = 1; - prim[0].mode = mode; - prim[0].start = 0; - prim[0].count = count[i]; - prim[0].indexed = 1; - prim[0].num_instances = 1; - prim[0].base_instance = 0; - prim[0].draw_id = i; + struct _mesa_prim prim; + prim.begin = 1; + prim.end = 1; + prim.mode = mode; + prim.start = 0; + prim.count = count[i]; + prim.draw_id = i; if (basevertex != NULL) - prim[0].basevertex = basevertex[i]; + prim.basevertex = basevertex[i]; else - prim[0].basevertex = 0; + prim.basevertex = 0; - ctx->Driver.Draw(ctx, prim, 1, &ib, false, 0, ~0, NULL, 0, NULL); + ctx->Driver.Draw(ctx, &prim, 1, &ib, false, 0, ~0, 1, 0, NULL, 0); } } - free(prim); - if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); } @@ -1378,14 +1386,13 @@ _mesa_draw_transform_feedback(struct gl_context *ctx, GLenum mode, prim.begin = 1; prim.end = 1; prim.mode = mode; - prim.num_instances = numInstances; - prim.base_instance = 0; /* Maybe we should do some primitive splitting for primitive restart * (like in DrawArrays), but we have no way to know how many vertices * will be rendered. */ - ctx->Driver.Draw(ctx, &prim, 1, NULL, GL_FALSE, 0, ~0, obj, stream, NULL); + ctx->Driver.Draw(ctx, &prim, 1, NULL, GL_FALSE, 0, ~0, numInstances, 0, + obj, stream); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); @@ -1466,54 +1473,19 @@ _mesa_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, static void -_mesa_validated_drawarraysindirect(struct gl_context *ctx, - GLenum mode, const GLvoid *indirect) -{ - ctx->Driver.DrawIndirect(ctx, mode, - ctx->DrawIndirectBuffer, (GLsizeiptr) indirect, - 1 /* draw_count */ , 16 /* stride */ , - NULL, 0, NULL); - - if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) - _mesa_flush(ctx); -} - - -static void -_mesa_validated_multidrawarraysindirect(struct gl_context *ctx, - GLenum mode, - const GLvoid *indirect, - GLsizei primcount, GLsizei stride) +_mesa_validated_multidrawarraysindirect(struct gl_context *ctx, GLenum mode, + GLintptr indirect, + GLintptr drawcount_offset, + GLsizei drawcount, GLsizei stride, + struct gl_buffer_object *drawcount_buffer) { - GLsizeiptr offset = (GLsizeiptr) indirect; - - if (primcount == 0) + /* If drawcount_buffer is set, drawcount is the maximum draw count.*/ + if (drawcount == 0) return; - ctx->Driver.DrawIndirect(ctx, mode, ctx->DrawIndirectBuffer, offset, - primcount, stride, NULL, 0, NULL); - - if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) - _mesa_flush(ctx); -} - - -static void -_mesa_validated_drawelementsindirect(struct gl_context *ctx, - GLenum mode, GLenum type, - const GLvoid *indirect) -{ - struct _mesa_index_buffer ib; - - ib.count = 0; /* unknown */ - ib.index_size = sizeof_ib_type(type); - ib.obj = ctx->Array.VAO->IndexBufferObj; - ib.ptr = NULL; - - ctx->Driver.DrawIndirect(ctx, mode, - ctx->DrawIndirectBuffer, (GLsizeiptr) indirect, - 1 /* draw_count */ , 20 /* stride */ , - NULL, 0, &ib); + ctx->Driver.DrawIndirect(ctx, mode, ctx->DrawIndirectBuffer, indirect, + drawcount, stride, drawcount_buffer, + drawcount_offset, NULL); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) _mesa_flush(ctx); @@ -1523,25 +1495,25 @@ _mesa_validated_drawelementsindirect(struct gl_context *ctx, static void _mesa_validated_multidrawelementsindirect(struct gl_context *ctx, GLenum mode, GLenum type, - const GLvoid *indirect, - GLsizei primcount, GLsizei stride) + GLintptr indirect, + GLintptr drawcount_offset, + GLsizei drawcount, GLsizei stride, + struct gl_buffer_object *drawcount_buffer) { - struct _mesa_index_buffer ib; - GLsizeiptr offset = (GLsizeiptr) indirect; - - if (primcount == 0) + /* If drawcount_buffer is set, drawcount is the maximum draw count.*/ + if (drawcount == 0) return; /* NOTE: IndexBufferObj is guaranteed to be a VBO. */ - + struct _mesa_index_buffer ib; ib.count = 0; /* unknown */ - ib.index_size = sizeof_ib_type(type); ib.obj = ctx->Array.VAO->IndexBufferObj; ib.ptr = NULL; + get_index_size(type, &ib); - ctx->Driver.DrawIndirect(ctx, mode, - ctx->DrawIndirectBuffer, offset, - primcount, stride, NULL, 0, &ib); + ctx->Driver.DrawIndirect(ctx, mode, ctx->DrawIndirectBuffer, indirect, + drawcount, stride, drawcount_buffer, + drawcount_offset, &ib); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) _mesa_flush(ctx); @@ -1593,7 +1565,8 @@ _mesa_exec_DrawArraysIndirect(GLenum mode, const GLvoid *indirect) if (skip_validated_draw(ctx)) return; - _mesa_validated_drawarraysindirect(ctx, mode, indirect); + _mesa_validated_multidrawarraysindirect(ctx, mode, (GLintptr)indirect, + 0, 1, 16, NULL); } @@ -1659,7 +1632,9 @@ _mesa_exec_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect if (skip_validated_draw(ctx)) return; - _mesa_validated_drawelementsindirect(ctx, mode, type, indirect); + _mesa_validated_multidrawelementsindirect(ctx, mode, type, + (GLintptr)indirect, 0, + 1, 20, NULL); } @@ -1724,8 +1699,8 @@ _mesa_exec_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect, if (skip_validated_draw(ctx)) return; - _mesa_validated_multidrawarraysindirect(ctx, mode, indirect, - primcount, stride); + _mesa_validated_multidrawarraysindirect(ctx, mode, (GLintptr)indirect, 0, + primcount, stride, NULL); } @@ -1803,62 +1778,9 @@ _mesa_exec_MultiDrawElementsIndirect(GLenum mode, GLenum type, if (skip_validated_draw(ctx)) return; - _mesa_validated_multidrawelementsindirect(ctx, mode, type, indirect, - primcount, stride); -} - - -static void -_mesa_validated_multidrawarraysindirectcount(struct gl_context *ctx, - GLenum mode, - GLintptr indirect, - GLintptr drawcount_offset, - GLsizei maxdrawcount, - GLsizei stride) -{ - GLsizeiptr offset = indirect; - - if (maxdrawcount == 0) - return; - - ctx->Driver.DrawIndirect(ctx, mode, - ctx->DrawIndirectBuffer, offset, - maxdrawcount, stride, - ctx->ParameterBuffer, drawcount_offset, NULL); - - if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) - _mesa_flush(ctx); -} - - -static void -_mesa_validated_multidrawelementsindirectcount(struct gl_context *ctx, - GLenum mode, GLenum type, - GLintptr indirect, - GLintptr drawcount_offset, - GLsizei maxdrawcount, - GLsizei stride) -{ - struct _mesa_index_buffer ib; - GLsizeiptr offset = (GLsizeiptr) indirect; - - if (maxdrawcount == 0) - return; - - /* NOTE: IndexBufferObj is guaranteed to be a VBO. */ - - ib.count = 0; /* unknown */ - ib.index_size = sizeof_ib_type(type); - ib.obj = ctx->Array.VAO->IndexBufferObj; - ib.ptr = NULL; - - ctx->Driver.DrawIndirect(ctx, mode, - ctx->DrawIndirectBuffer, offset, - maxdrawcount, stride, - ctx->ParameterBuffer, drawcount_offset, &ib); - - if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) - _mesa_flush(ctx); + _mesa_validated_multidrawelementsindirect(ctx, mode, type, + (GLintptr)indirect, 0, primcount, + stride, NULL); } @@ -1898,9 +1820,9 @@ _mesa_exec_MultiDrawArraysIndirectCount(GLenum mode, GLintptr indirect, if (skip_validated_draw(ctx)) return; - _mesa_validated_multidrawarraysindirectcount(ctx, mode, indirect, - drawcount_offset, - maxdrawcount, stride); + _mesa_validated_multidrawarraysindirect(ctx, mode, indirect, + drawcount_offset, maxdrawcount, + stride, ctx->ParameterBuffer); } @@ -1941,9 +1863,9 @@ _mesa_exec_MultiDrawElementsIndirectCount(GLenum mode, GLenum type, if (skip_validated_draw(ctx)) return; - _mesa_validated_multidrawelementsindirectcount(ctx, mode, type, indirect, - drawcount_offset, maxdrawcount, - stride); + _mesa_validated_multidrawelementsindirect(ctx, mode, type, indirect, + drawcount_offset, maxdrawcount, + stride, ctx->ParameterBuffer); }