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