mesa: remove _mesa_index_buffer::index_size in favor of index_size_shift
[mesa.git] / src / mesa / main / draw.c
index 7fb57f67290c4fab38de56b3e70d2731792d181b..b39d200c0987bd6b85fb7767900b4ed5262fc19b 100644 (file)
@@ -104,20 +104,24 @@ 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);
+      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;
    }
 }
 
@@ -362,15 +366,14 @@ _mesa_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
       .begin = 1,
       .end = 1,
       .mode = mode,
-      .num_instances = numInstances,
-      .base_instance = baseInstance,
       .draw_id = drawID,
       .start = start,
       .count = count,
    };
 
    ctx->Driver.Draw(ctx, &prim, 1, NULL,
-                    GL_TRUE, start, start + count - 1, NULL, 0);
+                    GL_TRUE, start, start + count - 1,
+                    numInstances, baseInstance, NULL, 0);
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
       _mesa_flush(ctx);
@@ -609,6 +612,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.
  */
@@ -636,24 +661,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 (<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);
 }
 
 
@@ -763,9 +794,9 @@ _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;
@@ -773,8 +804,6 @@ _mesa_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
    prim.start = 0;
    prim.count = count;
    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
@@ -809,7 +838,8 @@ _mesa_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
     */
 
    ctx->Driver.Draw(ctx, &prim, 1, &ib,
-                    index_bounds_valid, start, end, NULL, 0);
+                    index_bounds_valid, start, end,
+                    numInstances, baseInstance, NULL, 0);
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
       _mesa_flush(ctx);
@@ -1160,8 +1190,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;
@@ -1169,18 +1197,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
@@ -1189,26 +1213,16 @@ _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) {
-         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.
@@ -1217,20 +1231,21 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
       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].num_instances = 1;
-         prim[i].base_instance = 0;
          prim[i].draw_id = i;
          if (basevertex != NULL)
             prim[i].basevertex = basevertex[i];
@@ -1239,37 +1254,35 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
       }
 
       ctx->Driver.Draw(ctx, prim, primcount, &ib,
-                       false, 0, ~0, NULL, 0);
+                       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].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);
+         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);
    }
@@ -1374,14 +1387,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);
+   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);
@@ -1502,9 +1514,9 @@ _mesa_validated_drawelementsindirect(struct gl_context *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,
@@ -1531,9 +1543,9 @@ _mesa_validated_multidrawelementsindirect(struct gl_context *ctx,
    /* 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,
@@ -1844,9 +1856,9 @@ _mesa_validated_multidrawelementsindirectcount(struct gl_context *ctx,
    /* 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,