mesa: add ARB_vertex_attrib_64bit VertexArrayVertexAttribLOffsetEXT
[mesa.git] / src / mesa / main / compute.c
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
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
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
102 validate_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
180 static bool
181 valid_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
246 static ALWAYS_INLINE void
247 dispatch_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
268 void 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
275 void 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
283 static ALWAYS_INLINE void
284 dispatch_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
299 extern void GLAPIENTRY
300 _mesa_DispatchComputeIndirect_no_error(GLintptr indirect)
301 {
302 dispatch_compute_indirect(indirect, true);
303 }
304
305 extern void GLAPIENTRY
306 _mesa_DispatchComputeIndirect(GLintptr indirect)
307 {
308 dispatch_compute_indirect(indirect, false);
309 }
310
311 static ALWAYS_INLINE void
312 dispatch_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
339 void 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
352 void 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 }