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 
36 static bool
check_valid_to_compute(struct gl_context *ctx, const char *function)37 check_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 
61 static bool
validate_DispatchCompute(struct gl_context *ctx, struct pipe_grid_info *info)62 validate_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 
108 static bool
validate_DispatchComputeGroupSizeARB(struct gl_context *ctx, struct pipe_grid_info *info)109 validate_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 
221 static bool
valid_dispatch_indirect(struct gl_context *ctx, GLintptr indirect)222 valid_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 
287 static void
prepare_compute(struct gl_context *ctx)288 prepare_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 
305 static ALWAYS_INLINE void
dispatch_compute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, bool no_error)306 dispatch_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 
341 void GLAPIENTRY
_mesa_DispatchCompute_no_error(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)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 
348 void GLAPIENTRY
_mesa_DispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)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 
356 static ALWAYS_INLINE void
dispatch_compute_indirect(GLintptr indirect, bool no_error)357 dispatch_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 
386 extern void GLAPIENTRY
_mesa_DispatchComputeIndirect_no_error(GLintptr indirect)387 _mesa_DispatchComputeIndirect_no_error(GLintptr indirect)
388 {
389    dispatch_compute_indirect(indirect, true);
390 }
391 
392 extern void GLAPIENTRY
_mesa_DispatchComputeIndirect(GLintptr indirect)393 _mesa_DispatchComputeIndirect(GLintptr indirect)
394 {
395    dispatch_compute_indirect(indirect, false);
396 }
397 
398 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)399 dispatch_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 
436 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)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 
449 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)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