[Mesa-dev] [RFC PATCH] vbo: create a new draw function interface for indirect draws

Ilia Mirkin imirkin at alum.mit.edu
Wed Dec 30 15:10:56 PST 2015


This is optional for now in the transition period, but optimally all
backends that support indirect draws would switch over to it and we can
remove the support for indirect in the "regular" draw function.

This should allow a backend to properly support ARB_multi_draw_indirect
and ARB_indirect_parameters.

Signed-off-by: Ilia Mirkin <imirkin at alum.mit.edu>
---

Nothing implements this interface for now but I wanted some feedback from people
before going too far into this. In case it's not clear, the idea is that for
ARB_indirect_parameters, nr_prims would be the maxcount, while indirect_nr_prims
(+ offset) would point to the real number.

 src/mesa/vbo/vbo.h            |  15 ++++
 src/mesa/vbo/vbo_context.h    |   6 ++
 src/mesa/vbo/vbo_exec_array.c | 166 +++++++++++++++++++++++++-----------------
 3 files changed, 120 insertions(+), 67 deletions(-)

diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index cef3b8c..5fc5858 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -110,6 +110,18 @@ typedef void (*vbo_draw_func)( struct gl_context *ctx,
 			       struct gl_buffer_object *indirect);
 
 
+typedef void (*vbo_indirect_draw_func)(
+   struct gl_context *ctx,
+   GLuint mode,
+   struct gl_buffer_object *indirect_data,
+   GLsizeiptr indirect_offset,
+   unsigned nr_prims,
+   unsigned stride,
+   struct gl_buffer_object *indirect_nr_prims,
+   GLsizeiptr indirect_nr_offset,
+   const struct _mesa_index_buffer *ib);
+
+
 
 
 /* Utility function to cope with various constraints on tnl modules or
@@ -179,6 +191,9 @@ void vbo_always_unmap_buffers(struct gl_context *ctx);
 
 void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func);
 
+void vbo_set_indirect_draw_func(struct gl_context *ctx,
+                                vbo_indirect_draw_func func);
+
 void vbo_check_buffers_are_unmapped(struct gl_context *ctx);
 
 void vbo_bind_arrays(struct gl_context *ctx);
diff --git a/src/mesa/vbo/vbo_context.h b/src/mesa/vbo/vbo_context.h
index 6293a8b..11f9b17 100644
--- a/src/mesa/vbo/vbo_context.h
+++ b/src/mesa/vbo/vbo_context.h
@@ -76,6 +76,12 @@ struct vbo_context {
     * is responsible for initiating any fallback actions required:
     */
    vbo_draw_func draw_prims;
+
+   /* Optional callback for indirect draws. This allows multidraws to not be
+    * broken up, as well as for the actual count to be passed in as a separate
+    * indirect parameter.
+    */
+   vbo_indirect_draw_func draw_indirect_prims;
 };
 
 
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 502b288..3da2d19 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -1550,23 +1550,30 @@ vbo_validated_drawarraysindirect(struct gl_context *ctx,
 
    vbo_bind_arrays(ctx);
 
-   memset(prim, 0, sizeof(prim));
-   prim[0].begin = 1;
-   prim[0].end = 1;
-   prim[0].mode = mode;
-   prim[0].is_indirect = 1;
-   prim[0].indirect_offset = (GLsizeiptr)indirect;
-
-   /* NOTE: We do NOT want to handle primitive restart here, nor perform any
-    * other checks that require knowledge of the values in the command buffer.
-    * That would defeat the whole purpose of this function.
-    */
+   if (vbo->draw_indirect_prims) {
+      vbo->draw_indirect_prims(ctx, mode,
+                               ctx->DrawIndirectBuffer, (GLsizeiptr)indirect,
+                               1 /* primcount */, 0 /* stride */,
+                               NULL, 0, NULL);
+   } else {
+      memset(prim, 0, sizeof(prim));
+      prim[0].begin = 1;
+      prim[0].end = 1;
+      prim[0].mode = mode;
+      prim[0].is_indirect = 1;
+      prim[0].indirect_offset = (GLsizeiptr)indirect;
+
+      /* NOTE: We do NOT want to handle primitive restart here, nor perform
+       * any other checks that require knowledge of the values in the command
+       * buffer.  That would defeat the whole purpose of this function.
+       */
 
-   check_buffers_are_unmapped(exec->array.inputs);
-   vbo->draw_prims(ctx, prim, 1,
-                   NULL, GL_TRUE, 0, ~0,
-                   NULL, 0,
-                   ctx->DrawIndirectBuffer);
+      check_buffers_are_unmapped(exec->array.inputs);
+      vbo->draw_prims(ctx, prim, 1,
+                      NULL, GL_TRUE, 0, ~0,
+                      NULL, 0,
+                      ctx->DrawIndirectBuffer);
+   }
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
       _mesa_flush(ctx);
@@ -1586,30 +1593,38 @@ vbo_validated_multidrawarraysindirect(struct gl_context *ctx,
 
    if (primcount == 0)
       return;
-   prim = calloc(primcount, sizeof(*prim));
-   if (prim == NULL) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawArraysIndirect");
-      return;
-   }
 
    vbo_bind_arrays(ctx);
 
-   prim[0].begin = 1;
-   prim[primcount - 1].end = 1;
-   for (i = 0; i < primcount; ++i, offset += stride) {
-      prim[i].mode = mode;
-      prim[i].indirect_offset = offset;
-      prim[i].is_indirect = 1;
-      prim[i].draw_id = i;
-   }
+   if (vbo->draw_indirect_prims) {
+      vbo->draw_indirect_prims(ctx, mode,
+                               ctx->DrawIndirectBuffer, offset,
+                               primcount, stride,
+                               NULL, 0, NULL);
+   } else {
+      prim = calloc(primcount, sizeof(*prim));
+      if (prim == NULL) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawArraysIndirect");
+         return;
+      }
 
-   check_buffers_are_unmapped(exec->array.inputs);
-   vbo->draw_prims(ctx, prim, primcount,
-                   NULL, GL_TRUE, 0, ~0,
-                   NULL, 0,
-                   ctx->DrawIndirectBuffer);
+      prim[0].begin = 1;
+      prim[primcount - 1].end = 1;
+      for (i = 0; i < primcount; ++i, offset += stride) {
+         prim[i].mode = mode;
+         prim[i].indirect_offset = offset;
+         prim[i].is_indirect = 1;
+         prim[i].draw_id = i;
+      }
 
-   free(prim);
+      check_buffers_are_unmapped(exec->array.inputs);
+      vbo->draw_prims(ctx, prim, primcount,
+                      NULL, GL_TRUE, 0, ~0,
+                      NULL, 0,
+                      ctx->DrawIndirectBuffer);
+
+      free(prim);
+   }
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
       _mesa_flush(ctx);
@@ -1632,19 +1647,27 @@ vbo_validated_drawelementsindirect(struct gl_context *ctx,
    ib.obj = ctx->Array.VAO->IndexBufferObj;
    ib.ptr = NULL;
 
-   memset(prim, 0, sizeof(prim));
-   prim[0].begin = 1;
-   prim[0].end = 1;
-   prim[0].mode = mode;
-   prim[0].indexed = 1;
-   prim[0].indirect_offset = (GLsizeiptr)indirect;
-   prim[0].is_indirect = 1;
+   if (vbo->draw_indirect_prims) {
+      vbo->draw_indirect_prims(ctx, mode,
+                               ctx->DrawIndirectBuffer, (GLsizeiptr)indirect,
+                               1 /* primcount */, 0 /* stride */,
+                               NULL, 0,
+                               &ib);
+   } else {
+      memset(prim, 0, sizeof(prim));
+      prim[0].begin = 1;
+      prim[0].end = 1;
+      prim[0].mode = mode;
+      prim[0].indexed = 1;
+      prim[0].indirect_offset = (GLsizeiptr)indirect;
+      prim[0].is_indirect = 1;
 
-   check_buffers_are_unmapped(exec->array.inputs);
-   vbo->draw_prims(ctx, prim, 1,
-                   &ib, GL_TRUE, 0, ~0,
-                   NULL, 0,
-                   ctx->DrawIndirectBuffer);
+      check_buffers_are_unmapped(exec->array.inputs);
+      vbo->draw_prims(ctx, prim, 1,
+                      &ib, GL_TRUE, 0, ~0,
+                      NULL, 0,
+                      ctx->DrawIndirectBuffer);
+   }
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
       _mesa_flush(ctx);
@@ -1665,11 +1688,6 @@ vbo_validated_multidrawelementsindirect(struct gl_context *ctx,
 
    if (primcount == 0)
       return;
-   prim = calloc(primcount, sizeof(*prim));
-   if (prim == NULL) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElementsIndirect");
-      return;
-   }
 
    vbo_bind_arrays(ctx);
 
@@ -1680,23 +1698,37 @@ vbo_validated_multidrawelementsindirect(struct gl_context *ctx,
    ib.obj = ctx->Array.VAO->IndexBufferObj;
    ib.ptr = NULL;
 
-   prim[0].begin = 1;
-   prim[primcount - 1].end = 1;
-   for (i = 0; i < primcount; ++i, offset += stride) {
-      prim[i].mode = mode;
-      prim[i].indexed = 1;
-      prim[i].indirect_offset = offset;
-      prim[i].is_indirect = 1;
-      prim[i].draw_id = i;
-   }
+   if (vbo->draw_indirect_prims) {
+      vbo->draw_indirect_prims(ctx, mode,
+                               ctx->DrawIndirectBuffer, offset,
+                               primcount, stride,
+                               NULL, 0,
+                               &ib);
+   } else {
+      prim = calloc(primcount, sizeof(*prim));
+      if (prim == NULL) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElementsIndirect");
+         return;
+      }
 
-   check_buffers_are_unmapped(exec->array.inputs);
-   vbo->draw_prims(ctx, prim, primcount,
-                   &ib, GL_TRUE, 0, ~0,
-                   NULL, 0,
-                   ctx->DrawIndirectBuffer);
+      prim[0].begin = 1;
+      prim[primcount - 1].end = 1;
+      for (i = 0; i < primcount; ++i, offset += stride) {
+         prim[i].mode = mode;
+         prim[i].indexed = 1;
+         prim[i].indirect_offset = offset;
+         prim[i].is_indirect = 1;
+         prim[i].draw_id = i;
+      }
 
-   free(prim);
+      check_buffers_are_unmapped(exec->array.inputs);
+      vbo->draw_prims(ctx, prim, primcount,
+                      &ib, GL_TRUE, 0, ~0,
+                      NULL, 0,
+                      ctx->DrawIndirectBuffer);
+
+      free(prim);
+   }
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
       _mesa_flush(ctx);
-- 
2.4.10



More information about the mesa-dev mailing list