From e1eab5a76f20061c005c8254b11ca1611ebda8f7 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Thu, 31 Dec 2015 16:11:56 -0500 Subject: [PATCH] mesa: add support for ARB_indirect_parameters draw functions MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilia Mirkin Reviewed-by: Marek Olšák --- src/mesa/main/api_validate.c | 115 ++++++++++++++++++++++++++++++++++ src/mesa/main/api_validate.h | 16 +++++ src/mesa/vbo/vbo_exec_array.c | 103 ++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index d693ec64ce4..2b629977644 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -920,6 +920,121 @@ _mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx, return GL_TRUE; } +static GLboolean +valid_draw_indirect_parameters(struct gl_context *ctx, + const char *name, + GLintptr drawcount) +{ + /* From the ARB_indirect_parameters specification: + * "INVALID_VALUE is generated by MultiDrawArraysIndirectCountARB or + * MultiDrawElementsIndirectCountARB if is not a multiple of + * four." + */ + if (drawcount & 3) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(drawcount is not a multiple of 4)", name); + return GL_FALSE; + } + + /* From the ARB_indirect_parameters specification: + * "INVALID_OPERATION is generated by MultiDrawArraysIndirectCountARB or + * MultiDrawElementsIndirectCountARB if no buffer is bound to the + * PARAMETER_BUFFER_ARB binding point." + */ + if (!_mesa_is_bufferobj(ctx->ParameterBuffer)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s: no buffer bound to PARAMETER_BUFFER", name); + return GL_FALSE; + } + + if (_mesa_check_disallowed_mapping(ctx->ParameterBuffer)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(PARAMETER_BUFFER is mapped)", name); + return GL_FALSE; + } + + /* From the ARB_indirect_parameters specification: + * "INVALID_OPERATION is generated by MultiDrawArraysIndirectCountARB or + * MultiDrawElementsIndirectCountARB if reading a typed value + * from the buffer bound to the PARAMETER_BUFFER_ARB target at the offset + * specified by would result in an out-of-bounds access." + */ + if (ctx->ParameterBuffer->Size < drawcount + sizeof(GLsizei)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(PARAMETER_BUFFER too small)", name); + return GL_FALSE; + } + + return GL_TRUE; +} + +GLboolean +_mesa_validate_MultiDrawArraysIndirectCount(struct gl_context *ctx, + GLenum mode, + GLintptr indirect, + GLintptr drawcount, + GLsizei maxdrawcount, + 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, maxdrawcount, stride, + "glMultiDrawArraysIndirectCountARB")) + return GL_FALSE; + + /* number of bytes of the indirect buffer which will be read */ + size = maxdrawcount + ? (maxdrawcount - 1) * stride + drawArraysNumParams * sizeof(GLuint) + : 0; + + if (!valid_draw_indirect(ctx, mode, (void *)indirect, size, + "glMultiDrawArraysIndirectCountARB")) + return GL_FALSE; + + return valid_draw_indirect_parameters( + ctx, "glMultiDrawArraysIndirectCountARB", drawcount); +} + +GLboolean +_mesa_validate_MultiDrawElementsIndirectCount(struct gl_context *ctx, + GLenum mode, GLenum type, + GLintptr indirect, + GLintptr drawcount, + GLsizei maxdrawcount, + 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, maxdrawcount, stride, + "glMultiDrawElementsIndirectCountARB")) + return GL_FALSE; + + /* number of bytes of the indirect buffer which will be read */ + size = maxdrawcount + ? (maxdrawcount - 1) * stride + drawElementsNumParams * sizeof(GLuint) + : 0; + + if (!valid_draw_indirect_elements(ctx, mode, type, + (void *)indirect, size, + "glMultiDrawElementsIndirectCountARB")) + return GL_FALSE; + + return valid_draw_indirect_parameters( + ctx, "glMultiDrawElementsIndirectCountARB", drawcount); +} + static bool check_valid_to_compute(struct gl_context *ctx, const char *function) { diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h index 5d030a7ba37..5b321e3ac99 100644 --- a/src/mesa/main/api_validate.h +++ b/src/mesa/main/api_validate.h @@ -105,6 +105,22 @@ _mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx, GLsizei primcount, GLsizei stride); +extern GLboolean +_mesa_validate_MultiDrawArraysIndirectCount(struct gl_context *ctx, + GLenum mode, + GLintptr indirect, + GLintptr drawcount, + GLsizei maxdrawcount, + GLsizei stride); + +extern GLboolean +_mesa_validate_MultiDrawElementsIndirectCount(struct gl_context *ctx, + GLenum mode, GLenum type, + GLintptr indirect, + GLintptr drawcount, + GLsizei maxdrawcount, + GLsizei stride); + extern GLboolean _mesa_validate_DispatchCompute(struct gl_context *ctx, const GLuint *num_groups); diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index c5019b1aa59..02139ef881f 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -1732,13 +1732,96 @@ vbo_exec_MultiDrawElementsIndirect(GLenum mode, GLenum type, primcount, stride); } +static void +vbo_validated_multidrawarraysindirectcount(struct gl_context *ctx, + GLenum mode, + GLintptr indirect, + GLintptr drawcount, + GLsizei maxdrawcount, + GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + GLsizeiptr offset = indirect; + + if (maxdrawcount == 0) + return; + + vbo_bind_arrays(ctx); + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_indirect_prims(ctx, mode, + ctx->DrawIndirectBuffer, offset, + maxdrawcount, stride, + ctx->ParameterBuffer, drawcount, + NULL); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawelementsindirectcount(struct gl_context *ctx, + GLenum mode, GLenum type, + GLintptr indirect, + GLintptr drawcount, + GLsizei maxdrawcount, + GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + GLsizeiptr offset = (GLsizeiptr)indirect; + + if (maxdrawcount == 0) + return; + + vbo_bind_arrays(ctx); + + /* NOTE: IndexBufferObj is guaranteed to be a VBO. */ + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.VAO->IndexBufferObj; + ib.ptr = NULL; + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_indirect_prims(ctx, mode, + ctx->DrawIndirectBuffer, offset, + maxdrawcount, stride, + ctx->ParameterBuffer, drawcount, + &ib); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + static void GLAPIENTRY vbo_exec_MultiDrawArraysIndirectCount(GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawArraysIndirectCountARB" + "(%s, %lx, %lx, %i, %i)\n", + _mesa_enum_to_string(mode), indirect, + drawcount, maxdrawcount, stride); + /* If is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 4 * sizeof(GLuint); /* sizeof(DrawArraysIndirectCommand) */ + + if (!_mesa_validate_MultiDrawArraysIndirectCount(ctx, mode, + indirect, drawcount, + maxdrawcount, stride)) + return; + + vbo_validated_multidrawarraysindirectcount(ctx, mode, + indirect, drawcount, + maxdrawcount, stride); } static void GLAPIENTRY @@ -1747,7 +1830,27 @@ vbo_exec_MultiDrawElementsIndirectCount(GLenum mode, GLenum type, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawElementsIndirectCountARB" + "(%s, %s, %lx, %lx, %i, %i)\n", + _mesa_enum_to_string(mode), + _mesa_enum_to_string(type), indirect, + drawcount, maxdrawcount, stride); + + /* If is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 5 * sizeof(GLuint); /* sizeof(DrawElementsIndirectCommand) */ + + if (!_mesa_validate_MultiDrawElementsIndirectCount(ctx, mode, type, + indirect, drawcount, + maxdrawcount, stride)) + return; + vbo_validated_multidrawelementsindirectcount(ctx, mode, type, + indirect, drawcount, + maxdrawcount, stride); } -- 2.30.2