diff options
Diffstat (limited to 'src/mesa/main/compute.c')
-rw-r--r-- | src/mesa/main/compute.c | 234 |
1 files changed, 229 insertions, 5 deletions
diff --git a/src/mesa/main/compute.c b/src/mesa/main/compute.c index bb6253906bc..5c845166884 100644 --- a/src/mesa/main/compute.c +++ b/src/mesa/main/compute.c @@ -22,9 +22,234 @@ */ #include "glheader.h" +#include "bufferobj.h" #include "compute.h" #include "context.h" -#include "api_validate.h" + +static bool +check_valid_to_compute(struct gl_context *ctx, const char *function) +{ + if (!_mesa_has_compute_shaders(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "unsupported function (%s) called", + function); + return false; + } + + /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: + * + * "An INVALID_OPERATION error is generated if there is no active program + * for the compute shader stage." + */ + if (ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE] == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(no active compute shader)", + function); + return false; + } + + return true; +} + +static bool +validate_DispatchCompute(struct gl_context *ctx, const GLuint *num_groups) +{ + int i; + FLUSH_CURRENT(ctx, 0); + + if (!check_valid_to_compute(ctx, "glDispatchCompute")) + return GL_FALSE; + + for (i = 0; i < 3; i++) { + /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: + * + * "An INVALID_VALUE error is generated if any of num_groups_x, + * num_groups_y and num_groups_z are greater than or equal to the + * maximum work group count for the corresponding dimension." + * + * However, the "or equal to" portions appears to be a specification + * bug. In all other areas, the specification appears to indicate that + * the number of workgroups can match the MAX_COMPUTE_WORK_GROUP_COUNT + * value. For example, under DispatchComputeIndirect: + * + * "If any of num_groups_x, num_groups_y or num_groups_z is greater than + * the value of MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding + * dimension then the results are undefined." + * + * Additionally, the OpenGLES 3.1 specification does not contain "or + * equal to" as an error condition. + */ + if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDispatchCompute(num_groups_%c)", 'x' + i); + return GL_FALSE; + } + } + + /* The ARB_compute_variable_group_size spec says: + * + * "An INVALID_OPERATION error is generated by DispatchCompute if the active + * program for the compute shader stage has a variable work group size." + */ + struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; + if (prog->info.cs.local_size_variable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDispatchCompute(variable work group size forbidden)"); + return GL_FALSE; + } + + return GL_TRUE; +} + +static bool +validate_DispatchComputeGroupSizeARB(struct gl_context *ctx, + const GLuint *num_groups, + const GLuint *group_size) +{ + GLuint total_invocations = 1; + int i; + + FLUSH_CURRENT(ctx, 0); + + if (!check_valid_to_compute(ctx, "glDispatchComputeGroupSizeARB")) + return GL_FALSE; + + /* The ARB_compute_variable_group_size spec says: + * + * "An INVALID_OPERATION error is generated by + * DispatchComputeGroupSizeARB if the active program for the compute + * shader stage has a fixed work group size." + */ + struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; + if (!prog->info.cs.local_size_variable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDispatchComputeGroupSizeARB(fixed work group size " + "forbidden)"); + return GL_FALSE; + } + + for (i = 0; i < 3; i++) { + /* The ARB_compute_variable_group_size spec says: + * + * "An INVALID_VALUE error is generated if any of num_groups_x, + * num_groups_y and num_groups_z are greater than or equal to the + * maximum work group count for the corresponding dimension." + */ + if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDispatchComputeGroupSizeARB(num_groups_%c)", 'x' + i); + return GL_FALSE; + } + + /* The ARB_compute_variable_group_size spec says: + * + * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if + * any of <group_size_x>, <group_size_y>, or <group_size_z> is less than + * or equal to zero or greater than the maximum local work group size + * for compute shaders with variable group size + * (MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB) in the corresponding + * dimension." + * + * However, the "less than" is a spec bug because they are declared as + * unsigned integers. + */ + if (group_size[i] == 0 || + group_size[i] > ctx->Const.MaxComputeVariableGroupSize[i]) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDispatchComputeGroupSizeARB(group_size_%c)", 'x' + i); + return GL_FALSE; + } + + total_invocations *= group_size[i]; + } + + /* The ARB_compute_variable_group_size spec says: + * + * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if + * the product of <group_size_x>, <group_size_y>, and <group_size_z> exceeds + * the implementation-dependent maximum local work group invocation count + * for compute shaders with variable group size + * (MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB)." + */ + if (total_invocations > ctx->Const.MaxComputeVariableGroupInvocations) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDispatchComputeGroupSizeARB(product of local_sizes " + "exceeds MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB " + "(%d > %d))", total_invocations, + ctx->Const.MaxComputeVariableGroupInvocations); + return GL_FALSE; + } + + return GL_TRUE; +} + +static bool +valid_dispatch_indirect(struct gl_context *ctx, GLintptr indirect) +{ + FLUSH_CURRENT(ctx, 0); + + GLsizei size = 3 * sizeof(GLuint); + const uint64_t end = (uint64_t) indirect + size; + const char *name = "glDispatchComputeIndirect"; + + if (!check_valid_to_compute(ctx, name)) + return GL_FALSE; + + /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: + * + * "An INVALID_VALUE error is generated if indirect is negative or is not a + * multiple of four." + */ + if (indirect & (sizeof(GLuint) - 1)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(indirect is not aligned)", name); + return GL_FALSE; + } + + if (indirect < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(indirect is less than zero)", name); + return GL_FALSE; + } + + /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: + * + * "An INVALID_OPERATION error is generated if no buffer is bound to the + * DRAW_INDIRECT_BUFFER binding, or if the command would source data + * beyond the end of the buffer object." + */ + if (!_mesa_is_bufferobj(ctx->DispatchIndirectBuffer)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s: no buffer bound to DISPATCH_INDIRECT_BUFFER", name); + return GL_FALSE; + } + + if (_mesa_check_disallowed_mapping(ctx->DispatchIndirectBuffer)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(DISPATCH_INDIRECT_BUFFER is mapped)", name); + return GL_FALSE; + } + + if (ctx->DispatchIndirectBuffer->Size < end) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(DISPATCH_INDIRECT_BUFFER too small)", name); + return GL_FALSE; + } + + /* The ARB_compute_variable_group_size spec says: + * + * "An INVALID_OPERATION error is generated if the active program for the + * compute shader stage has a variable work group size." + */ + struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; + if (prog->info.cs.local_size_variable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(variable work group size forbidden)", name); + return GL_FALSE; + } + + return GL_TRUE; +} void GLAPIENTRY _mesa_DispatchCompute(GLuint num_groups_x, @@ -38,7 +263,7 @@ _mesa_DispatchCompute(GLuint num_groups_x, _mesa_debug(ctx, "glDispatchCompute(%d, %d, %d)\n", num_groups_x, num_groups_y, num_groups_z); - if (!_mesa_validate_DispatchCompute(ctx, num_groups)) + if (!validate_DispatchCompute(ctx, num_groups)) return; if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u) @@ -55,7 +280,7 @@ _mesa_DispatchComputeIndirect(GLintptr indirect) if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glDispatchComputeIndirect(%ld)\n", (long) indirect); - if (!_mesa_validate_DispatchComputeIndirect(ctx, indirect)) + if (!valid_dispatch_indirect(ctx, indirect)) return; ctx->Driver.DispatchComputeIndirect(ctx, indirect); @@ -76,8 +301,7 @@ _mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y, num_groups_x, num_groups_y, num_groups_z, group_size_x, group_size_y, group_size_z); - if (!_mesa_validate_DispatchComputeGroupSizeARB(ctx, num_groups, - group_size)) + if (!validate_DispatchComputeGroupSizeARB(ctx, num_groups, group_size)) return; if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u) |