[Mesa-dev] [PATCH 02/11] mesa: implement GL_ARB_draw_indirect and GL_ARB_multi_draw_indirect

Brian Paul brianp at vmware.com
Mon Nov 4 06:57:12 PST 2013


On 11/04/2013 02:09 AM, Chris Forbes wrote:
> From: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
>
> v2:
> Removed some stray extern qualifiers.
>
> Documented use of Draw*IndirectCommand sizes.
>
> Removed separate extension enable flag for ARB_multi_draw_indirect
> since this can always be supported by looping.
>
> Kept generation of GL_INVALID_OPERATION in display list compile.
> The spec doesn't say anything about them, but all the direct drawing
> commands that support instancing do the same.
>
> v3:
> Initialize DrawIndirectBuffer with NullBufferObj.
>
> Only hook up the Draw functions in vtxfmt.c if API_OPENGL_CORE
> instead of _mesa_is_desktop_gl.
>
> Fix index bounds.
>
> v4: [Chris Forbes] Rebase to master -- significant conflicts due to
> vtxfmt vtable no longer containing draw functions.
>
> Conflicts:
> 	src/mesa/main/bufferobj.c
> 	src/mesa/main/dd.h
> 	src/mesa/main/dlist.c
> 	src/mesa/vbo/vbo_exec_array.c
> 	src/mesa/vbo/vbo_save_api.c
> ---
>   src/mapi/glapi/gen/ARB_draw_indirect.xml |  45 ++++++
>   src/mapi/glapi/gen/Makefile.am           |   1 +
>   src/mapi/glapi/gen/gl_API.xml            |   4 +-
>   src/mesa/main/api_validate.c             | 153 +++++++++++++++++++
>   src/mesa/main/api_validate.h             |  26 ++++
>   src/mesa/main/bufferobj.c                |  12 ++
>   src/mesa/main/dlist.c                    |  46 +++++-
>   src/mesa/main/extensions.c               |   2 +
>   src/mesa/main/get.c                      |   5 +
>   src/mesa/main/get_hash_params.py         |   2 +
>   src/mesa/main/mtypes.h                   |   3 +
>   src/mesa/main/tests/dispatch_sanity.cpp  |   8 +-
>   src/mesa/vbo/vbo_exec_array.c            | 248 +++++++++++++++++++++++++++++++
>   13 files changed, 549 insertions(+), 6 deletions(-)
>   create mode 100644 src/mapi/glapi/gen/ARB_draw_indirect.xml

I think some people would like to see this patch split up into smaller 
pieces that update the dispatch code, then add the core Mesa code, etc.
But you've already gone through several revs already.  It's not a huge 
deal to me.


>
> diff --git a/src/mapi/glapi/gen/ARB_draw_indirect.xml b/src/mapi/glapi/gen/ARB_draw_indirect.xml
> new file mode 100644
> index 0000000..7de03cd
> --- /dev/null
> +++ b/src/mapi/glapi/gen/ARB_draw_indirect.xml
> @@ -0,0 +1,45 @@
> +<?xml version="1.0"?>
> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
> +
> +<OpenGLAPI>
> +
> +<category name="GL_ARB_draw_indirect" number="87">
> +
> +    <enum name="DRAW_INDIRECT_BUFFER"                   value="0x8F3F"/>
> +    <enum name="DRAW_INDIRECT_BUFFER_BINDING"           value="0x8F43"/>
> +
> +    <function name="DrawArraysIndirect" offset="assign" exec="dynamic">
> +        <param name="mode" type="GLenum"/>
> +        <param name="indirect" type="const GLvoid *"/>

The use of GLvoid has been removed in glext.h and I'd be OK with doing 
the same in the dispatch code.


> +    </function>
> +
> +    <function name="DrawElementsIndirect" offset="assign" exec="dynamic">
> +        <param name="mode" type="GLenum"/>
> +        <param name="type" type="GLenum"/>
> +        <param name="indirect" type="const GLvoid *"/>
> +    </function>
> +
> +</category>
> +
> +
> +<category name="GL_ARB_multi_draw_indirect" number="133">
> +
> +    <function name="MultiDrawArraysIndirect" offset="assign" exec="dynamic">
> +        <param name="mode" type="GLenum"/>
> +        <param name="indirect" type="const GLvoid *"/>
> +        <param name="primcount" type="GLsizei"/>
> +        <param name="stride" type="GLsizei"/>
> +    </function>
> +
> +    <function name="MultiDrawElementsIndirect" offset="assign" exec="dynamic">
> +        <param name="mode" type="GLenum"/>
> +        <param name="type" type="GLenum"/>
> +        <param name="indirect" type="const GLvoid *"/>
> +        <param name="primcount" type="GLsizei"/>
> +        <param name="stride" type="GLsizei"/>
> +    </function>
> +
> +</category>
> +
> +
> +</OpenGLAPI>
> diff --git a/src/mapi/glapi/gen/Makefile.am b/src/mapi/glapi/gen/Makefile.am
> index cbbf659..0c67513 100644
> --- a/src/mapi/glapi/gen/Makefile.am
> +++ b/src/mapi/glapi/gen/Makefile.am
> @@ -98,6 +98,7 @@ API_XML = \
>   	ARB_draw_buffers.xml \
>   	ARB_draw_buffers_blend.xml \
>   	ARB_draw_elements_base_vertex.xml \
> +	ARB_draw_indirect.xml \
>   	ARB_draw_instanced.xml \
>   	ARB_ES2_compatibility.xml \
>   	ARB_ES3_compatibility.xml \
> diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml
> index 69014c5..7cab5ba 100644
> --- a/src/mapi/glapi/gen/gl_API.xml
> +++ b/src/mapi/glapi/gen/gl_API.xml
> @@ -8241,6 +8241,8 @@
>
>   <!-- ARB extensions #86...#93 -->
>
> +<xi:include href="ARB_draw_indirect.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
> +
>   <category name="GL_ARB_transform_feedback3" number="94">
>     <enum name="MAX_TRANSFORM_FEEDBACK_BUFFERS" value="0x8E70"/>
>     <enum name="MAX_VERTEX_STREAMS"             value="0x8E71"/>
> @@ -8466,7 +8468,7 @@
>
>   <xi:include href="ARB_invalidate_subdata.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
>
> -<!-- ARB extensions #133...#138 -->
> +<!-- ARB extensions #134...#138 -->
>
>   <xi:include href="ARB_texture_buffer_range.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
>
> diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c
> index f285c97..f3128cb 100644
> --- a/src/mesa/main/api_validate.c
> +++ b/src/mesa/main/api_validate.c
> @@ -837,3 +837,156 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
>
>      return GL_TRUE;
>   }
> +

Maybe put a comment on this describing what 'size' is.

> +static GLboolean
> +valid_draw_indirect(struct gl_context *ctx,
> +                    GLenum mode, const GLvoid *indirect,
> +                    GLsizei size, const char *name)
> +{
> +   const GLsizeiptr end = (GLsizeiptr)indirect + size;
> +
> +   if (!_mesa_valid_prim_mode(ctx, mode, name))
> +      return GL_FALSE;
> +
> +   if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "%s(indirect is not aligned)", name);
> +      return GL_FALSE;
> +   }
> +
> +   if (_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
> +      if (_mesa_bufferobj_mapped(ctx->DrawIndirectBuffer)) {
> +         _mesa_error(ctx, GL_INVALID_OPERATION,
> +                     "%s(DRAW_INDIRECT_BUFFER is mapped)", name);
> +         return GL_FALSE;
> +      }
> +      if (ctx->DrawIndirectBuffer->Size < end) {
> +         _mesa_error(ctx, GL_INVALID_OPERATION,
> +                     "%s(DRAW_INDIRECT_BUFFER too small)", name);
> +         return GL_FALSE;
> +      }
> +   } else {
> +      if (ctx->API != API_OPENGL_COMPAT) {
> +         _mesa_error(ctx, GL_INVALID_OPERATION,
> +                     "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);
> +         return GL_FALSE;
> +      }
> +   }
> +
> +   if (!check_valid_to_render(ctx, name))
> +      return GL_FALSE;
> +
> +   return GL_TRUE;
> +}
> +
> +static inline GLboolean
> +valid_draw_indirect_elements(struct gl_context *ctx,
> +                             GLenum mode, GLenum type, const GLvoid *indirect,
> +                             GLsizeiptr size, const char *name)
> +{
> +   if (!valid_elements_type(ctx, type, name))
> +      return GL_FALSE;
> +
> +   /*
> +    * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
> +    * may not come from a client array and must come from an index buffer.
> +    * If no element array buffer is bound, an INVALID_OPERATION error is
> +    * generated.
> +    */
> +   if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name);
> +      return GL_FALSE;
> +   }
> +
> +   return valid_draw_indirect(ctx, mode, indirect, size, name);
> +}
> +
> +static inline GLboolean
> +valid_draw_indirect_multi(struct gl_context *ctx,
> +                          GLsizei primcount, GLsizei stride,
> +                          const char *name)
> +{
> +   if (primcount < 0) {
> +      _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);
> +      return GL_FALSE;
> +   }
> +
> +   if (stride % 4) {
> +      _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name);
> +      return GL_FALSE;
> +   }
> +
> +   return GL_TRUE;
> +}
> +
> +GLboolean
> +_mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
> +                                  GLenum mode,
> +                                  const GLvoid *indirect)
> +{
> +   FLUSH_CURRENT(ctx, 0);
> +
> +   return valid_draw_indirect(ctx, mode,
> +                              indirect, 4 * sizeof(GLuint),

4 here and 5 below, etc. seem like magic numbers.  How about declaring 
and using a local var such as "const unsigned drawArraysNumParams = 4;" 
to clarify?


> +                              "glDrawArraysIndirect");
> +}
> +
> +GLboolean
> +_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
> +                                    GLenum mode, GLenum type,
> +                                    const GLvoid *indirect)
> +{
> +   FLUSH_CURRENT(ctx, 0);
> +
> +   return valid_draw_indirect_elements(ctx, mode, type,
> +                                       indirect, 5 * sizeof(GLuint),
> +                                       "glDrawElementsIndirect");
> +}
> +
> +GLboolean
> +_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
> +                                       GLenum mode,
> +                                       const GLvoid *indirect,
> +                                       GLsizei primcount, GLsizei stride)
> +{
> +   GLsizeiptr size = 0;
> +   if (primcount) /* &(last command) + sizeof(DrawArraysIndirectCommand) */

Is the commented code a debug left-over?


> +      size = (primcount - 1) * stride + 4 * sizeof(GLuint);
> +
> +   FLUSH_CURRENT(ctx, 0);
> +
> +   if (!valid_draw_indirect_multi(ctx, primcount, stride,
> +                                  "glMultiDrawArraysIndirect"))
> +      return GL_FALSE;
> +
> +   if (!valid_draw_indirect(ctx, mode, indirect, size,
> +                            "glMultiDrawArraysIndirect"))
> +      return GL_FALSE;
> +
> +   return GL_TRUE;
> +}
> +
> +GLboolean
> +_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
> +                                         GLenum mode, GLenum type,
> +                                         const GLvoid *indirect,
> +                                         GLsizei primcount, GLsizei stride)
> +{
> +   GLsizeiptr size = 0;

Insert blank line here.


> +   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");
> +}

I thought that when we build/init the display list 'save' dispatch 
table, the unused entries point to a generic function that generates 
GL_INVALID_OPERATION.  In that case, I don't think we'd need these 
functions.  I'd have to dig into the code to be sure though.


>
>   /**
>    * 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)) {
>



More information about the mesa-dev mailing list