• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.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 
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.cs.local_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.cs.local_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);
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 
303 void GLAPIENTRY
_mesa_DispatchCompute_no_error(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z)304 _mesa_DispatchCompute_no_error(GLuint num_groups_x, GLuint num_groups_y,
305                                GLuint num_groups_z)
306 {
307    dispatch_compute(num_groups_x, num_groups_y, num_groups_z, true);
308 }
309 
310 void GLAPIENTRY
_mesa_DispatchCompute(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z)311 _mesa_DispatchCompute(GLuint num_groups_x,
312                       GLuint num_groups_y,
313                       GLuint num_groups_z)
314 {
315    dispatch_compute(num_groups_x, num_groups_y, num_groups_z, false);
316 }
317 
318 static ALWAYS_INLINE void
dispatch_compute_indirect(GLintptr indirect,bool no_error)319 dispatch_compute_indirect(GLintptr indirect, bool no_error)
320 {
321    GET_CURRENT_CONTEXT(ctx);
322 
323    FLUSH_VERTICES(ctx, 0);
324 
325    if (MESA_VERBOSE & VERBOSE_API)
326       _mesa_debug(ctx, "glDispatchComputeIndirect(%ld)\n", (long) indirect);
327 
328    if (!no_error && !valid_dispatch_indirect(ctx, indirect))
329       return;
330 
331    ctx->Driver.DispatchComputeIndirect(ctx, indirect);
332 }
333 
334 extern void GLAPIENTRY
_mesa_DispatchComputeIndirect_no_error(GLintptr indirect)335 _mesa_DispatchComputeIndirect_no_error(GLintptr indirect)
336 {
337    dispatch_compute_indirect(indirect, true);
338 }
339 
340 extern void GLAPIENTRY
_mesa_DispatchComputeIndirect(GLintptr indirect)341 _mesa_DispatchComputeIndirect(GLintptr indirect)
342 {
343    dispatch_compute_indirect(indirect, false);
344 }
345 
346 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)347 dispatch_compute_group_size(GLuint num_groups_x, GLuint num_groups_y,
348                             GLuint num_groups_z, GLuint group_size_x,
349                             GLuint group_size_y, GLuint group_size_z,
350                             bool no_error)
351 {
352    GET_CURRENT_CONTEXT(ctx);
353    const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z };
354    const GLuint group_size[3] = { group_size_x, group_size_y, group_size_z };
355 
356    FLUSH_VERTICES(ctx, 0);
357 
358    if (MESA_VERBOSE & VERBOSE_API)
359       _mesa_debug(ctx,
360                   "glDispatchComputeGroupSizeARB(%d, %d, %d, %d, %d, %d)\n",
361                   num_groups_x, num_groups_y, num_groups_z,
362                   group_size_x, group_size_y, group_size_z);
363 
364    if (!no_error &&
365        !validate_DispatchComputeGroupSizeARB(ctx, num_groups, group_size))
366       return;
367 
368    if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u)
369        return;
370 
371    ctx->Driver.DispatchComputeGroupSize(ctx, num_groups, group_size);
372 }
373 
374 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)375 _mesa_DispatchComputeGroupSizeARB_no_error(GLuint num_groups_x,
376                                            GLuint num_groups_y,
377                                            GLuint num_groups_z,
378                                            GLuint group_size_x,
379                                            GLuint group_size_y,
380                                            GLuint group_size_z)
381 {
382    dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z,
383                                group_size_x, group_size_y, group_size_z,
384                                true);
385 }
386 
387 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)388 _mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y,
389                                   GLuint num_groups_z, GLuint group_size_x,
390                                   GLuint group_size_y, GLuint group_size_z)
391 {
392    dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z,
393                                group_size_x, group_size_y, group_size_z,
394                                false);
395 }
396