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 <imir...@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); > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev