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 <chrisf@ijw.co.nz>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:
Chris Forbes 2013-11-06 20:03:21 +13:00
parent aadbb0f275
commit 5a798e73b5

View file

@ -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 <stride> 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 <stride> 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);
}
/**