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
29 static bool
check_valid_to_compute(struct gl_context * ctx,const char * function)30 check_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
54 static bool
validate_DispatchCompute(struct gl_context * ctx,const GLuint * num_groups)55 validate_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.workgroup_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
101 static bool
validate_DispatchComputeGroupSizeARB(struct gl_context * ctx,const GLuint * num_groups,const GLuint * group_size)102 validate_DispatchComputeGroupSizeARB(struct gl_context *ctx,
103 const GLuint *num_groups,
104 const GLuint *group_size)
105 {
106 if (!check_valid_to_compute(ctx, "glDispatchComputeGroupSizeARB"))
107 return GL_FALSE;
108
109 /* The ARB_compute_variable_group_size spec says:
110 *
111 * "An INVALID_OPERATION error is generated by
112 * DispatchComputeGroupSizeARB if the active program for the compute
113 * shader stage has a fixed work group size."
114 */
115 struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
116 if (!prog->info.workgroup_size_variable) {
117 _mesa_error(ctx, GL_INVALID_OPERATION,
118 "glDispatchComputeGroupSizeARB(fixed work group size "
119 "forbidden)");
120 return GL_FALSE;
121 }
122
123 for (int i = 0; i < 3; i++) {
124 /* The ARB_compute_variable_group_size spec says:
125 *
126 * "An INVALID_VALUE error is generated if any of num_groups_x,
127 * num_groups_y and num_groups_z are greater than or equal to the
128 * maximum work group count for the corresponding dimension."
129 */
130 if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) {
131 _mesa_error(ctx, GL_INVALID_VALUE,
132 "glDispatchComputeGroupSizeARB(num_groups_%c)", 'x' + i);
133 return GL_FALSE;
134 }
135
136 /* The ARB_compute_variable_group_size spec says:
137 *
138 * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
139 * any of <group_size_x>, <group_size_y>, or <group_size_z> is less than
140 * or equal to zero or greater than the maximum local work group size
141 * for compute shaders with variable group size
142 * (MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB) in the corresponding
143 * dimension."
144 *
145 * However, the "less than" is a spec bug because they are declared as
146 * unsigned integers.
147 */
148 if (group_size[i] == 0 ||
149 group_size[i] > ctx->Const.MaxComputeVariableGroupSize[i]) {
150 _mesa_error(ctx, GL_INVALID_VALUE,
151 "glDispatchComputeGroupSizeARB(group_size_%c)", 'x' + i);
152 return GL_FALSE;
153 }
154 }
155
156 /* The ARB_compute_variable_group_size spec says:
157 *
158 * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
159 * the product of <group_size_x>, <group_size_y>, and <group_size_z> exceeds
160 * the implementation-dependent maximum local work group invocation count
161 * for compute shaders with variable group size
162 * (MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB)."
163 */
164 uint64_t total_invocations = group_size[0] * group_size[1];
165 if (total_invocations <= UINT32_MAX) {
166 /* Only bother multiplying the third value if total still fits in
167 * 32-bit, since MaxComputeVariableGroupInvocations is also 32-bit.
168 */
169 total_invocations *= group_size[2];
170 }
171 if (total_invocations > ctx->Const.MaxComputeVariableGroupInvocations) {
172 _mesa_error(ctx, GL_INVALID_VALUE,
173 "glDispatchComputeGroupSizeARB(product of local_sizes "
174 "exceeds MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB "
175 "(%u * %u * %u > %u))",
176 group_size[0], group_size[1], group_size[2],
177 ctx->Const.MaxComputeVariableGroupInvocations);
178 return GL_FALSE;
179 }
180
181 /* The NV_compute_shader_derivatives spec says:
182 *
183 * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
184 * the active program for the compute shader stage has a compute shader
185 * using the "derivative_group_quadsNV" layout qualifier and
186 * <group_size_x> or <group_size_y> is not a multiple of two.
187 *
188 * An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
189 * the active program for the compute shader stage has a compute shader
190 * using the "derivative_group_linearNV" layout qualifier and the product
191 * of <group_size_x>, <group_size_y>, and <group_size_z> is not a multiple
192 * of four."
193 */
194 if (prog->info.cs.derivative_group == DERIVATIVE_GROUP_QUADS &&
195 ((group_size[0] & 1) || (group_size[1] & 1))) {
196 _mesa_error(ctx, GL_INVALID_VALUE,
197 "glDispatchComputeGroupSizeARB(derivative_group_quadsNV "
198 "requires group_size_x (%d) and group_size_y (%d) to be "
199 "divisble by 2)", group_size[0], group_size[1]);
200 return GL_FALSE;
201 }
202
203 if (prog->info.cs.derivative_group == DERIVATIVE_GROUP_LINEAR &&
204 total_invocations & 3) {
205 _mesa_error(ctx, GL_INVALID_VALUE,
206 "glDispatchComputeGroupSizeARB(derivative_group_linearNV "
207 "requires product of group sizes (%"PRIu64") to be divisible "
208 "by 4)", total_invocations);
209 return GL_FALSE;
210 }
211
212 return GL_TRUE;
213 }
214
215 static bool
valid_dispatch_indirect(struct gl_context * ctx,GLintptr indirect)216 valid_dispatch_indirect(struct gl_context *ctx, GLintptr indirect)
217 {
218 GLsizei size = 3 * sizeof(GLuint);
219 const uint64_t end = (uint64_t) indirect + size;
220 const char *name = "glDispatchComputeIndirect";
221
222 if (!check_valid_to_compute(ctx, name))
223 return GL_FALSE;
224
225 /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
226 *
227 * "An INVALID_VALUE error is generated if indirect is negative or is not a
228 * multiple of four."
229 */
230 if (indirect & (sizeof(GLuint) - 1)) {
231 _mesa_error(ctx, GL_INVALID_VALUE,
232 "%s(indirect is not aligned)", name);
233 return GL_FALSE;
234 }
235
236 if (indirect < 0) {
237 _mesa_error(ctx, GL_INVALID_VALUE,
238 "%s(indirect is less than zero)", name);
239 return GL_FALSE;
240 }
241
242 /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
243 *
244 * "An INVALID_OPERATION error is generated if no buffer is bound to the
245 * DRAW_INDIRECT_BUFFER binding, or if the command would source data
246 * beyond the end of the buffer object."
247 */
248 if (!ctx->DispatchIndirectBuffer) {
249 _mesa_error(ctx, GL_INVALID_OPERATION,
250 "%s: no buffer bound to DISPATCH_INDIRECT_BUFFER", name);
251 return GL_FALSE;
252 }
253
254 if (_mesa_check_disallowed_mapping(ctx->DispatchIndirectBuffer)) {
255 _mesa_error(ctx, GL_INVALID_OPERATION,
256 "%s(DISPATCH_INDIRECT_BUFFER is mapped)", name);
257 return GL_FALSE;
258 }
259
260 if (ctx->DispatchIndirectBuffer->Size < end) {
261 _mesa_error(ctx, GL_INVALID_OPERATION,
262 "%s(DISPATCH_INDIRECT_BUFFER too small)", name);
263 return GL_FALSE;
264 }
265
266 /* The ARB_compute_variable_group_size spec says:
267 *
268 * "An INVALID_OPERATION error is generated if the active program for the
269 * compute shader stage has a variable work group size."
270 */
271 struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
272 if (prog->info.workgroup_size_variable) {
273 _mesa_error(ctx, GL_INVALID_OPERATION,
274 "%s(variable work group size forbidden)", name);
275 return GL_FALSE;
276 }
277
278 return GL_TRUE;
279 }
280
281 static ALWAYS_INLINE void
dispatch_compute(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z,bool no_error)282 dispatch_compute(GLuint num_groups_x, GLuint num_groups_y,
283 GLuint num_groups_z, bool no_error)
284 {
285 GET_CURRENT_CONTEXT(ctx);
286 const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z };
287
288 FLUSH_VERTICES(ctx, 0, 0);
289
290 if (MESA_VERBOSE & VERBOSE_API)
291 _mesa_debug(ctx, "glDispatchCompute(%d, %d, %d)\n",
292 num_groups_x, num_groups_y, num_groups_z);
293
294 if (!no_error && !validate_DispatchCompute(ctx, num_groups))
295 return;
296
297 if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u)
298 return;
299
300 ctx->Driver.DispatchCompute(ctx, num_groups);
301
302 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
303 _mesa_flush(ctx);
304 }
305
306 void GLAPIENTRY
_mesa_DispatchCompute_no_error(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z)307 _mesa_DispatchCompute_no_error(GLuint num_groups_x, GLuint num_groups_y,
308 GLuint num_groups_z)
309 {
310 dispatch_compute(num_groups_x, num_groups_y, num_groups_z, true);
311 }
312
313 void GLAPIENTRY
_mesa_DispatchCompute(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z)314 _mesa_DispatchCompute(GLuint num_groups_x,
315 GLuint num_groups_y,
316 GLuint num_groups_z)
317 {
318 dispatch_compute(num_groups_x, num_groups_y, num_groups_z, false);
319 }
320
321 static ALWAYS_INLINE void
dispatch_compute_indirect(GLintptr indirect,bool no_error)322 dispatch_compute_indirect(GLintptr indirect, bool no_error)
323 {
324 GET_CURRENT_CONTEXT(ctx);
325
326 FLUSH_VERTICES(ctx, 0, 0);
327
328 if (MESA_VERBOSE & VERBOSE_API)
329 _mesa_debug(ctx, "glDispatchComputeIndirect(%ld)\n", (long) indirect);
330
331 if (!no_error && !valid_dispatch_indirect(ctx, indirect))
332 return;
333
334 ctx->Driver.DispatchComputeIndirect(ctx, indirect);
335
336 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
337 _mesa_flush(ctx);
338 }
339
340 extern void GLAPIENTRY
_mesa_DispatchComputeIndirect_no_error(GLintptr indirect)341 _mesa_DispatchComputeIndirect_no_error(GLintptr indirect)
342 {
343 dispatch_compute_indirect(indirect, true);
344 }
345
346 extern void GLAPIENTRY
_mesa_DispatchComputeIndirect(GLintptr indirect)347 _mesa_DispatchComputeIndirect(GLintptr indirect)
348 {
349 dispatch_compute_indirect(indirect, false);
350 }
351
352 static ALWAYS_INLINE void
dispatch_compute_group_size(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z,GLuint group_size_x,GLuint group_size_y,GLuint group_size_z,bool no_error)353 dispatch_compute_group_size(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 bool no_error)
357 {
358 GET_CURRENT_CONTEXT(ctx);
359 const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z };
360 const GLuint group_size[3] = { group_size_x, group_size_y, group_size_z };
361
362 FLUSH_VERTICES(ctx, 0, 0);
363
364 if (MESA_VERBOSE & VERBOSE_API)
365 _mesa_debug(ctx,
366 "glDispatchComputeGroupSizeARB(%d, %d, %d, %d, %d, %d)\n",
367 num_groups_x, num_groups_y, num_groups_z,
368 group_size_x, group_size_y, group_size_z);
369
370 if (!no_error &&
371 !validate_DispatchComputeGroupSizeARB(ctx, num_groups, group_size))
372 return;
373
374 if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u)
375 return;
376
377 ctx->Driver.DispatchComputeGroupSize(ctx, num_groups, group_size);
378
379 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
380 _mesa_flush(ctx);
381 }
382
383 void GLAPIENTRY
_mesa_DispatchComputeGroupSizeARB_no_error(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z,GLuint group_size_x,GLuint group_size_y,GLuint group_size_z)384 _mesa_DispatchComputeGroupSizeARB_no_error(GLuint num_groups_x,
385 GLuint num_groups_y,
386 GLuint num_groups_z,
387 GLuint group_size_x,
388 GLuint group_size_y,
389 GLuint group_size_z)
390 {
391 dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z,
392 group_size_x, group_size_y, group_size_z,
393 true);
394 }
395
396 void GLAPIENTRY
_mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z,GLuint group_size_x,GLuint group_size_y,GLuint group_size_z)397 _mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y,
398 GLuint num_groups_z, GLuint group_size_x,
399 GLuint group_size_y, GLuint group_size_z)
400 {
401 dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z,
402 group_size_x, group_size_y, group_size_z,
403 false);
404 }
405