xref: /third_party/mesa3d/src/mesa/main/compute.c (revision bf215546)
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 "context.h"
27#include "state.h"
28#include "api_exec_decl.h"
29
30#include "pipe/p_state.h"
31
32#include "state_tracker/st_context.h"
33#include "state_tracker/st_cb_bitmap.h"
34#include "state_tracker/st_util.h"
35
36static bool
37check_valid_to_compute(struct gl_context *ctx, const char *function)
38{
39   if (!_mesa_has_compute_shaders(ctx)) {
40      _mesa_error(ctx, GL_INVALID_OPERATION,
41                  "unsupported function (%s) called",
42                  function);
43      return false;
44   }
45
46   /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
47    *
48    * "An INVALID_OPERATION error is generated if there is no active program
49    *  for the compute shader stage."
50    */
51   if (ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE] == NULL) {
52      _mesa_error(ctx, GL_INVALID_OPERATION,
53                  "%s(no active compute shader)",
54                  function);
55      return false;
56   }
57
58   return true;
59}
60
61static bool
62validate_DispatchCompute(struct gl_context *ctx, struct pipe_grid_info *info)
63{
64   if (!check_valid_to_compute(ctx, "glDispatchCompute"))
65      return GL_FALSE;
66
67   for (int i = 0; i < 3; i++) {
68      /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
69       *
70       * "An INVALID_VALUE error is generated if any of num_groups_x,
71       *  num_groups_y and num_groups_z are greater than or equal to the
72       *  maximum work group count for the corresponding dimension."
73       *
74       * However, the "or equal to" portions appears to be a specification
75       * bug. In all other areas, the specification appears to indicate that
76       * the number of workgroups can match the MAX_COMPUTE_WORK_GROUP_COUNT
77       * value. For example, under DispatchComputeIndirect:
78       *
79       * "If any of num_groups_x, num_groups_y or num_groups_z is greater than
80       *  the value of MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding
81       *  dimension then the results are undefined."
82       *
83       * Additionally, the OpenGLES 3.1 specification does not contain "or
84       * equal to" as an error condition.
85       */
86      if (info->grid[i] > ctx->Const.MaxComputeWorkGroupCount[i]) {
87         _mesa_error(ctx, GL_INVALID_VALUE,
88                     "glDispatchCompute(num_groups_%c)", 'x' + i);
89         return GL_FALSE;
90      }
91   }
92
93   /* The ARB_compute_variable_group_size spec says:
94    *
95    * "An INVALID_OPERATION error is generated by DispatchCompute if the active
96    *  program for the compute shader stage has a variable work group size."
97    */
98   struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
99   if (prog->info.workgroup_size_variable) {
100      _mesa_error(ctx, GL_INVALID_OPERATION,
101                  "glDispatchCompute(variable work group size forbidden)");
102      return GL_FALSE;
103   }
104
105   return GL_TRUE;
106}
107
108static bool
109validate_DispatchComputeGroupSizeARB(struct gl_context *ctx,
110                                     struct pipe_grid_info *info)
111{
112   if (!check_valid_to_compute(ctx, "glDispatchComputeGroupSizeARB"))
113      return GL_FALSE;
114
115   /* The ARB_compute_variable_group_size spec says:
116    *
117    * "An INVALID_OPERATION error is generated by
118    *  DispatchComputeGroupSizeARB if the active program for the compute
119    *  shader stage has a fixed work group size."
120    */
121   struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
122   if (!prog->info.workgroup_size_variable) {
123      _mesa_error(ctx, GL_INVALID_OPERATION,
124                  "glDispatchComputeGroupSizeARB(fixed work group size "
125                  "forbidden)");
126      return GL_FALSE;
127   }
128
129   for (int i = 0; i < 3; i++) {
130      /* The ARB_compute_variable_group_size spec says:
131       *
132       * "An INVALID_VALUE error is generated if any of num_groups_x,
133       *  num_groups_y and num_groups_z are greater than or equal to the
134       *  maximum work group count for the corresponding dimension."
135       */
136      if (info->grid[i] > ctx->Const.MaxComputeWorkGroupCount[i]) {
137         _mesa_error(ctx, GL_INVALID_VALUE,
138                     "glDispatchComputeGroupSizeARB(num_groups_%c)", 'x' + i);
139         return GL_FALSE;
140      }
141
142      /* The ARB_compute_variable_group_size spec says:
143       *
144       * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
145       *  any of <group_size_x>, <group_size_y>, or <group_size_z> is less than
146       *  or equal to zero or greater than the maximum local work group size
147       *  for compute shaders with variable group size
148       *  (MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB) in the corresponding
149       *  dimension."
150       *
151       * However, the "less than" is a spec bug because they are declared as
152       * unsigned integers.
153       */
154      if (info->block[i] == 0 ||
155          info->block[i] > ctx->Const.MaxComputeVariableGroupSize[i]) {
156         _mesa_error(ctx, GL_INVALID_VALUE,
157                     "glDispatchComputeGroupSizeARB(group_size_%c)", 'x' + i);
158         return GL_FALSE;
159      }
160   }
161
162   /* The ARB_compute_variable_group_size spec says:
163    *
164    * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
165    *  the product of <group_size_x>, <group_size_y>, and <group_size_z> exceeds
166    *  the implementation-dependent maximum local work group invocation count
167    *  for compute shaders with variable group size
168    *  (MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB)."
169    */
170   uint64_t total_invocations = info->block[0] * info->block[1];
171   if (total_invocations <= UINT32_MAX) {
172      /* Only bother multiplying the third value if total still fits in
173       * 32-bit, since MaxComputeVariableGroupInvocations is also 32-bit.
174       */
175      total_invocations *= info->block[2];
176   }
177   if (total_invocations > ctx->Const.MaxComputeVariableGroupInvocations) {
178      _mesa_error(ctx, GL_INVALID_VALUE,
179                  "glDispatchComputeGroupSizeARB(product of local_sizes "
180                  "exceeds MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB "
181                  "(%u * %u * %u > %u))",
182                  info->block[0], info->block[1], info->block[2],
183                  ctx->Const.MaxComputeVariableGroupInvocations);
184      return GL_FALSE;
185   }
186
187   /* The NV_compute_shader_derivatives spec says:
188    *
189    * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
190    *  the active program for the compute shader stage has a compute shader
191    *  using the "derivative_group_quadsNV" layout qualifier and
192    *  <group_size_x> or <group_size_y> is not a multiple of two.
193    *
194    *  An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
195    *  the active program for the compute shader stage has a compute shader
196    *  using the "derivative_group_linearNV" layout qualifier and the product
197    *  of <group_size_x>, <group_size_y>, and <group_size_z> is not a multiple
198    *  of four."
199    */
200   if (prog->info.cs.derivative_group == DERIVATIVE_GROUP_QUADS &&
201       ((info->block[0] & 1) || (info->block[1] & 1))) {
202      _mesa_error(ctx, GL_INVALID_VALUE,
203                  "glDispatchComputeGroupSizeARB(derivative_group_quadsNV "
204                  "requires group_size_x (%d) and group_size_y (%d) to be "
205                  "divisble by 2)", info->block[0], info->block[1]);
206      return GL_FALSE;
207   }
208
209   if (prog->info.cs.derivative_group == DERIVATIVE_GROUP_LINEAR &&
210       total_invocations & 3) {
211      _mesa_error(ctx, GL_INVALID_VALUE,
212                  "glDispatchComputeGroupSizeARB(derivative_group_linearNV "
213                  "requires product of group sizes (%"PRIu64") to be divisible "
214                  "by 4)", total_invocations);
215      return GL_FALSE;
216   }
217
218   return GL_TRUE;
219}
220
221static bool
222valid_dispatch_indirect(struct gl_context *ctx,  GLintptr indirect)
223{
224   GLsizei size = 3 * sizeof(GLuint);
225   const uint64_t end = (uint64_t) indirect + size;
226   const char *name = "glDispatchComputeIndirect";
227
228   if (!check_valid_to_compute(ctx, name))
229      return GL_FALSE;
230
231   /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
232    *
233    * "An INVALID_VALUE error is generated if indirect is negative or is not a
234    *  multiple of four."
235    */
236   if (indirect & (sizeof(GLuint) - 1)) {
237      _mesa_error(ctx, GL_INVALID_VALUE,
238                  "%s(indirect is not aligned)", name);
239      return GL_FALSE;
240   }
241
242   if (indirect < 0) {
243      _mesa_error(ctx, GL_INVALID_VALUE,
244                  "%s(indirect is less than zero)", name);
245      return GL_FALSE;
246   }
247
248   /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
249    *
250    * "An INVALID_OPERATION error is generated if no buffer is bound to the
251    *  DRAW_INDIRECT_BUFFER binding, or if the command would source data
252    *  beyond the end of the buffer object."
253    */
254   if (!ctx->DispatchIndirectBuffer) {
255      _mesa_error(ctx, GL_INVALID_OPERATION,
256                  "%s: no buffer bound to DISPATCH_INDIRECT_BUFFER", name);
257      return GL_FALSE;
258   }
259
260   if (_mesa_check_disallowed_mapping(ctx->DispatchIndirectBuffer)) {
261      _mesa_error(ctx, GL_INVALID_OPERATION,
262                  "%s(DISPATCH_INDIRECT_BUFFER is mapped)", name);
263      return GL_FALSE;
264   }
265
266   if (ctx->DispatchIndirectBuffer->Size < end) {
267      _mesa_error(ctx, GL_INVALID_OPERATION,
268                  "%s(DISPATCH_INDIRECT_BUFFER too small)", name);
269      return GL_FALSE;
270   }
271
272   /* The ARB_compute_variable_group_size spec says:
273    *
274    * "An INVALID_OPERATION error is generated if the active program for the
275    *  compute shader stage has a variable work group size."
276    */
277   struct gl_program *prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
278   if (prog->info.workgroup_size_variable) {
279      _mesa_error(ctx, GL_INVALID_OPERATION,
280                  "%s(variable work group size forbidden)", name);
281      return GL_FALSE;
282   }
283
284   return GL_TRUE;
285}
286
287static void
288prepare_compute(struct gl_context *ctx)
289{
290   struct st_context *st = st_context(ctx);
291
292   st_flush_bitmap_cache(st);
293   st_invalidate_readpix_cache(st);
294
295   if (ctx->NewState)
296      _mesa_update_state(ctx);
297
298   if ((st->dirty | ctx->NewDriverState) & st->active_states &
299       ST_PIPELINE_COMPUTE_STATE_MASK ||
300       st->compute_shader_may_be_dirty)
301      st_validate_state(st, ST_PIPELINE_COMPUTE);
302
303}
304
305static ALWAYS_INLINE void
306dispatch_compute(GLuint num_groups_x, GLuint num_groups_y,
307                 GLuint num_groups_z, bool no_error)
308{
309   GET_CURRENT_CONTEXT(ctx);
310   struct pipe_grid_info info = { 0 };
311
312   FLUSH_VERTICES(ctx, 0, 0);
313
314   if (MESA_VERBOSE & VERBOSE_API)
315      _mesa_debug(ctx, "glDispatchCompute(%d, %d, %d)\n",
316                  num_groups_x, num_groups_y, num_groups_z);
317
318   info.grid[0] = num_groups_x;
319   info.grid[1] = num_groups_y;
320   info.grid[2] = num_groups_z;
321
322   if (!no_error && !validate_DispatchCompute(ctx, &info))
323      return;
324
325   if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u)
326       return;
327
328   struct gl_program *prog =
329      ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
330   info.block[0] = prog->info.workgroup_size[0];
331   info.block[1] = prog->info.workgroup_size[1];
332   info.block[2] = prog->info.workgroup_size[2];
333
334   prepare_compute(ctx);
335   ctx->pipe->launch_grid(ctx->pipe, &info);
336
337   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
338      _mesa_flush(ctx);
339}
340
341void GLAPIENTRY
342_mesa_DispatchCompute_no_error(GLuint num_groups_x, GLuint num_groups_y,
343                               GLuint num_groups_z)
344{
345   dispatch_compute(num_groups_x, num_groups_y, num_groups_z, true);
346}
347
348void GLAPIENTRY
349_mesa_DispatchCompute(GLuint num_groups_x,
350                      GLuint num_groups_y,
351                      GLuint num_groups_z)
352{
353   dispatch_compute(num_groups_x, num_groups_y, num_groups_z, false);
354}
355
356static ALWAYS_INLINE void
357dispatch_compute_indirect(GLintptr indirect, bool no_error)
358{
359   GET_CURRENT_CONTEXT(ctx);
360
361   FLUSH_VERTICES(ctx, 0, 0);
362
363   if (MESA_VERBOSE & VERBOSE_API)
364      _mesa_debug(ctx, "glDispatchComputeIndirect(%ld)\n", (long) indirect);
365
366   if (!no_error && !valid_dispatch_indirect(ctx, indirect))
367      return;
368
369   struct pipe_grid_info info = { 0 };
370   info.indirect_offset = indirect;
371   info.indirect = ctx->DispatchIndirectBuffer->buffer;
372
373   struct gl_program *prog =
374      ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
375   info.block[0] = prog->info.workgroup_size[0];
376   info.block[1] = prog->info.workgroup_size[1];
377   info.block[2] = prog->info.workgroup_size[2];
378
379   prepare_compute(ctx);
380   ctx->pipe->launch_grid(ctx->pipe, &info);
381
382   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
383      _mesa_flush(ctx);
384}
385
386extern void GLAPIENTRY
387_mesa_DispatchComputeIndirect_no_error(GLintptr indirect)
388{
389   dispatch_compute_indirect(indirect, true);
390}
391
392extern void GLAPIENTRY
393_mesa_DispatchComputeIndirect(GLintptr indirect)
394{
395   dispatch_compute_indirect(indirect, false);
396}
397
398static ALWAYS_INLINE void
399dispatch_compute_group_size(GLuint num_groups_x, GLuint num_groups_y,
400                            GLuint num_groups_z, GLuint group_size_x,
401                            GLuint group_size_y, GLuint group_size_z,
402                            bool no_error)
403{
404   GET_CURRENT_CONTEXT(ctx);
405   FLUSH_VERTICES(ctx, 0, 0);
406
407   if (MESA_VERBOSE & VERBOSE_API)
408      _mesa_debug(ctx,
409                  "glDispatchComputeGroupSizeARB(%d, %d, %d, %d, %d, %d)\n",
410                  num_groups_x, num_groups_y, num_groups_z,
411                  group_size_x, group_size_y, group_size_z);
412
413   struct pipe_grid_info info = { 0 };
414   info.grid[0] = num_groups_x;
415   info.grid[1] = num_groups_y;
416   info.grid[2] = num_groups_z;
417
418   info.block[0] = group_size_x;
419   info.block[1] = group_size_y;
420   info.block[2] = group_size_z;
421
422   if (!no_error &&
423       !validate_DispatchComputeGroupSizeARB(ctx, &info))
424      return;
425
426   if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u)
427       return;
428
429   prepare_compute(ctx);
430   ctx->pipe->launch_grid(ctx->pipe, &info);
431
432   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
433      _mesa_flush(ctx);
434}
435
436void GLAPIENTRY
437_mesa_DispatchComputeGroupSizeARB_no_error(GLuint num_groups_x,
438                                           GLuint num_groups_y,
439                                           GLuint num_groups_z,
440                                           GLuint group_size_x,
441                                           GLuint group_size_y,
442                                           GLuint group_size_z)
443{
444   dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z,
445                               group_size_x, group_size_y, group_size_z,
446                               true);
447}
448
449void GLAPIENTRY
450_mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y,
451                                  GLuint num_groups_z, GLuint group_size_x,
452                                  GLuint group_size_y, GLuint group_size_z)
453{
454   dispatch_compute_group_size(num_groups_x, num_groups_y, num_groups_z,
455                               group_size_x, group_size_y, group_size_z,
456                               false);
457}
458