mesa: Add validation helpers for new indirect draws

Based on part of Patch 2 of Christoph Bumiller's ARB_draw_indirect series.

V3: - Disallow primcount==0 for DrawMulti*Indirect. The spec is unclear
      on this, but it's silly. We might go back on this later if it
      turns out to be a problem.

    - Make it clear that the caller has dealt with stride==0

V4: - Allow primcount==0 again.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Chris Forbes 2013-11-06 20:03:21 +13:00
parent a95236cfc1
commit 36046ae278
2 changed files with 218 additions and 0 deletions

View file

@ -837,3 +837,195 @@ _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;
/* From the ARB_draw_indirect specification:
* "An INVALID_OPERATION error is generated [...] if <indirect> is no
* word aligned."
*/
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)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);
return GL_FALSE;
}
if (_mesa_bufferobj_mapped(ctx->DrawIndirectBuffer)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(DRAW_INDIRECT_BUFFER is mapped)", name);
return GL_FALSE;
}
/* From the ARB_draw_indirect specification:
* "An INVALID_OPERATION error is generated if the commands source data
* beyond the end of the buffer object [...]"
*/
if (ctx->DrawIndirectBuffer->Size < end) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(DRAW_INDIRECT_BUFFER too small)", 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)
{
/* From the ARB_multi_draw_indirect specification:
* "INVALID_VALUE is generated by MultiDrawArraysIndirect or
* MultiDrawElementsIndirect if <primcount> is negative."
*
* "<primcount> must be positive, otherwise an INVALID_VALUE error will
* be generated."
*/
if (primcount < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);
return GL_FALSE;
}
/* From the ARB_multi_draw_indirect specification:
* "<stride> must be a multiple of four, otherwise an INVALID_VALUE
* error is generated."
*/
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)
{
const unsigned drawArraysNumParams = 4;
FLUSH_CURRENT(ctx, 0);
return valid_draw_indirect(ctx, mode,
indirect, drawArraysNumParams * sizeof(GLuint),
"glDrawArraysIndirect");
}
GLboolean
_mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
GLenum mode, GLenum type,
const GLvoid *indirect)
{
const unsigned drawElementsNumParams = 5;
FLUSH_CURRENT(ctx, 0);
return valid_draw_indirect_elements(ctx, mode, type,
indirect, drawElementsNumParams * sizeof(GLuint),
"glDrawElementsIndirect");
}
GLboolean
_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
GLenum mode,
const GLvoid *indirect,
GLsizei primcount, GLsizei stride)
{
GLsizeiptr size = 0;
const unsigned drawArraysNumParams = 4;
FLUSH_CURRENT(ctx, 0);
/* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */
assert(stride != 0);
if (!valid_draw_indirect_multi(ctx, primcount, stride,
"glMultiDrawArraysIndirect"))
return GL_FALSE;
/* number of bytes of the indirect buffer which will be read */
size = primcount
? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint)
: 0;
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;
const unsigned drawElementsNumParams = 5;
FLUSH_CURRENT(ctx, 0);
/* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */
assert(stride != 0);
if (!valid_draw_indirect_multi(ctx, primcount, stride,
"glMultiDrawElementsIndirect"))
return GL_FALSE;
/* number of bytes of the indirect buffer which will be read */
size = primcount
? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint)
: 0;
if (!valid_draw_indirect_elements(ctx, mode, type,
indirect, size,
"glMultiDrawElementsIndirect"))
return GL_FALSE;
return GL_TRUE;
}

View file

@ -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