[Mesa-dev] [PATCH 1/4] mesa: implement GL_ARB_draw_indirect

Christoph Bumiller e0425955 at student.tuwien.ac.at
Fri Feb 1 13:50:20 PST 2013


I have 1 piglit test to check drawing with several combinations of
parameters (using transform feedback to write the commands), but
will make some more tests for various things like interaction with
PrimitiveRestart or error conditions.

(http://people.freedesktop.org/~chrisbmr/0001-arb_draw_indirect-add-initial-test.patch)

The gallium interface specifies a start_instance parameter that the
GL extension doesn't have (it's reservedMustBeZero instead, but,
seriously, why ? D3D does have it. Because making yet another
extension will be so much fun ?)

Not sure if we want to expose this with the compatibilit profile.
---
 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/drivers/dri/i965/brw_draw.c         |    3 +-
 src/mesa/drivers/dri/i965/brw_draw.h         |    3 +-
 src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c |    9 +-
 src/mesa/main/api_validate.c                 |  159 ++++++++++++++++
 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                       |    4 +
 src/mesa/main/tests/dispatch_sanity.cpp      |    8 +-
 src/mesa/main/vtxfmt.c                       |    7 +
 src/mesa/state_tracker/st_cb_rasterpos.c     |    2 +-
 src/mesa/state_tracker/st_draw.c             |    3 +-
 src/mesa/state_tracker/st_draw.h             |    6 +-
 src/mesa/state_tracker/st_draw_feedback.c    |    3 +-
 src/mesa/tnl/tnl.h                           |    3 +-
 src/mesa/vbo/vbo.h                           |    5 +-
 src/mesa/vbo/vbo_exec_array.c                |  251 +++++++++++++++++++++++++-
 src/mesa/vbo/vbo_exec_draw.c                 |    2 +-
 src/mesa/vbo/vbo_primitive_restart.c         |    4 +-
 src/mesa/vbo/vbo_rebase.c                    |    2 +-
 src/mesa/vbo/vbo_save_api.c                  |   53 ++++++
 src/mesa/vbo/vbo_save_draw.c                 |    2 +-
 src/mesa/vbo/vbo_split_copy.c                |    2 +-
 src/mesa/vbo/vbo_split_inplace.c             |    2 +-
 31 files changed, 652 insertions(+), 28 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 4d51bbc..37fdea1 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 4cbd724..bb6034f 100644
--- a/src/mapi/glapi/gen/gl_API.xml
+++ b/src/mapi/glapi/gen/gl_API.xml
@@ -8239,6 +8239,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"/>
@@ -8316,7 +8318,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/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c
index 2c2b826..b9829e5 100644
--- a/src/mesa/drivers/dri/i965/brw_draw.c
+++ b/src/mesa/drivers/dri/i965/brw_draw.c
@@ -548,7 +548,8 @@ void brw_draw_prims( struct gl_context *ctx,
 		     GLboolean index_bounds_valid,
 		     GLuint min_index,
 		     GLuint max_index,
-		     struct gl_transform_feedback_object *tfb_vertcount )
+		     struct gl_transform_feedback_object *tfb_vertcount,
+		     struct gl_buffer_object *indirect )
 {
    const struct gl_client_array **arrays = ctx->Array._DrawArrays;
 
diff --git a/src/mesa/drivers/dri/i965/brw_draw.h b/src/mesa/drivers/dri/i965/brw_draw.h
index d86a9e7..3dfac2e 100644
--- a/src/mesa/drivers/dri/i965/brw_draw.h
+++ b/src/mesa/drivers/dri/i965/brw_draw.h
@@ -41,7 +41,8 @@ void brw_draw_prims( struct gl_context *ctx,
 		     GLboolean index_bounds_valid,
 		     GLuint min_index,
 		     GLuint max_index,
-		     struct gl_transform_feedback_object *tfb_vertcount );
+		     struct gl_transform_feedback_object *tfb_vertcount,
+		     struct gl_buffer_object *tfb_vertcount );
 
 void brw_draw_init( struct brw_context *brw );
 void brw_draw_destroy( struct brw_context *brw );
diff --git a/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c b/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c
index 436db32..4dee0b8 100644
--- a/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c
+++ b/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c
@@ -222,7 +222,8 @@ TAG(vbo_render_prims)(struct gl_context *ctx,
 		      const struct _mesa_index_buffer *ib,
 		      GLboolean index_bounds_valid,
 		      GLuint min_index, GLuint max_index,
-		      struct gl_transform_feedback_object *tfb_vertcount);
+		      struct gl_transform_feedback_object *tfb_vertcount,
+		      struct gl_buffer_object *indirect);
 
 static GLboolean
 vbo_maybe_split(struct gl_context *ctx, const struct gl_client_array **arrays,
@@ -453,7 +454,8 @@ TAG(vbo_render_prims)(struct gl_context *ctx,
 		      const struct _mesa_index_buffer *ib,
 		      GLboolean index_bounds_valid,
 		      GLuint min_index, GLuint max_index,
-		      struct gl_transform_feedback_object *tfb_vertcount)
+		      struct gl_transform_feedback_object *tfb_vertcount,
+		      struct gl_buffer_object *indirect)
 {
 	struct nouveau_render_state *render = to_render_state(ctx);
 	const struct gl_client_array **arrays = ctx->Array._DrawArrays;
@@ -489,7 +491,8 @@ TAG(vbo_check_render_prims)(struct gl_context *ctx,
 			    const struct _mesa_index_buffer *ib,
 			    GLboolean index_bounds_valid,
 			    GLuint min_index, GLuint max_index,
-			    struct gl_transform_feedback_object *tfb_vertcount)
+			    struct gl_transform_feedback_object *tfb_vertcount,
+			    struct gl_buffer_object *indirect)
 {
 	struct nouveau_context *nctx = to_nouveau_context(ctx);
 
diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c
index 53b0021..db9566c 100644
--- a/src/mesa/main/api_validate.c
+++ b/src/mesa/main/api_validate.c
@@ -737,3 +737,162 @@ _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;
+}
+
+extern GLboolean
+_mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
+                                  GLenum mode,
+                                  const GLvoid *indirect)
+{
+   FLUSH_CURRENT(ctx, 0);
+
+   if (!valid_draw_indirect(ctx, mode,
+                            indirect, 4 * sizeof(GLuint),
+                            "glDrawArraysIndirect"))
+      return GL_FALSE;
+
+   return GL_TRUE;
+}
+
+extern GLboolean
+_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
+                                    GLenum mode, GLenum type,
+                                    const GLvoid *indirect)
+{
+   FLUSH_CURRENT(ctx, 0);
+
+   if (!valid_draw_indirect_elements(ctx, mode, type,
+                                     indirect, 5 * sizeof(GLuint),
+                                     "glDrawElementsIndirect"))
+      return GL_FALSE;
+
+   return GL_TRUE;
+}
+
+extern GLboolean
+_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
+                                       GLenum mode,
+                                       const GLvoid *indirect,
+                                       GLsizei primcount, GLsizei stride)
+{
+   GLsizeiptr size = 0;
+   if (primcount)
+      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;
+}
+
+extern GLboolean
+_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
+                                         GLenum mode, GLenum type,
+                                         const GLvoid *indirect,
+                                         GLsizei primcount, GLsizei stride)
+{
+   GLsizeiptr size = 0;
+   if (primcount)
+      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 7c06938..2a8c82b 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 9a75fd9..a7f0734 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -1065,6 +1065,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 c9638a1..04c6be7 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_multi_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 da1e01c..fc0b4f5 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -354,6 +354,7 @@ EXTRA_EXT(ARB_timer_query);
 EXTRA_EXT(ARB_map_buffer_alignment);
 EXTRA_EXT(ARB_texture_cube_map_array);
 EXTRA_EXT(ARB_texture_buffer_range);
+EXTRA_EXT(ARB_draw_indirect);
 
 static const int
 extra_NV_primitive_restart[] = {
@@ -840,6 +841,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 b6bed80..75e9333 100644
--- a/src/mesa/main/get_hash_params.py
+++ b/src/mesa/main/get_hash_params.py
@@ -707,6 +707,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 b92f98e..54a8a55 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -3051,6 +3051,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;
@@ -3065,6 +3066,7 @@ struct gl_extensions
    GLboolean ARB_internalformat_query;
    GLboolean ARB_map_buffer_alignment;
    GLboolean ARB_map_buffer_range;
+   GLboolean ARB_multi_draw_indirect;
    GLboolean ARB_occlusion_query;
    GLboolean ARB_occlusion_query2;
    GLboolean ARB_point_sprite;
@@ -3605,6 +3607,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 399b9a5..507528e 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 347d07d..73e160c 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/state_tracker/st_cb_rasterpos.c b/src/mesa/state_tracker/st_cb_rasterpos.c
index fb4a62e..9bbc22e 100644
--- a/src/mesa/state_tracker/st_cb_rasterpos.c
+++ b/src/mesa/state_tracker/st_cb_rasterpos.c
@@ -255,7 +255,7 @@ st_RasterPos(struct gl_context *ctx, const GLfloat v[4])
     * st_feedback_draw_vbo doesn't check for that flag. */
    ctx->Array._DrawArrays = rs->arrays;
    st_feedback_draw_vbo(ctx, &rs->prim, 1, NULL, GL_TRUE, 0, 1,
-                        NULL);
+                        NULL, NULL);
    ctx->Array._DrawArrays = saved_arrays;
 
    /* restore draw's rasterization stage depending on rendermode */
diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index de62264..0f3aae7 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -195,7 +195,8 @@ st_draw_vbo(struct gl_context *ctx,
 	    GLboolean index_bounds_valid,
             GLuint min_index,
             GLuint max_index,
-            struct gl_transform_feedback_object *tfb_vertcount)
+            struct gl_transform_feedback_object *tfb_vertcount,
+            struct gl_buffer_object *indirect)
 {
    struct st_context *st = st_context(ctx);
    struct pipe_index_buffer ibuffer = {0};
diff --git a/src/mesa/state_tracker/st_draw.h b/src/mesa/state_tracker/st_draw.h
index 3313fc8..401992c 100644
--- a/src/mesa/state_tracker/st_draw.h
+++ b/src/mesa/state_tracker/st_draw.h
@@ -55,7 +55,8 @@ st_draw_vbo(struct gl_context *ctx,
 	    GLboolean index_bounds_valid,
             GLuint min_index,
             GLuint max_index,
-            struct gl_transform_feedback_object *tfb_vertcount);
+            struct gl_transform_feedback_object *tfb_vertcount,
+            struct gl_buffer_object *indirect);
 
 extern void
 st_feedback_draw_vbo(struct gl_context *ctx,
@@ -65,7 +66,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
 		     GLboolean index_bounds_valid,
                      GLuint min_index,
                      GLuint max_index,
-                     struct gl_transform_feedback_object *tfb_vertcount);
+                     struct gl_transform_feedback_object *tfb_vertcount,
+                     struct gl_buffer_object *indirect);
 
 /**
  * When drawing with VBOs, the addresses specified with
diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c
index ae87fb2..5ecd7a5 100644
--- a/src/mesa/state_tracker/st_draw_feedback.c
+++ b/src/mesa/state_tracker/st_draw_feedback.c
@@ -95,7 +95,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
 		     GLboolean index_bounds_valid,
                      GLuint min_index,
                      GLuint max_index,
-                     struct gl_transform_feedback_object *tfb_vertcount)
+                     struct gl_transform_feedback_object *tfb_vertcount,
+                     struct gl_buffer_object *indirect)
 {
    struct st_context *st = st_context(ctx);
    struct pipe_context *pipe = st->pipe;
diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h
index 9583228..ad361ea 100644
--- a/src/mesa/tnl/tnl.h
+++ b/src/mesa/tnl/tnl.h
@@ -92,7 +92,8 @@ _tnl_vbo_draw_prims( struct gl_context *ctx,
 		     GLboolean index_bounds_valid,
 		     GLuint min_index,
 		     GLuint max_index,
-		     struct gl_transform_feedback_object *tfb_vertcount );
+		     struct gl_transform_feedback_object *tfb_vertcount,
+		     struct gl_buffer_object *indirect );
 
 extern void
 _tnl_RasterPos(struct gl_context *ctx, const GLfloat vObj[4]);
diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index 49dab23..7156c35 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -52,6 +52,8 @@ struct _mesa_prim {
    GLint basevertex;
    GLuint num_instances;
    GLuint base_instance;
+
+   GLsizeiptr indirect_offset;
 };
 
 /* Would like to call this a "vbo_index_buffer", but this would be
@@ -79,7 +81,8 @@ typedef void (*vbo_draw_func)( struct gl_context *ctx,
 			       GLboolean index_bounds_valid,
 			       GLuint min_index,
 			       GLuint max_index,
-			       struct gl_transform_feedback_object *tfb_vertcount );
+			       struct gl_transform_feedback_object *tfb_vertcount,
+			       struct gl_buffer_object *indirect );
 
 
 
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 7e61f7b..c14b88c 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -542,7 +542,7 @@ vbo_handle_primitive_restart(struct gl_context *ctx,
    } else {
       /* Call driver directly for draw_prims */
       vbo->draw_prims(ctx, prim, nr_prims, ib,
-                      index_bounds_valid, min_index, max_index, NULL);
+                      index_bounds_valid, min_index, max_index, NULL, NULL);
    }
 }
 
@@ -607,7 +607,7 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
          /* draw one or two prims */
          check_buffers_are_unmapped(exec->array.inputs);
          vbo->draw_prims(ctx, prim, primCount, NULL,
-                         GL_TRUE, start, start + count - 1, NULL);
+                         GL_TRUE, start, start + count - 1, NULL, NULL);
       }
    }
    else {
@@ -618,7 +618,7 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
       check_buffers_are_unmapped(exec->array.inputs);
       vbo->draw_prims(ctx, prim, 1, NULL,
                       GL_TRUE, start, start + count - 1,
-                      NULL);
+                      NULL, NULL);
    }
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
@@ -1285,7 +1285,7 @@ vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
 
    check_buffers_are_unmapped(exec->array.inputs);
    vbo->draw_prims(ctx, prim, 1, NULL,
-                   GL_TRUE, 0, 0, obj);
+                   GL_TRUE, 0, 0, obj, NULL);
 
    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
       _mesa_flush(ctx);
@@ -1359,6 +1359,245 @@ 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.
+    * (XXX: maybe modify/remove snarky comment below)
+    * Just don't advertise ARB_draw_indirect if your card sucks.
+    */
+
+   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 (!_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 (!_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 +1625,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_exec_draw.c b/src/mesa/vbo/vbo_exec_draw.c
index 9529ce0..1122356 100644
--- a/src/mesa/vbo/vbo_exec_draw.c
+++ b/src/mesa/vbo/vbo_exec_draw.c
@@ -404,7 +404,7 @@ vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
 				       GL_TRUE,
 				       0,
 				       exec->vtx.vert_count - 1,
-				       NULL);
+				       NULL, NULL);
 
 	 /* If using a real VBO, get new storage -- unless asked not to.
           */
diff --git a/src/mesa/vbo/vbo_primitive_restart.c b/src/mesa/vbo/vbo_primitive_restart.c
index a6a0149..38b4766 100644
--- a/src/mesa/vbo/vbo_primitive_restart.c
+++ b/src/mesa/vbo/vbo_primitive_restart.c
@@ -213,11 +213,11 @@ vbo_sw_primitive_restart(struct gl_context *ctx,
                 (temp_prim.count == sub_prim->count)) {
                draw_prims_func(ctx, &temp_prim, 1, ib,
                                GL_TRUE, sub_prim->min_index, sub_prim->max_index,
-                               NULL);
+                               NULL, NULL);
             } else {
                draw_prims_func(ctx, &temp_prim, 1, ib,
                                GL_FALSE, -1, -1,
-                               NULL);
+                               NULL, NULL);
             }
          }
          if (sub_end_index >= end_index) {
diff --git a/src/mesa/vbo/vbo_rebase.c b/src/mesa/vbo/vbo_rebase.c
index d0bf6c5..828e667 100644
--- a/src/mesa/vbo/vbo_rebase.c
+++ b/src/mesa/vbo/vbo_rebase.c
@@ -237,7 +237,7 @@ void vbo_rebase_prims( struct gl_context *ctx,
 	 GL_TRUE,
 	 0, 
 	 max_index - min_index,
-	 NULL );
+	 NULL, NULL );
 
    ctx->Array._DrawArrays = saved_arrays;
    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index b4c90a0..0ac182d 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -1108,6 +1108,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);
@@ -1463,6 +1512,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;
 }
 
 
diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c
index efb386e..4eeed53 100644
--- a/src/mesa/vbo/vbo_save_draw.c
+++ b/src/mesa/vbo/vbo_save_draw.c
@@ -319,7 +319,7 @@ vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
                                       GL_TRUE,
                                       0,    /* Node is a VBO, so this is ok */
                                       node->count - 1,
-                                      NULL);
+                                      NULL, NULL);
       }
    }
 
diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c
index a917f39..51c4a3a 100644
--- a/src/mesa/vbo/vbo_split_copy.c
+++ b/src/mesa/vbo/vbo_split_copy.c
@@ -201,7 +201,7 @@ flush( struct copy_context *copy )
 	       GL_TRUE,
 	       0,
 	       copy->dstbuf_nr - 1,
-	       NULL );
+	       NULL, NULL );
 
    ctx->Array._DrawArrays = saved_arrays;
    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
index 8a38308..a9ae8f1 100644
--- a/src/mesa/vbo/vbo_split_inplace.c
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -94,7 +94,7 @@ static void flush_vertex( struct split_context *split )
 	       !split->ib,
 	       split->min_index,
 	       split->max_index,
-	       NULL);
+	       NULL, NULL);
 
    ctx->Array._DrawArrays = saved_arrays;
    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
-- 
1.7.3.4



More information about the mesa-dev mailing list