+ if (primcount) /* &(last command) + sizeof(DrawElementsIndirectCommand) */
+ size = (primcount - 1) * stride + 5 * sizeof(GLuint);
+
+ FLUSH_CURRENT(ctx, 0);
+
+ if (!valid_draw_indirect_multi(ctx, primcount, stride,
+ "glMultiDrawElementsIndirect"))
+ return GL_FALSE;
+
+ if (!valid_draw_indirect_elements(ctx, mode, type,
+ indirect, size,
+ "glMultiDrawElementsIndirect"))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h
index f2b753c..8238df1 100644
--- a/src/mesa/main/api_validate.h
+++ b/src/mesa/main/api_validate.h
@@ -87,5 +87,31 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
GLuint stream,
GLsizei numInstances);
+extern GLboolean
+_mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
+ GLenum mode,
+ const GLvoid *indirect);
+
+extern GLboolean
+_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
+ GLenum mode,
+ GLenum type,
+ const GLvoid *indirect);
+
+extern GLboolean
+_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
+ GLenum mode,
+ const GLvoid *indirect,
+ GLsizei primcount,
+ GLsizei stride);
+
+extern GLboolean
+_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
+ GLenum mode,
+ GLenum type,
+ const GLvoid *indirect,
+ GLsizei primcount,
+ GLsizei stride);
+
#endif
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
index 1f55061..69ea1c0 100644
--- a/src/mesa/main/bufferobj.c
+++ b/src/mesa/main/bufferobj.c
@@ -86,6 +86,10 @@ get_buffer_target(struct gl_context *ctx, GLenum target)
return &ctx->CopyReadBuffer;
case GL_COPY_WRITE_BUFFER:
return &ctx->CopyWriteBuffer;
+ case GL_DRAW_INDIRECT_BUFFER:
+ if (ctx->Extensions.ARB_draw_indirect)
+ return &ctx->DrawIndirectBuffer;
+ break;
case GL_TRANSFORM_FEEDBACK_BUFFER:
if (ctx->Extensions.EXT_transform_feedback) {
return &ctx->TransformFeedback.CurrentBuffer;
@@ -626,6 +630,9 @@ _mesa_init_buffer_objects( struct gl_context *ctx )
_mesa_reference_buffer_object(ctx, &ctx->UniformBuffer,
ctx->Shared->NullBufferObj);
+ _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer,
+ ctx->Shared->NullBufferObj);
+
for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
_mesa_reference_buffer_object(ctx,
&ctx->UniformBufferBindings[i].BufferObject,
@@ -873,6 +880,11 @@ _mesa_DeleteBuffers(GLsizei n, const GLuint *ids)
_mesa_BindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
}
+ /* unbind ARB_draw_indirect binding point */
+ if (ctx->DrawIndirectBuffer == bufObj) {
+ _mesa_BindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 );
+ }
+
/* unbind ARB_copy_buffer binding points */
if (ctx->CopyReadBuffer == bufObj) {
_mesa_BindBuffer( GL_COPY_READ_BUFFER, 0 );
diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c
index 5956419..c953ffb 100644
--- a/src/mesa/main/dlist.c
+++ b/src/mesa/main/dlist.c
@@ -1356,6 +1356,42 @@ save_DrawElementsInstancedBaseVertexBaseInstance(GLenum
mode,
"glDrawElementsInstancedBaseVertexBaseInstance() during display list
compile");
}
+/* GL_ARB_draw_indirect. */
+static void GLAPIENTRY
+save_DrawArraysIndirect(GLenum mode, const GLvoid *indirect)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glDrawArraysIndirect() during display list compile");
+}
+
+static void GLAPIENTRY
+save_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glDrawElementsIndirect() during display list compile");
+}
+
+/* GL_ARB_multi_draw_indirect. */
+static void GLAPIENTRY
+save_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect,
+ GLsizei primcount, GLsizei stride)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMultiDrawArraysIndirect() during display list compile");
+}
+
+static void GLAPIENTRY
+save_MultiDrawElementsIndirect(GLenum mode, GLenum type,
+ const GLvoid *indirect,
+ GLsizei primcount, GLsizei stride)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMultiDrawElementsIndirect() during display list compile");
+}
/**
* While building a display list we cache some OpenGL state.
@@ -1363,7 +1399,7 @@ save_DrawElementsInstancedBaseVertexBaseInstance(GLenum
mode,
* when we start compiling a list, or after glCallList(s)).
*/
static void
-invalidate_saved_current_state(struct gl_context *ctx)
+invalidate_saved_current_state( struct gl_context *ctx )
{
GLint i;
@@ -9283,6 +9319,14 @@ _mesa_initialize_save_table(const struct gl_context *ctx)
SET_DrawArraysInstancedBaseInstance(table,
save_DrawArraysInstancedBaseInstance);
SET_DrawElementsInstancedBaseInstance(table,
save_DrawElementsInstancedBaseInstance);
SET_DrawElementsInstancedBaseVertexBaseInstance(table,
save_DrawElementsInstancedBaseVertexBaseInstance);
+
+ /* GL_ARB_draw_indirect */
+ SET_DrawArraysIndirect(table, save_DrawArraysIndirect);
+ SET_DrawElementsIndirect(table, save_DrawElementsIndirect);
+
+ /* GL_ARB_multi_draw_indirect */
+ SET_MultiDrawArraysIndirect(table, save_MultiDrawArraysIndirect);
+ SET_MultiDrawElementsIndirect(table, save_MultiDrawElementsIndirect);
}
diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c
index 48c4e9f..f0aae00 100644
--- a/src/mesa/main/extensions.c
+++ b/src/mesa/main/extensions.c
@@ -92,6 +92,7 @@ static const struct extension extension_table[] = {
{ "GL_ARB_draw_buffers", o(dummy_true),
GL, 2002 },
{ "GL_ARB_draw_buffers_blend", o(ARB_draw_buffers_blend),
GL, 2009 },
{ "GL_ARB_draw_elements_base_vertex",
o(ARB_draw_elements_base_vertex), GL, 2009 },
+ { "GL_ARB_draw_indirect", o(ARB_draw_indirect),
GLC, 2010 },
{ "GL_ARB_draw_instanced", o(ARB_draw_instanced),
GL, 2008 },
{ "GL_ARB_explicit_attrib_location",
o(ARB_explicit_attrib_location), GL, 2009 },
{ "GL_ARB_fragment_coord_conventions",
o(ARB_fragment_coord_conventions), GL, 2009 },
@@ -109,6 +110,7 @@ static const struct extension extension_table[] = {
{ "GL_ARB_invalidate_subdata", o(dummy_true),
GL, 2012 },
{ "GL_ARB_map_buffer_alignment",
o(ARB_map_buffer_alignment), GL, 2011 },
{ "GL_ARB_map_buffer_range", o(ARB_map_buffer_range),
GL, 2008 },
+ { "GL_ARB_multi_draw_indirect", o(ARB_draw_indirect),
GLC, 2012 },
{ "GL_ARB_multisample", o(dummy_true),
GLL, 1994 },
{ "GL_ARB_multitexture", o(dummy_true),
GLL, 1998 },
{ "GL_ARB_occlusion_query2", o(ARB_occlusion_query2),
GL, 2003 },
diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
index 6a0de0c..a471383 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -375,6 +375,7 @@ EXTRA_EXT(ARB_texture_buffer_range);
EXTRA_EXT(ARB_texture_multisample);
EXTRA_EXT(ARB_texture_gather);
EXTRA_EXT(ARB_shader_atomic_counters);
+EXTRA_EXT(ARB_draw_indirect);
static const int
extra_ARB_color_buffer_float_or_glcore[] = {
@@ -913,6 +914,10 @@ find_custom_value(struct gl_context *ctx, const struct
value_desc *d, union valu
case GL_ATOMIC_COUNTER_BUFFER_BINDING:
v->value_int = ctx->AtomicBuffer->Name;
break;
+ /* GL_ARB_draw_indirect */
+ case GL_DRAW_INDIRECT_BUFFER_BINDING:
+ v->value_int = ctx->DrawIndirectBuffer->Name;
+ break;
}
}
diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py
index 0851b7b..226ede0 100644
--- a/src/mesa/main/get_hash_params.py
+++ b/src/mesa/main/get_hash_params.py
@@ -743,6 +743,8 @@ descriptor=[
{ "apis": ["GL_CORE"], "params": [
# GL_ARB_texture_buffer_range
[ "TEXTURE_BUFFER_OFFSET_ALIGNMENT",
"CONTEXT_INT(Const.TextureBufferOffsetAlignment), extra_ARB_texture_buffer_range" ],
+# GL_ARB_draw_indirect
+ [ "DRAW_INDIRECT_BUFFER_BINDING", "LOC_CUSTOM, TYPE_INT, 0,
extra_ARB_draw_indirect" ],
]}
]
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index b5c5583..4f4fc52 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -3237,6 +3237,7 @@ struct gl_extensions
GLboolean ARB_depth_texture;
GLboolean ARB_draw_buffers_blend;
GLboolean ARB_draw_elements_base_vertex;
+ GLboolean ARB_draw_indirect;
GLboolean ARB_draw_instanced;
GLboolean ARB_fragment_coord_conventions;
GLboolean ARB_fragment_program;
@@ -3812,6 +3813,8 @@ struct gl_context
struct gl_perf_monitor_state PerfMonitor;
+ struct gl_buffer_object *DrawIndirectBuffer; /** < GL_ARB_draw_indirect */
+
struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */
struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */
diff --git a/src/mesa/main/tests/dispatch_sanity.cpp
b/src/mesa/main/tests/dispatch_sanity.cpp
index 58cff9b..e7fbcc5 100644
--- a/src/mesa/main/tests/dispatch_sanity.cpp
+++ b/src/mesa/main/tests/dispatch_sanity.cpp
@@ -667,8 +667,8 @@ const struct function gl_core_functions_possible[] = {
{ "glVertexAttribP3uiv", 43, -1 },
{ "glVertexAttribP4ui", 43, -1 },
{ "glVertexAttribP4uiv", 43, -1 },
-// { "glDrawArraysIndirect", 43, -1 }, // XXX: Add to xml
-// { "glDrawElementsIndirect", 43, -1 }, // XXX: Add to xml
+ { "glDrawArraysIndirect", 43, -1 },
+ { "glDrawElementsIndirect", 43, -1 },
// { "glUniform1d", 43, -1 }, // XXX: Add to xml
// { "glUniform2d", 43, -1 }, // XXX: Add to xml
// { "glUniform3d", 43, -1 }, // XXX: Add to xml
@@ -877,8 +877,8 @@ const struct function gl_core_functions_possible[] = {
{ "glInvalidateBufferData", 43, -1 },
{ "glInvalidateFramebuffer", 43, -1 },
{ "glInvalidateSubFramebuffer", 43, -1 },
-// { "glMultiDrawArraysIndirect", 43, -1 }, // XXX: Add to xml
-// { "glMultiDrawElementsIndirect", 43, -1 }, // XXX: Add to xml
+ { "glMultiDrawArraysIndirect", 43, -1 },
+ { "glMultiDrawElementsIndirect", 43, -1 },
// { "glGetProgramInterfaceiv", 43, -1 }, // XXX: Add to xml
// { "glGetProgramResourceIndex", 43, -1 }, // XXX: Add to xml
// { "glGetProgramResourceName", 43, -1 }, // XXX: Add to xml
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 5e1f80c..7aa0ad2 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -1564,6 +1564,250 @@ 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].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 deafeat 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(1, primcount * sizeof(*prim));
+ if (prim == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawArraysIndirect");
+ return;
+ }
+
+ vbo_bind_arrays(ctx);
+
+ memset(prim, 0, primcount * sizeof(*prim));
+ 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;
+ }
+
+ 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;
+
+ 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(1, 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;
+
+ memset(prim, 0, primcount * sizeof(*prim));
+ 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;
+ }
+
+ 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.
+ */
+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
+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
+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);
+}
/**
* Initialize the dispatch table with the VBO functions for drawing.
@@ -1595,6 +1839,10 @@ vbo_initialize_exec_dispatch(const struct gl_context
*ctx,
SET_DrawElementsInstancedBaseInstance(exec,
vbo_exec_DrawElementsInstancedBaseInstance);
SET_DrawElementsInstancedBaseVertex(exec,
vbo_exec_DrawElementsInstancedBaseVertex);
SET_DrawElementsInstancedBaseVertexBaseInstance(exec,
vbo_exec_DrawElementsInstancedBaseVertexBaseInstance);
+ SET_DrawArraysIndirect(exec, vbo_exec_DrawArraysIndirect);
+ SET_DrawElementsIndirect(exec, vbo_exec_DrawElementsIndirect);
+ SET_MultiDrawArraysIndirect(exec, vbo_exec_MultiDrawArraysIndirect);
+ SET_MultiDrawElementsIndirect(exec, vbo_exec_MultiDrawElementsIndirect);
}
if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {