}
-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);
+ ib->index_size_shift = 2;
+ break;
case GL_UNSIGNED_SHORT:
- return sizeof(GLushort);
+ ib->index_size_shift = 1;
+ break;
case GL_UNSIGNED_BYTE:
- return sizeof(GLubyte);
+ ib->index_size_shift = 0;
+ break;
default:
assert(!"unsupported index data type");
/* In case assert is turned off */
- return 0;
+ ib->index_size_shift = 0;
+ break;
}
}
}
+#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.
*/
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 (<i> in the above pseudo-code) may be
- * read by a vertex shader as <gl_DrawIDARB>, 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);
}
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;
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;
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
* 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) {
- 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.
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].draw_id = i;
if (basevertex != NULL)
ctx->Driver.Draw(ctx, prim, primcount, &ib,
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].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, 1, 0, NULL, 0);
+ 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);
}
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, (GLsizeiptr) indirect,
/* 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;
+ get_index_size(type, &ib);
ctx->Driver.DrawIndirect(ctx, mode,
ctx->DrawIndirectBuffer, offset,
/* 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;
+ get_index_size(type, &ib);
ctx->Driver.DrawIndirect(ctx, mode,
ctx->DrawIndirectBuffer, offset,