<div dir="ltr">On 6 November 2013 23:06, Chris Forbes <span dir="ltr"><<a href="mailto:chrisf@ijw.co.nz" target="_blank">chrisf@ijw.co.nz</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Based on part of Patch 2 of Christoph Bumiller's ARB_draw_indirect series.<br>
<br>
Signed-off-by: Chris Forbes <<a href="mailto:chrisf@ijw.co.nz">chrisf@ijw.co.nz</a>><br>
---<br>
 src/mesa/main/api_validate.c | 163 +++++++++++++++++++++++++++++++++++++++++++<br>
 src/mesa/main/api_validate.h |  26 +++++++<br>
 2 files changed, 189 insertions(+)<br>
<br>
diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c<br>
index f285c97..befd69f 100644<br>
--- a/src/mesa/main/api_validate.c<br>
+++ b/src/mesa/main/api_validate.c<br>
@@ -837,3 +837,166 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,<br>
<br>
    return GL_TRUE;<br>
 }<br>
+<br>
+static GLboolean<br>
+valid_draw_indirect(struct gl_context *ctx,<br>
+                    GLenum mode, const GLvoid *indirect,<br>
+                    GLsizei size, const char *name)<br>
+{<br>
+   const GLsizeiptr end = (GLsizeiptr)indirect + size;<br>
+<br>
+   if (!_mesa_valid_prim_mode(ctx, mode, name))<br>
+      return GL_FALSE;<br>
+<br>
+   if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) {<br>
+      _mesa_error(ctx, GL_INVALID_OPERATION,<br>
+                  "%s(indirect is not aligned)", name);<br>
+      return GL_FALSE;<br>
+   }<br>
+<br>
+   if (_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {<br>
+      if (_mesa_bufferobj_mapped(ctx->DrawIndirectBuffer)) {<br>
+         _mesa_error(ctx, GL_INVALID_OPERATION,<br>
+                     "%s(DRAW_INDIRECT_BUFFER is mapped)", name);<br>
+         return GL_FALSE;<br>
+      }<br>
+      if (ctx->DrawIndirectBuffer->Size < end) {<br>
+         _mesa_error(ctx, GL_INVALID_OPERATION,<br>
+                     "%s(DRAW_INDIRECT_BUFFER too small)", name);<br>
+         return GL_FALSE;<br>
+      }<br>
+   } else {<br>
+      if (ctx->API != API_OPENGL_COMPAT) {<br>
+         _mesa_error(ctx, GL_INVALID_OPERATION,<br>
+                     "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);<br>
+         return GL_FALSE;<br>
+      }<br>
+   }<br>
+<br>
+   if (!check_valid_to_render(ctx, name))<br>
+      return GL_FALSE;<br>
+<br>
+   return GL_TRUE;<br>
+}<br>
+<br>
+static inline GLboolean<br>
+valid_draw_indirect_elements(struct gl_context *ctx,<br>
+                             GLenum mode, GLenum type, const GLvoid *indirect,<br>
+                             GLsizeiptr size, const char *name)<br>
+{<br>
+   if (!valid_elements_type(ctx, type, name))<br>
+      return GL_FALSE;<br>
+<br>
+   /*<br>
+    * Unlike regular DrawElementsInstancedBaseVertex commands, the indices<br>
+    * may not come from a client array and must come from an index buffer.<br>
+    * If no element array buffer is bound, an INVALID_OPERATION error is<br>
+    * generated.<br>
+    */<br>
+   if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {<br>
+      _mesa_error(ctx, GL_INVALID_OPERATION,<br>
+                  "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name);<br>
+      return GL_FALSE;<br>
+   }<br>
+<br>
+   return valid_draw_indirect(ctx, mode, indirect, size, name);<br>
+}<br>
+<br>
+static inline GLboolean<br>
+valid_draw_indirect_multi(struct gl_context *ctx,<br>
+                          GLsizei primcount, GLsizei stride,<br>
+                          const char *name)<br>
+{<br>
+   if (primcount < 0) {<br>
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);<br>
+      return GL_FALSE;<br>
+   }<br></blockquote><div><br><div>ARB_multi_draw_indirect is inconsistent about whether a primcount of 0 is allowed.  In one place it says:<br><br>    <primcount> must be positive, otherwise an INVALID_VALUE error will be<br>

    generated.<br><br></div><div>Which would seem to imply that 0 is not allowed.  But then later it says:<br><br>    INVALID_VALUE is generated by MultiDrawArraysIndirect or<br>    MultiDrawElementsIndirect if <primcount> is negative.<br>

<br></div><div>Which would seem to imply that 0 is allowed.<br><br></div><div>OpenGL 4.3 and 4.4 consistently say:<br><br>    An INVALID_VALUE error is generated if drawcount is not positive.<br><br></div><div>Usually
 when there's a difference like this between the extension specs and the
 OpenGL spec, the OpenGL spec is the correct one.  So unless we have 
experimental evidence from shipping drivers that a primcount of 0 is 
allowed, I think we should make it an error.<br>
</div><br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+   if (stride % 4) {<br>
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name);<br>
+      return GL_FALSE;<br>
+   }<br>
+<br>
+   return GL_TRUE;<br>
+}<br>
+<br>
+GLboolean<br>
+_mesa_validate_DrawArraysIndirect(struct gl_context *ctx,<br>
+                                  GLenum mode,<br>
+                                  const GLvoid *indirect)<br>
+{<br>
+   const unsigned drawArraysNumParams = 4;<br>
+<br>
+   FLUSH_CURRENT(ctx, 0);<br>
+<br>
+   return valid_draw_indirect(ctx, mode,<br>
+                              indirect, drawArraysNumParams * sizeof(GLuint),<br>
+                              "glDrawArraysIndirect");<br>
+}<br>
+<br>
+GLboolean<br>
+_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,<br>
+                                    GLenum mode, GLenum type,<br>
+                                    const GLvoid *indirect)<br>
+{<br>
+   const unsigned drawElementsNumParams = 5;<br>
+<br>
+   FLUSH_CURRENT(ctx, 0);<br>
+<br>
+   return valid_draw_indirect_elements(ctx, mode, type,<br>
+                                       indirect, drawElementsNumParams * sizeof(GLuint),<br>
+                                       "glDrawElementsIndirect");<br>
+}<br>
+<br>
+GLboolean<br>
+_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,<br>
+                                       GLenum mode,<br>
+                                       const GLvoid *indirect,<br>
+                                       GLsizei primcount, GLsizei stride)<br>
+{<br>
+   GLsizeiptr size = 0;<br>
+   const unsigned drawArraysNumParams = 4;<br>
+<br>
+   /* number of bytes of the indirect buffer which will be read */<br>
+   if (primcount)<br>
+      size = (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint);<br></blockquote><div><br></div><div>Two comments about this:<br></div><div><br>1. Given what I said above about primcount == 0 being invalid, I'd 
recommend moving this size computation after the call to 
valid_draw_indirect_multi, and dropping the "if (primcount)" part.<br><br></div><div>2. I was briefly concerned about the fact that this computation didn't take into account the fact that stride can be 0 (meaning the primitives are tightly packed), and then I realized that this is handled in the caller.  To avoid confusion, I'd recommend adding an "assert(stride != 0);" here, along with a short comment saying that the caller converts a stride of 0 to a stride of 4.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+   FLUSH_CURRENT(ctx, 0);<br>
+<br>
+   if (!valid_draw_indirect_multi(ctx, primcount, stride,<br>
+                                  "glMultiDrawArraysIndirect"))<br>
+      return GL_FALSE;<br>
+<br>
+   if (!valid_draw_indirect(ctx, mode, indirect, size,<br>
+                            "glMultiDrawArraysIndirect"))<br>
+      return GL_FALSE;<br>
+<br>
+   return GL_TRUE;<br>
+}<br>
+<br>
+GLboolean<br>
+_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,<br>
+                                         GLenum mode, GLenum type,<br>
+                                         const GLvoid *indirect,<br>
+                                         GLsizei primcount, GLsizei stride)<br>
+{<br>
+   GLsizeiptr size = 0;<br>
+   const unsigned drawElementsNumParams = 5;<br>
+<br>
+   /* number of bytes of the indirect buffer which will be read */<br>
+   if (primcount)<br>
+      size = (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint);<br></blockquote><div><br></div><div>Same two comments apply here.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

+<br>
+   FLUSH_CURRENT(ctx, 0);<br>
+<br>
+   if (!valid_draw_indirect_multi(ctx, primcount, stride,<br>
+                                  "glMultiDrawElementsIndirect"))<br>
+      return GL_FALSE;<br>
+<br>
+   if (!valid_draw_indirect_elements(ctx, mode, type,<br>
+                                     indirect, size,<br>
+                                     "glMultiDrawElementsIndirect"))<br>
+      return GL_FALSE;<br>
+<br>
+   return GL_TRUE;<br>
+}<br>
diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h<br>
index f2b753c..8238df1 100644<br>
--- a/src/mesa/main/api_validate.h<br>
+++ b/src/mesa/main/api_validate.h<br>
@@ -87,5 +87,31 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,<br>
                                      GLuint stream,<br>
                                      GLsizei numInstances);<br>
<br>
+extern GLboolean<br>
+_mesa_validate_DrawArraysIndirect(struct gl_context *ctx,<br>
+                                  GLenum mode,<br>
+                                  const GLvoid *indirect);<br>
+<br>
+extern GLboolean<br>
+_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,<br>
+                                    GLenum mode,<br>
+                                    GLenum type,<br>
+                                    const GLvoid *indirect);<br>
+<br>
+extern GLboolean<br>
+_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,<br>
+                                       GLenum mode,<br>
+                                       const GLvoid *indirect,<br>
+                                       GLsizei primcount,<br>
+                                       GLsizei stride);<br>
+<br>
+extern GLboolean<br>
+_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,<br>
+                                         GLenum mode,<br>
+                                         GLenum type,<br>
+                                         const GLvoid *indirect,<br>
+                                         GLsizei primcount,<br>
+                                         GLsizei stride);<br>
+<br>
<br>
 #endif<br>
<span class=""><font color="#888888">--<br>
1.8.4.2<br></font></span></blockquote><div><br></div><div>With those issues addressed, this patch is:<br><br>Reviewed-by: Paul Berry <<a href="mailto:stereotype441@gmail.com">stereotype441@gmail.com</a>><br></div></div>
</div></div>