diff options
author | Chris Forbes <[email protected]> | 2013-11-06 20:03:21 +1300 |
---|---|---|
committer | Chris Forbes <[email protected]> | 2013-11-25 22:01:35 +1300 |
commit | 36046ae2789f74c04e6b62fa5250d81e8d1160eb (patch) | |
tree | c71e4f473e6e9b2b71b2144caedc861b3692db29 | |
parent | a95236cfc1d55750840a6ac7a5747da3ecd200d2 (diff) |
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 <[email protected]>
Reviewed-by: Paul Berry <[email protected]>
Reviewed-by: Kenneth Graunke <[email protected]>
Reviewed-by: Eric Anholt <[email protected]>
-rw-r--r-- | src/mesa/main/api_validate.c | 192 | ||||
-rw-r--r-- | src/mesa/main/api_validate.h | 26 |
2 files changed, 218 insertions, 0 deletions
diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index f285c9748ed..96b178905cc 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -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; +} diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h index f2b753ca90f..8238df16c24 100644 --- a/src/mesa/main/api_validate.h +++ b/src/mesa/main/api_validate.h @@ -87,5 +87,31 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx, GLuint stream, GLsizei numInstances); +extern GLboolean +_mesa_validate_DrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect); + +extern GLboolean +_mesa_validate_DrawElementsIndirect(struct gl_context *ctx, + GLenum mode, + GLenum type, + const GLvoid *indirect); + +extern GLboolean +_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, + GLsizei stride); + +extern GLboolean +_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx, + GLenum mode, + GLenum type, + const GLvoid *indirect, + GLsizei primcount, + GLsizei stride); + #endif |