mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-03 11:30:21 +01:00
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:
parent
a95236cfc1
commit
36046ae278
2 changed files with 218 additions and 0 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue