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

Ian Romanick idr at freedesktop.org
Mon Jan 4 19:10:14 PST 2016


On 12/31/2015 11:55 AM, Ilia Mirkin wrote:
> 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>
> ---
>  src/mesa/vbo/vbo.h            |  15 ++++
>  src/mesa/vbo/vbo_context.c    |   7 ++
>  src/mesa/vbo/vbo_context.h    |   6 ++
>  src/mesa/vbo/vbo_exec_array.c | 166 +++++++++++++++++++++++++-----------------
>  4 files changed, 127 insertions(+), 67 deletions(-)
> 
> diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
> index cef3b8c..0c63bf3 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 draw_count,
> +   unsigned stride,
> +   struct gl_buffer_object *indirect_params,
> +   GLsizeiptr indirect_params_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.c b/src/mesa/vbo/vbo_context.c
> index 5e1a760..8a196e7 100644
> --- a/src/mesa/vbo/vbo_context.c
> +++ b/src/mesa/vbo/vbo_context.c
> @@ -223,3 +223,10 @@ void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func)
>     vbo->draw_prims = func;
>  }
>  
> +
> +void vbo_set_indirect_draw_func(struct gl_context *ctx,
> +                                vbo_indirect_draw_func func)
> +{
> +   struct vbo_context *vbo = vbo_context(ctx);
> +   vbo->draw_indirect_prims = func;
> +}
> 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) {

My expectation is that we'll want to transition quickly to whatever new
interface we decide upon.  Would it be possible to make the existing
loops over vbo->draw_prims be a separate function that is the default
implementation of vbo->draw_indirect_prims?  At the very least, that
would make the callers a bit cleaner.  We also wouldn't punish "proper"
implementations with the extra test, and the indirection ought to
provide more incentive to "improper" implementations to get on it. :)

I haven't looked very closely at the actual interface yet.  Most of my
day back at work was going through e-mail, and going to buy a new
keyboard with a "D" key that isn't all worn out. :)

> +      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);
> 



More information about the mesa-dev mailing list