[Mesa-dev] [PATCH 2/5] mesa: implement GL_ARB_draw_indirect and GL_ARB_multi_draw_indirect

Ian Romanick idr at freedesktop.org
Fri Apr 5 14:14:35 PDT 2013


On 04/05/2013 05:29 AM, Christoph Bumiller wrote:
> 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.

I think we can dodge the issue entirely.  The extension spec says OpenGL 
3.1 is required (though it's not immediately obvious to me why), and we 
only expose OpenGL 3.1 without compatibility... without display lists.

It looks like (below) this extension is only exposed in core profile any 
way.  Just gut all the API_OPENGL_COMPAT checks and all the display list 
stuff.  That should simplify things a bit...

> ---
>   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               |    9 +
>   src/mesa/main/dd.h                      |   12 ++
>   src/mesa/main/dlist.c                   |   41 +++++
>   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/main/vtxfmt.c                  |    7 +
>   src/mesa/vbo/vbo_exec_array.c           |  249 +++++++++++++++++++++++++++++++
>   src/mesa/vbo/vbo_save_api.c             |   53 +++++++
>   15 files changed, 570 insertions(+), 5 deletions(-)
>
> diff --git a/src/mapi/glapi/gen/Makefile.am b/src/mapi/glapi/gen/Makefile.am
> index 36e47e2..243c148 100644
> --- a/src/mapi/glapi/gen/Makefile.am
> +++ b/src/mapi/glapi/gen/Makefile.am
> @@ -96,6 +96,7 @@ API_XML = \
>   	ARB_depth_clamp.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 df95924..f22fdac 100644
> --- a/src/mapi/glapi/gen/gl_API.xml
> +++ b/src/mapi/glapi/gen/gl_API.xml
> @@ -8240,6 +8240,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"/>
> @@ -8317,7 +8319,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 53b0021..e875c5d 100644
> --- a/src/mesa/main/api_validate.c
> +++ b/src/mesa/main/api_validate.c
> @@ -737,3 +737,156 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
>
>      return GL_TRUE;
>   }
> +
> +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),
> +                              "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 0ca9c90..38c6efd 100644
> --- a/src/mesa/main/api_validate.h
> +++ b/src/mesa/main/api_validate.h
> @@ -85,5 +85,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 b82ba7b..0fe01d4 100644
> --- a/src/mesa/main/bufferobj.c
> +++ b/src/mesa/main/bufferobj.c
> @@ -87,6 +87,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;
> @@ -875,6 +879,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/dd.h b/src/mesa/main/dd.h
> index 8f3cd3d..51a78b4 100644
> --- a/src/mesa/main/dd.h
> +++ b/src/mesa/main/dd.h
> @@ -1078,6 +1078,18 @@ typedef struct {
>                                                              GLuint name,
>                                                              GLuint stream,
>                                                              GLsizei primcount);
> +   void (GLAPIENTRYP DrawArraysIndirect)(GLenum mode,
> +                                         const GLvoid *indirect);
> +   void (GLAPIENTRYP DrawElementsIndirect)(GLenum mode, GLenum type,
> +                                           const GLvoid *indirect);
> +   void (GLAPIENTRYP MultiDrawArraysIndirect)(GLenum mode,
> +                                              const GLvoid *indirect,
> +                                              GLsizei primcount,
> +                                              GLsizei stride);
> +   void (GLAPIENTRYP MultiDrawElementsIndirect)(GLenum mode, GLenum type,
> +                                                const GLvoid *indirect,
> +                                                GLsizei primcount,
> +                                                GLsizei stride);
>      /*@}*/
>
>      /**
> diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c
> index 4b20d89..45e7439 100644
> --- a/src/mesa/main/dlist.c
> +++ b/src/mesa/main/dlist.c
> @@ -1356,6 +1356,41 @@ save_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode,
>   	       "glDrawElementsInstancedBaseVertexBaseInstance() during display list compile");
>   }
>
> +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");
> +}
> +
> +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");
> +}
> +
>   static void invalidate_saved_current_state( struct gl_context *ctx )
>   {
>      GLint i;
> @@ -9620,6 +9655,12 @@ _mesa_save_vtxfmt_init(GLvertexformat * vfmt)
>      vfmt->DrawElementsInstancedBaseInstance = save_DrawElementsInstancedBaseInstance;
>      vfmt->DrawElementsInstancedBaseVertexBaseInstance = save_DrawElementsInstancedBaseVertexBaseInstance;
>
> +   /* GL_ARB_draw_indirect and GL_ARB_multi_draw_indirect */
> +   vfmt->DrawArraysIndirect = save_DrawArraysIndirect;
> +   vfmt->MultiDrawArraysIndirect = save_MultiDrawArraysIndirect;
> +   vfmt->DrawElementsIndirect = save_DrawElementsIndirect;
> +   vfmt->MultiDrawElementsIndirect = save_MultiDrawElementsIndirect;
> +
>      /* The driver is required to implement these as
>       * 1) They can probably do a better job.
>       * 2) A lot of new mechanisms would have to be added to this module
> diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c
> index c7f038b..a124c04 100644
> --- a/src/mesa/main/extensions.c
> +++ b/src/mesa/main/extensions.c
> @@ -93,6 +93,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 582ef31..f0f44aa 100644
> --- a/src/mesa/main/get.c
> +++ b/src/mesa/main/get.c
> @@ -356,6 +356,7 @@ EXTRA_EXT(ARB_map_buffer_alignment);
>   EXTRA_EXT(ARB_texture_cube_map_array);
>   EXTRA_EXT(ARB_texture_buffer_range);
>   EXTRA_EXT(ARB_texture_multisample);
> +EXTRA_EXT(ARB_draw_indirect);
>
>   static const int
>   extra_NV_primitive_restart[] = {
> @@ -853,6 +854,10 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
>            _mesa_problem(ctx, "driver doesn't implement GetTimestamp");
>         }
>         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 7d4f7e2..68513dc 100644
> --- a/src/mesa/main/get_hash_params.py
> +++ b/src/mesa/main/get_hash_params.py
> @@ -715,6 +715,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 ace6938..b7852c7 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -2953,6 +2953,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;
> @@ -3515,6 +3516,8 @@ struct gl_context
>
>      struct gl_transform_feedback_state TransformFeedback;
>
> +   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 ffd83fe..dedaef4 100644
> --- a/src/mesa/main/tests/dispatch_sanity.cpp
> +++ b/src/mesa/main/tests/dispatch_sanity.cpp
> @@ -674,8 +674,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
> @@ -884,8 +884,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/main/vtxfmt.c b/src/mesa/main/vtxfmt.c
> index 8669c40..92a9374 100644
> --- a/src/mesa/main/vtxfmt.c
> +++ b/src/mesa/main/vtxfmt.c
> @@ -147,6 +147,13 @@ install_vtxfmt(struct gl_context *ctx, struct _glapi_table *tab,
>                                                  vfmt->DrawTransformFeedbackStreamInstanced);
>      }
>
> +   if (_mesa_is_desktop_gl(ctx)) {
> +      SET_DrawArraysIndirect(tab, vfmt->DrawArraysIndirect);
> +      SET_DrawElementsIndirect(tab, vfmt->DrawElementsIndirect);
> +      SET_MultiDrawArraysIndirect(tab, vfmt->MultiDrawArraysIndirect);
> +      SET_MultiDrawElementsIndirect(tab, vfmt->MultiDrawElementsIndirect);
> +   }
> +
>      /* Originally for GL_NV_vertex_program, this is also used by dlist.c */
>      if (ctx->API == API_OPENGL_COMPAT) {
>         SET_VertexAttrib1fNV(tab, vfmt->VertexAttrib1fNV);
> diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
> index 93674e2..75fda00 100644
> --- a/src/mesa/vbo/vbo_exec_array.c
> +++ b/src/mesa/vbo/vbo_exec_array.c
> @@ -1359,6 +1359,251 @@ 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);
> +}
> +
>   /**
>    * Plug in the immediate-mode vertex array drawing commands into the
>    * givven vbo_exec_context object.
> @@ -1386,6 +1631,10 @@ vbo_exec_array_init( struct vbo_exec_context *exec )
>            vbo_exec_DrawTransformFeedbackInstanced;
>      exec->vtxfmt.DrawTransformFeedbackStreamInstanced =
>            vbo_exec_DrawTransformFeedbackStreamInstanced;
> +   exec->vtxfmt.DrawArraysIndirect = vbo_exec_DrawArraysIndirect;
> +   exec->vtxfmt.DrawElementsIndirect = vbo_exec_DrawElementsIndirect;
> +   exec->vtxfmt.MultiDrawArraysIndirect = vbo_exec_MultiDrawArraysIndirect;
> +   exec->vtxfmt.MultiDrawElementsIndirect = vbo_exec_MultiDrawElementsIndirect;
>   }
>
>
> diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
> index 7490717..37e3342 100644
> --- a/src/mesa/vbo/vbo_save_api.c
> +++ b/src/mesa/vbo/vbo_save_api.c
> @@ -1151,6 +1151,55 @@ _save_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name,
>
>
>   static void GLAPIENTRY
> +_save_DrawArraysIndirect(GLenum mode, const GLvoid *indirect)
> +{
> +   GET_CURRENT_CONTEXT(ctx);
> +   (void) mode;
> +   (void) indirect;
> +   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawArraysIndirect");
> +}
> +
> +
> +static void GLAPIENTRY
> +_save_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect)
> +{
> +   GET_CURRENT_CONTEXT(ctx);
> +   (void) mode;
> +   (void) type;
> +   (void) indirect;
> +   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElementsIndirect");
> +}
> +
> +
> +static void GLAPIENTRY
> +_save_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect,
> +                              GLsizei primcount, GLsizei stride)
> +{
> +   GET_CURRENT_CONTEXT(ctx);
> +   (void) mode;
> +   (void) indirect;
> +   (void) primcount;
> +   (void) stride;
> +   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glMultiDrawArraysIndirect");
> +}
> +
> +
> +static void GLAPIENTRY
> +_save_MultiDrawElementsIndirect(GLenum mode, GLenum type,
> +                                const GLvoid *indirect,
> +                                GLsizei primcount, GLsizei stride)
> +{
> +   GET_CURRENT_CONTEXT(ctx);
> +   (void) mode;
> +   (void) type;
> +   (void) indirect;
> +   (void) primcount;
> +   (void) stride;
> +   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glMultiDrawElementsIndirect");
> +}
> +
> +
> +static void GLAPIENTRY
>   _save_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
>   {
>      GET_CURRENT_CONTEXT(ctx);
> @@ -1506,6 +1555,10 @@ _save_vtxfmt_init(struct gl_context *ctx)
>      vfmt->DrawTransformFeedbackInstanced = _save_DrawTransformFeedbackInstanced;
>      vfmt->DrawTransformFeedbackStreamInstanced =
>            _save_DrawTransformFeedbackStreamInstanced;
> +   vfmt->DrawArraysIndirect = _save_DrawArraysIndirect;
> +   vfmt->DrawElementsIndirect = _save_DrawElementsIndirect;
> +   vfmt->MultiDrawArraysIndirect = _save_MultiDrawArraysIndirect;
> +   vfmt->MultiDrawElementsIndirect = _save_MultiDrawElementsIndirect;
>   }
>
>
>



More information about the mesa-dev mailing list