compute.c revision b8e80941
1/* 2 * Copyright © 2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "glheader.h" 25#include "bufferobj.h" 26#include "compute.h" 27#include "context.h" 28 29static bool 30check_valid_to_compute(struct gl_context *ctx, const char *function) 31{ 32 if (!_mesa_has_compute_shaders(ctx)) { 33 _mesa_error(ctx, GL_INVALID_OPERATION, 34 "unsupported function (%s) called", 35 function); 36 return false; 37 } 38 39 /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: 40 * 41 * "An INVALID_OPERATION error is generated if there is no active program 42 * for the compute shader stage." 43 */ 44 if (ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE] == NULL) { 45 _mesa_error(ctx, GL_INVALID_OPERATION, 46 "%s(no active compute shader)", 47 function); 48 return false; 49 } 50 51 return true; 52} 53 54static bool 55validate_DispatchCompute(struct gl_context *ctx, const GLuint *num_groups) 56{ 57 if (!check_valid_to_compute(ctx, "glDispatchCompute")) 58 return GL_FALSE; 59 60 for (int i = 0; i < 3; i++) { 61 /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: 62 * 63 * "An INVALID_VALUE error is generated if any of num_groups_x, 64 * num_groups_y and num_groups_z are greater than or equal to the 65 * maximum work group count for the corresponding dimension." 66 * 67 * However, the "or equal to" portions appears to be a specification 68 * bug. In all other areas, the specification appears to indicate that 69 * the number of workgroups can match the MAX_COMPUTE_WORK_GROUP_COUNT 70 * value. For example, under DispatchComputeIndirect: 71 * 72 * "If any of num_groups_x, num_groups_y or num_groups_z is greater than 73 * the value of MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding 74 * dimension then the results are undefined." 75 * 76 * Additionally, the OpenGLES 3.1 specification does not contain "or 77 * equal to" as an error condition. 78 */ 79 if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) { 80 _mesa_error(ctx, GL_INVALID_VALUE, 81 "glDispatchCompute(num_groups_%c)", 'x' + i); 82 return GL_FALSE; 83 } 84 } 85 86 /* The ARB_compute_variable_group_size spec says: 87 * 88 * "An INVALID_OPERATION error is generated by DispatchCompute if the active 89 * program for the compute shader stage has a variable work group size." 90 */ 91 struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; 92 if (prog->info.cs.local_size_variable) { 93 _mesa_error(ctx, GL_INVALID_OPERATION, 94 "glDispatchCompute(variable work group size forbidden)"); 95 return GL_FALSE; 96 } 97 98 return GL_TRUE; 99} 100 101static bool 102validate_DispatchComputeGroupSizeARB(struct gl_context *ctx, 103 const GLuint *num_groups, 104 const GLuint *group_size) 105{ 106 GLuint total_invocations = 1; 107 108 if (!check_valid_to_compute(ctx, "glDispatchComputeGroupSizeARB")) 109 return GL_FALSE; 110 111 /* The ARB_compute_variable_group_size spec says: 112 * 113 * "An INVALID_OPERATION error is generated by 114 * DispatchComputeGroupSizeARB if the active program for the compute 115 * shader stage has a fixed work group size." 116 */ 117 struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; 118 if (!prog->info.cs.local_size_variable) { 119 _mesa_error(ctx, GL_INVALID_OPERATION, 120 "glDispatchComputeGroupSizeARB(fixed work group size " 121 "forbidden)"); 122 return GL_FALSE; 123 } 124 125 for (int i = 0; i < 3; i++) { 126 /* The ARB_compute_variable_group_size spec says: 127 * 128 * "An INVALID_VALUE error is generated if any of num_groups_x, 129 * num_groups_y and num_groups_z are greater than or equal to the 130 * maximum work group count for the corresponding dimension." 131 */ 132 if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) { 133 _mesa_error(ctx, GL_INVALID_VALUE, 134 "glDispatchComputeGroupSizeARB(num_groups_%c)", 'x' + i); 135 return GL_FALSE; 136 } 137 138 /* The ARB_compute_variable_group_size spec says: 139 * 140 * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if 141 * any of <group_size_x>, <group_size_y>, or <group_size_z> is less than 142 * or equal to zero or greater than the maximum local work group size 143 * for compute shaders with variable group size 144 * (MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB) in the corresponding 145 * dimension." 146 * 147 * However, the "less than" is a spec bug because they are declared as 148 * unsigned integers. 149 */ 150 if (group_size[i] == 0 || 151 group_size[i] > ctx->Const.MaxComputeVariableGroupSize[i]) { 152 _mesa_error(ctx, GL_INVALID_VALUE, 153 "glDispatchComputeGroupSizeARB(group_size_%c)", 'x' + i); 154 return GL_FALSE; 155 } 156 157 total_invocations *= group_size[i]; 158 } 159 160 /* The ARB_compute_variable_group_size spec says: 161 * 162 * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if 163 * the product of <group_size_x>, <group_size_y>, and <group_size_z> exceeds 164 * the implementation-dependent maximum local work group invocation count 165 * for compute shaders with variable group size 166 * (MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB)." 167 */ 168 if (total_invocations > ctx->Const.MaxComputeVariableGroupInvocations) { 169 _mesa_error(ctx, GL_INVALID_VALUE, 170 "glDispatchComputeGroupSizeARB(product of local_sizes " 171 "exceeds MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB " 172 "(%d > %d))", total_invocations, 173 ctx->Const.MaxComputeVariableGroupInvocations); 174 return GL_FALSE; 175 } 176 177 return GL_TRUE; 178} 179 180static bool 181valid_dispatch_indirect(struct gl_context *ctx, GLintptr indirect) 182{ 183 GLsizei size = 3 * sizeof(GLuint); 184 const uint64_t end = (uint64_t) indirect + size; 185 const char *name = "glDispatchComputeIndirect"; 186 187 if (!check_valid_to_compute(ctx, name)) 188 return GL_FALSE; 189 190 /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: 191 * 192 * "An INVALID_VALUE error is generated if indirect is negative or is not a 193 * multiple of four." 194 */ 195 if (indirect & (sizeof(GLuint) - 1)) { 196 _mesa_error(ctx, GL_INVALID_VALUE, 197 "%s(indirect is not aligned)", name); 198 return GL_FALSE; 199 } 200 201 if (indirect < 0) { 202 _mesa_error(ctx, GL_INVALID_VALUE, 203 "%s(indirect is less than zero)", name); 204 return GL_FALSE; 205 } 206 207 /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders: 208 * 209 * "An INVALID_OPERATION error is generated if no buffer is bound to the 210 * DRAW_INDIRECT_BUFFER binding, or if the command would source data 211 * beyond the end of the buffer object." 212 */ 213 if (!_mesa_is_bufferobj(ctx->DispatchIndirectBuffer)) { 214 _mesa_error(ctx, GL_INVALID_OPERATION, 215 "%s: no buffer bound to DISPATCH_INDIRECT_BUFFER", name); 216 return GL_FALSE; 217 } 218 219 if (_mesa_check_disallowed_mapping(ctx->DispatchIndirectBuffer)) { 220 _mesa_error(ctx, GL_INVALID_OPERATION, 221 "%s(DISPATCH_INDIRECT_BUFFER is mapped)", name); 222 return GL_FALSE; 223 } 224 225 if (ctx->DispatchIndirectBuffer->Size < end) { 226 _mesa_error(ctx, GL_INVALID_OPERATION, 227 "%s(DISPATCH_INDIRECT_BUFFER too small)", name); 228 return GL_FALSE; 229 } 230 231 /* The ARB_compute_variable_group_size spec says: 232 * 233 * "An INVALID_OPERATION error is generated if the active program for the 234 * compute shader stage has a variable work group size." 235 */ 236 struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; 237 if (prog->info.cs.local_size_variable) { 238 _mesa_error(ctx, GL_INVALID_OPERATION, 239 "%s(variable work group size forbidden)", name); 240 return GL_FALSE; 241 } 242 243 return GL_TRUE; 244} 245 246static ALWAYS_INLINE void 247dispatch_compute(GLuint num_groups_x, GLuint num_groups_y, 248 GLuint num_groups_z, bool no_error) 249{ 250 GET_CURRENT_CONTEXT(ctx); 251 const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z }; 252 253 FLUSH_CURRENT(ctx, 0); 254 255 if (MESA_VERBOSE & VERBOSE_API) 256 _mesa_debug(ctx, "glDispatchCompute(%d, %d, %d)\n", 257 num_groups_x, num_groups_y, num_groups_z); 258 259 if (!no_error && !validate_DispatchCompute(ctx, num_groups)) 260 return; 261 262 if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u) 263 return; 264 265 ctx->Driver.DispatchCompute(ctx, num_groups); 266} 267 268void GLAPIENTRY 269_mesa_DispatchCompute_no_error(GLuint num_groups_x, GLuint num_groups_y, 270 GLuint num_groups_z) 271{ 272 dispatch_compute(num_groups_x, num_groups_y, num_groups_z, true); 273} 274 275void GLAPIENTRY 276_mesa_DispatchCompute(GLuint num_groups_x, 277 GLuint num_groups_y, 278 GLuint num_groups_z) 279{ 280 dispatch_compute(num_groups_x, num_groups_y, num_groups_z, false); 281} 282 283static ALWAYS_INLINE void 284dispatch_compute_indirect(GLintptr indirect, bool no_error) 285{ 286 GET_CURRENT_CONTEXT(ctx); 287 288 FLUSH_CURRENT(ctx, 0); 289 290 if (MESA_VERBOSE & VERBOSE_API) 291 _mesa_debug(ctx, "glDispatchComputeIndirect(%ld)\n", (long) indirect); 292 293 if (!no_error && !valid_dispatch_indirect(ctx, indirect)) 294 return; 295 296 ctx->Driver.DispatchComputeIndirect(ctx, indirect); 297} 298 299extern void GLAPIENTRY 300_mesa_DispatchComputeIndirect_no_error(GLintptr indirect) 301{ 302 dispatch_compute_indirect(indirect, true); 303} 304 305extern void GLAPIENTRY 306_mesa_DispatchComputeIndirect(GLintptr indirect) 307{ 308 dispatch_compute_indirect(indirect, false); 309} 310 311static ALWAYS_INLINE void 312dispatch_compute_group_size(GLuint num_groups_x, GLuint num_groups_y, 313 GLuint num_groups_z, GLuint group_size_x, 314 GLuint group_size_y, GLuint group_size_z, 315 bool no_error) 316{ 317 GET_CURRENT_CONTEXT(ctx); 318 const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z }; 319 const GLuint group_size[3] = { group_size_x, group_size_y, group_size_z }; 320 321 FLUSH_CURRENT(ctx, 0); 322 323 if (MESA_VERBOSE & VERBOSE_API) 324 _mesa_debug(ctx, 325 "glDispatchComputeGroupSizeARB(%d, %d, %d, %d, %d, %d)\n", 326 num_groups_x, num_groups_y, num_groups_z, 327 group_size_x, group_size_y, group_size_z); 328 329 if (!no_error && 330 !validate_DispatchComputeGroupSizeARB(ctx, num_groups, group_size)) 331 return; 332 333 if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u) 334 return; 335 336 ctx->Driver.DispatchComputeGroupSize(ctx, num_groups, group_size); 337} 338 339void GLAPIENTRY 340_mesa_DispatchComputeGroupSizeARB_no_error(GLuint num_groups_x, 341 GLuint num_groups_y, 342 GLuint num_groups_z, 343 GLuint group_size_x, 344 GLuint group_size_y, 345 GLuint group_size_z) 346{ 347 dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z, 348 group_size_x, group_size_y, group_size_z, 349 true); 350} 351 352void GLAPIENTRY 353_mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y, 354 GLuint num_groups_z, GLuint group_size_x, 355 GLuint group_size_y, GLuint group_size_z) 356{ 357 dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z, 358 group_size_x, group_size_y, group_size_z, 359 false); 360} 361