From 5a798e73b5b4cab23dec945d4cbfa19951c084ba Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 6 Nov 2013 20:03:21 +1300 Subject: [PATCH] vbo: Flesh out implementation of indirect draws Based on part of Patch 2 of Christoph Bumiller's ARB_draw_indirect series. Signed-off-by: Chris Forbes Reviewed-by: Kenneth Graunke Reviewed-by: Eric Anholt Reviewed-by: Ian Romanick --- src/mesa/vbo/vbo_exec_array.c | 218 ++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index e85a0aa7512..db7da6922ea 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -1569,6 +1569,166 @@ vbo_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, vbo_draw_transform_feedback(ctx, mode, obj, stream, primcount); } +static void +vbo_validated_drawarraysindirect(struct gl_context *ctx, + GLenum mode, const GLvoid *indirect) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim prim[1]; + + 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. + */ + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, + NULL, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawarraysindirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim *prim; + GLsizei i; + GLsizeiptr offset = (GLsizeiptr)indirect; + + 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; + } + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, primcount, + NULL, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_drawelementsindirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim prim[1]; + + vbo_bind_arrays(ctx); + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; + 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; + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, + &ib, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawelementsindirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim *prim; + GLsizei i; + GLsizeiptr offset = (GLsizeiptr)indirect; + + 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); + + /* NOTE: ElementArrayBufferObj is guaranteed to be a VBO. */ + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; + 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; + } + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, primcount, + &ib, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + /** * Like [Multi]DrawArrays/Elements, but they take most arguments from * a buffer object. @@ -1576,12 +1736,33 @@ vbo_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, static void GLAPIENTRY vbo_exec_DrawArraysIndirect(GLenum mode, const GLvoid *indirect) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawArraysIndirect(%s, %p)\n", + _mesa_lookup_enum_by_nr(mode), indirect); + + if (!_mesa_validate_DrawArraysIndirect(ctx, mode, indirect)) + return; + + vbo_validated_drawarraysindirect(ctx, mode, indirect); } static void GLAPIENTRY vbo_exec_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawElementsIndirect(%s, %s, %p)\n", + _mesa_lookup_enum_by_nr(mode), + _mesa_lookup_enum_by_nr(type), indirect); + + if (!_mesa_validate_DrawElementsIndirect(ctx, mode, type, indirect)) + return; + + vbo_validated_drawelementsindirect(ctx, mode, type, indirect); } static void GLAPIENTRY @@ -1589,6 +1770,24 @@ vbo_exec_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawArraysIndirect(%s, %p, %i, %i)\n", + _mesa_lookup_enum_by_nr(mode), indirect, primcount, stride); + + /* If is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 4 * sizeof(GLuint); /* sizeof(DrawArraysIndirectCommand) */ + + if (!_mesa_validate_MultiDrawArraysIndirect(ctx, mode, + indirect, + primcount, stride)) + return; + + vbo_validated_multidrawarraysindirect(ctx, mode, + indirect, + primcount, stride); } static void GLAPIENTRY @@ -1596,6 +1795,25 @@ vbo_exec_MultiDrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawElementsIndirect(%s, %s, %p, %i, %i)\n", + _mesa_lookup_enum_by_nr(mode), + _mesa_lookup_enum_by_nr(type), indirect, primcount, stride); + + /* If is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 5 * sizeof(GLuint); /* sizeof(DrawElementsIndirectCommand) */ + + if (!_mesa_validate_MultiDrawElementsIndirect(ctx, mode, type, + indirect, + primcount, stride)) + return; + + vbo_validated_multidrawelementsindirect(ctx, mode, type, + indirect, + primcount, stride); } /** -- 2.30.2