[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