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

Ian Romanick idr at freedesktop.org
Mon Nov 4 10:56:25 PST 2013


On 11/04/2013 01: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
> 
> 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 *"/>
> +    </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;
>  }
> +
> +static GLboolean

If you do the patch splitting suggested by Brian, perhaps do some
s/GLboolean/bool/ too.

> +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),
> +                              "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) */
> +      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;
> +   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)

             && _mesa_is_desktop_gl(ctx)

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

Where is this error documented?  I don't see it in the extension spec.
Or is this just because we're only doing these extensions in core
profiles and there are no display lists in core profile?

> +}
> +
> +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)) {
> 



More information about the mesa-dev mailing list