mesa: Check for vertex program the same way in desktop GL and ES
[mesa.git] / src / mesa / main / api_validate.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <stdbool.h>
26 #include "glheader.h"
27 #include "api_validate.h"
28 #include "bufferobj.h"
29 #include "context.h"
30 #include "imports.h"
31 #include "mtypes.h"
32 #include "enums.h"
33 #include "vbo/vbo.h"
34 #include "transformfeedback.h"
35 #include <stdbool.h>
36
37
38 /**
39 * Check if OK to draw arrays/elements.
40 */
41 static bool
42 check_valid_to_render(struct gl_context *ctx, const char *function)
43 {
44 if (!_mesa_valid_to_render(ctx, function)) {
45 return false;
46 }
47
48 switch (ctx->API) {
49 case API_OPENGLES2:
50 /* For ES2, we can draw if we have a vertex program/shader). */
51 return ctx->VertexProgram._Current != NULL;
52
53 case API_OPENGLES:
54 /* For OpenGL ES, only draw if we have vertex positions
55 */
56 if (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
57 return false;
58 break;
59
60 case API_OPENGL_CORE:
61 /* Section 10.4 (Drawing Commands Using Vertex Arrays) of the OpenGL 4.5
62 * Core Profile spec says:
63 *
64 * "An INVALID_OPERATION error is generated if no vertex array
65 * object is bound (see section 10.3.1)."
66 */
67 if (ctx->Array.VAO == ctx->Array.DefaultVAO) {
68 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no VAO bound)", function);
69 return false;
70 }
71
72 /* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec
73 * says:
74 *
75 * "If there is no active program for the vertex or fragment shader
76 * stages, the results of vertex and/or fragment processing will be
77 * undefined. However, this is not an error."
78 *
79 * The fragment shader is not tested here because other state (e.g.,
80 * GL_RASTERIZER_DISCARD) affects whether or not we actually care.
81 */
82 return ctx->VertexProgram._Current != NULL;
83
84 case API_OPENGL_COMPAT:
85 if (ctx->VertexProgram._Current != NULL) {
86 /* Draw regardless of whether or not we have any vertex arrays.
87 * (Ex: could draw a point using a constant vertex pos)
88 */
89 return true;
90 } else {
91 /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
92 * array [0]).
93 */
94 return (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
95 ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
96 }
97 break;
98
99 default:
100 unreachable("Invalid API value in check_valid_to_render()");
101 }
102
103 return true;
104 }
105
106
107 /**
108 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
109 * etc? The set of legal values depends on whether geometry shaders/programs
110 * are supported.
111 * Note: This may be called during display list compilation.
112 */
113 bool
114 _mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode)
115 {
116 switch (mode) {
117 case GL_POINTS:
118 case GL_LINES:
119 case GL_LINE_LOOP:
120 case GL_LINE_STRIP:
121 case GL_TRIANGLES:
122 case GL_TRIANGLE_STRIP:
123 case GL_TRIANGLE_FAN:
124 return true;
125 case GL_QUADS:
126 case GL_QUAD_STRIP:
127 case GL_POLYGON:
128 return (ctx->API == API_OPENGL_COMPAT);
129 case GL_LINES_ADJACENCY:
130 case GL_LINE_STRIP_ADJACENCY:
131 case GL_TRIANGLES_ADJACENCY:
132 case GL_TRIANGLE_STRIP_ADJACENCY:
133 return _mesa_has_geometry_shaders(ctx);
134 default:
135 return false;
136 }
137 }
138
139
140 /**
141 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
142 * etc? Also, do additional checking related to transformation feedback.
143 * Note: this function cannot be called during glNewList(GL_COMPILE) because
144 * this code depends on current transform feedback state.
145 */
146 GLboolean
147 _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
148 {
149 bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode);
150
151 if (!valid_enum) {
152 _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
153 return GL_FALSE;
154 }
155
156 /* From the ARB_geometry_shader4 spec:
157 *
158 * The error INVALID_OPERATION is generated if Begin, or any command that
159 * implicitly calls Begin, is called when a geometry shader is active and:
160 *
161 * * the input primitive type of the current geometry shader is
162 * POINTS and <mode> is not POINTS,
163 *
164 * * the input primitive type of the current geometry shader is
165 * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP,
166 *
167 * * the input primitive type of the current geometry shader is
168 * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or
169 * TRIANGLE_FAN,
170 *
171 * * the input primitive type of the current geometry shader is
172 * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or
173 * LINE_STRIP_ADJACENCY_ARB, or
174 *
175 * * the input primitive type of the current geometry shader is
176 * TRIANGLES_ADJACENCY_ARB and <mode> is not
177 * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
178 *
179 */
180 if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
181 const GLenum geom_mode =
182 ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
183 switch (mode) {
184 case GL_POINTS:
185 valid_enum = (geom_mode == GL_POINTS);
186 break;
187 case GL_LINES:
188 case GL_LINE_LOOP:
189 case GL_LINE_STRIP:
190 valid_enum = (geom_mode == GL_LINES);
191 break;
192 case GL_TRIANGLES:
193 case GL_TRIANGLE_STRIP:
194 case GL_TRIANGLE_FAN:
195 valid_enum = (geom_mode == GL_TRIANGLES);
196 break;
197 case GL_QUADS:
198 case GL_QUAD_STRIP:
199 case GL_POLYGON:
200 valid_enum = false;
201 break;
202 case GL_LINES_ADJACENCY:
203 case GL_LINE_STRIP_ADJACENCY:
204 valid_enum = (geom_mode == GL_LINES_ADJACENCY);
205 break;
206 case GL_TRIANGLES_ADJACENCY:
207 case GL_TRIANGLE_STRIP_ADJACENCY:
208 valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY);
209 break;
210 default:
211 valid_enum = false;
212 break;
213 }
214 if (!valid_enum) {
215 _mesa_error(ctx, GL_INVALID_OPERATION,
216 "%s(mode=%s vs geometry shader input %s)",
217 name,
218 _mesa_lookup_prim_by_nr(mode),
219 _mesa_lookup_prim_by_nr(geom_mode));
220 return GL_FALSE;
221 }
222 }
223
224 /* From the GL_EXT_transform_feedback spec:
225 *
226 * "The error INVALID_OPERATION is generated if Begin, or any command
227 * that performs an explicit Begin, is called when:
228 *
229 * * a geometry shader is not active and <mode> does not match the
230 * allowed begin modes for the current transform feedback state as
231 * given by table X.1.
232 *
233 * * a geometry shader is active and the output primitive type of the
234 * geometry shader does not match the allowed begin modes for the
235 * current transform feedback state as given by table X.1.
236 *
237 */
238 if (_mesa_is_xfb_active_and_unpaused(ctx)) {
239 GLboolean pass = GL_TRUE;
240
241 if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
242 switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
243 case GL_POINTS:
244 pass = ctx->TransformFeedback.Mode == GL_POINTS;
245 break;
246 case GL_LINE_STRIP:
247 pass = ctx->TransformFeedback.Mode == GL_LINES;
248 break;
249 case GL_TRIANGLE_STRIP:
250 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
251 break;
252 default:
253 pass = GL_FALSE;
254 }
255 }
256 else {
257 switch (mode) {
258 case GL_POINTS:
259 pass = ctx->TransformFeedback.Mode == GL_POINTS;
260 break;
261 case GL_LINES:
262 case GL_LINE_STRIP:
263 case GL_LINE_LOOP:
264 pass = ctx->TransformFeedback.Mode == GL_LINES;
265 break;
266 default:
267 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
268 break;
269 }
270 }
271 if (!pass) {
272 _mesa_error(ctx, GL_INVALID_OPERATION,
273 "%s(mode=%s vs transform feedback %s)",
274 name,
275 _mesa_lookup_prim_by_nr(mode),
276 _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
277 return GL_FALSE;
278 }
279 }
280
281 return GL_TRUE;
282 }
283
284 /**
285 * Verify that the element type is valid.
286 *
287 * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
288 */
289 static bool
290 valid_elements_type(struct gl_context *ctx, GLenum type, const char *name)
291 {
292 switch (type) {
293 case GL_UNSIGNED_BYTE:
294 case GL_UNSIGNED_SHORT:
295 case GL_UNSIGNED_INT:
296 return true;
297
298 default:
299 _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name,
300 _mesa_lookup_enum_by_nr(type));
301 return false;
302 }
303 }
304
305 static bool
306 validate_DrawElements_common(struct gl_context *ctx,
307 GLenum mode, GLsizei count, GLenum type,
308 const GLvoid *indices,
309 const char *caller)
310 {
311 /* From the GLES3 specification, section 2.14.2 (Transform Feedback
312 * Primitive Capture):
313 *
314 * The error INVALID_OPERATION is also generated by DrawElements,
315 * DrawElementsInstanced, and DrawRangeElements while transform feedback
316 * is active and not paused, regardless of mode.
317 */
318 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
319 _mesa_error(ctx, GL_INVALID_OPERATION,
320 "%s(transform feedback active)", caller);
321 return false;
322 }
323
324 if (count < 0) {
325 _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller);
326 return false;
327 }
328
329 if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
330 return false;
331 }
332
333 if (!valid_elements_type(ctx, type, caller))
334 return false;
335
336 if (!check_valid_to_render(ctx, caller))
337 return false;
338
339 /* Not using a VBO for indices, so avoid NULL pointer derefs later.
340 */
341 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
342 return false;
343
344 if (count == 0)
345 return false;
346
347 return true;
348 }
349
350 /**
351 * Error checking for glDrawElements(). Includes parameter checking
352 * and VBO bounds checking.
353 * \return GL_TRUE if OK to render, GL_FALSE if error found
354 */
355 GLboolean
356 _mesa_validate_DrawElements(struct gl_context *ctx,
357 GLenum mode, GLsizei count, GLenum type,
358 const GLvoid *indices)
359 {
360 FLUSH_CURRENT(ctx, 0);
361
362 return validate_DrawElements_common(ctx, mode, count, type, indices,
363 "glDrawElements");
364 }
365
366
367 /**
368 * Error checking for glMultiDrawElements(). Includes parameter checking
369 * and VBO bounds checking.
370 * \return GL_TRUE if OK to render, GL_FALSE if error found
371 */
372 GLboolean
373 _mesa_validate_MultiDrawElements(struct gl_context *ctx,
374 GLenum mode, const GLsizei *count,
375 GLenum type, const GLvoid * const *indices,
376 GLuint primcount)
377 {
378 unsigned i;
379
380 FLUSH_CURRENT(ctx, 0);
381
382 for (i = 0; i < primcount; i++) {
383 if (count[i] < 0) {
384 _mesa_error(ctx, GL_INVALID_VALUE,
385 "glMultiDrawElements(count)" );
386 return GL_FALSE;
387 }
388 }
389
390 if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) {
391 return GL_FALSE;
392 }
393
394 if (!valid_elements_type(ctx, type, "glMultiDrawElements"))
395 return GL_FALSE;
396
397 if (!check_valid_to_render(ctx, "glMultiDrawElements"))
398 return GL_FALSE;
399
400 /* Not using a VBO for indices, so avoid NULL pointer derefs later.
401 */
402 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
403 for (i = 0; i < primcount; i++) {
404 if (!indices[i])
405 return GL_FALSE;
406 }
407 }
408
409 return GL_TRUE;
410 }
411
412
413 /**
414 * Error checking for glDrawRangeElements(). Includes parameter checking
415 * and VBO bounds checking.
416 * \return GL_TRUE if OK to render, GL_FALSE if error found
417 */
418 GLboolean
419 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
420 GLuint start, GLuint end,
421 GLsizei count, GLenum type,
422 const GLvoid *indices)
423 {
424 FLUSH_CURRENT(ctx, 0);
425
426 if (end < start) {
427 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
428 return GL_FALSE;
429 }
430
431 return validate_DrawElements_common(ctx, mode, count, type, indices,
432 "glDrawRangeElements");
433 }
434
435
436 /**
437 * Called from the tnl module to error check the function parameters and
438 * verify that we really can draw something.
439 * \return GL_TRUE if OK to render, GL_FALSE if error found
440 */
441 GLboolean
442 _mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLsizei count)
443 {
444 struct gl_transform_feedback_object *xfb_obj
445 = ctx->TransformFeedback.CurrentObject;
446 FLUSH_CURRENT(ctx, 0);
447
448 if (count < 0) {
449 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
450 return GL_FALSE;
451 }
452
453 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
454 return GL_FALSE;
455 }
456
457 if (!check_valid_to_render(ctx, "glDrawArrays"))
458 return GL_FALSE;
459
460 /* From the GLES3 specification, section 2.14.2 (Transform Feedback
461 * Primitive Capture):
462 *
463 * The error INVALID_OPERATION is generated by DrawArrays and
464 * DrawArraysInstanced if recording the vertices of a primitive to the
465 * buffer objects being used for transform feedback purposes would result
466 * in either exceeding the limits of any buffer object’s size, or in
467 * exceeding the end position offset + size − 1, as set by
468 * BindBufferRange.
469 *
470 * This is in contrast to the behaviour of desktop GL, where the extra
471 * primitives are silently dropped from the transform feedback buffer.
472 */
473 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
474 size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
475 if (xfb_obj->GlesRemainingPrims < prim_count) {
476 _mesa_error(ctx, GL_INVALID_OPERATION,
477 "glDrawArrays(exceeds transform feedback size)");
478 return GL_FALSE;
479 }
480 xfb_obj->GlesRemainingPrims -= prim_count;
481 }
482
483 if (count == 0)
484 return GL_FALSE;
485
486 return GL_TRUE;
487 }
488
489
490 GLboolean
491 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
492 GLsizei count, GLsizei numInstances)
493 {
494 struct gl_transform_feedback_object *xfb_obj
495 = ctx->TransformFeedback.CurrentObject;
496 FLUSH_CURRENT(ctx, 0);
497
498 if (count < 0) {
499 _mesa_error(ctx, GL_INVALID_VALUE,
500 "glDrawArraysInstanced(count=%d)", count);
501 return GL_FALSE;
502 }
503
504 if (first < 0) {
505 _mesa_error(ctx, GL_INVALID_VALUE,
506 "glDrawArraysInstanced(start=%d)", first);
507 return GL_FALSE;
508 }
509
510 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
511 return GL_FALSE;
512 }
513
514 if (numInstances <= 0) {
515 if (numInstances < 0)
516 _mesa_error(ctx, GL_INVALID_VALUE,
517 "glDrawArraysInstanced(numInstances=%d)", numInstances);
518 return GL_FALSE;
519 }
520
521 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
522 return GL_FALSE;
523
524 /* From the GLES3 specification, section 2.14.2 (Transform Feedback
525 * Primitive Capture):
526 *
527 * The error INVALID_OPERATION is generated by DrawArrays and
528 * DrawArraysInstanced if recording the vertices of a primitive to the
529 * buffer objects being used for transform feedback purposes would result
530 * in either exceeding the limits of any buffer object’s size, or in
531 * exceeding the end position offset + size − 1, as set by
532 * BindBufferRange.
533 *
534 * This is in contrast to the behaviour of desktop GL, where the extra
535 * primitives are silently dropped from the transform feedback buffer.
536 */
537 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
538 size_t prim_count
539 = vbo_count_tessellated_primitives(mode, count, numInstances);
540 if (xfb_obj->GlesRemainingPrims < prim_count) {
541 _mesa_error(ctx, GL_INVALID_OPERATION,
542 "glDrawArraysInstanced(exceeds transform feedback size)");
543 return GL_FALSE;
544 }
545 xfb_obj->GlesRemainingPrims -= prim_count;
546 }
547
548 if (count == 0)
549 return GL_FALSE;
550
551 return GL_TRUE;
552 }
553
554
555 GLboolean
556 _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
557 GLenum mode, GLsizei count, GLenum type,
558 const GLvoid *indices, GLsizei numInstances)
559 {
560 FLUSH_CURRENT(ctx, 0);
561
562 if (numInstances < 0) {
563 _mesa_error(ctx, GL_INVALID_VALUE,
564 "glDrawElementsInstanced(numInstances=%d)", numInstances);
565 return GL_FALSE;
566 }
567
568 return validate_DrawElements_common(ctx, mode, count, type, indices,
569 "glDrawElementsInstanced")
570 && (numInstances > 0);
571 }
572
573
574 GLboolean
575 _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
576 GLenum mode,
577 struct gl_transform_feedback_object *obj,
578 GLuint stream,
579 GLsizei numInstances)
580 {
581 FLUSH_CURRENT(ctx, 0);
582
583 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) {
584 return GL_FALSE;
585 }
586
587 if (!obj) {
588 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
589 return GL_FALSE;
590 }
591
592 if (stream >= ctx->Const.MaxVertexStreams) {
593 _mesa_error(ctx, GL_INVALID_VALUE,
594 "glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
595 return GL_FALSE;
596 }
597
598 if (!obj->EndedAnytime) {
599 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
600 return GL_FALSE;
601 }
602
603 if (numInstances <= 0) {
604 if (numInstances < 0)
605 _mesa_error(ctx, GL_INVALID_VALUE,
606 "glDrawTransformFeedback*Instanced(numInstances=%d)",
607 numInstances);
608 return GL_FALSE;
609 }
610
611 if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) {
612 return GL_FALSE;
613 }
614
615 return GL_TRUE;
616 }
617
618 static GLboolean
619 valid_draw_indirect(struct gl_context *ctx,
620 GLenum mode, const GLvoid *indirect,
621 GLsizei size, const char *name)
622 {
623 const GLsizeiptr end = (GLsizeiptr)indirect + size;
624
625 if (!_mesa_valid_prim_mode(ctx, mode, name))
626 return GL_FALSE;
627
628
629 /* From the ARB_draw_indirect specification:
630 * "An INVALID_OPERATION error is generated [...] if <indirect> is no
631 * word aligned."
632 */
633 if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) {
634 _mesa_error(ctx, GL_INVALID_OPERATION,
635 "%s(indirect is not aligned)", name);
636 return GL_FALSE;
637 }
638
639 if (!_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
640 _mesa_error(ctx, GL_INVALID_OPERATION,
641 "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);
642 return GL_FALSE;
643 }
644
645 if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) {
646 _mesa_error(ctx, GL_INVALID_OPERATION,
647 "%s(DRAW_INDIRECT_BUFFER is mapped)", name);
648 return GL_FALSE;
649 }
650
651 /* From the ARB_draw_indirect specification:
652 * "An INVALID_OPERATION error is generated if the commands source data
653 * beyond the end of the buffer object [...]"
654 */
655 if (ctx->DrawIndirectBuffer->Size < end) {
656 _mesa_error(ctx, GL_INVALID_OPERATION,
657 "%s(DRAW_INDIRECT_BUFFER too small)", name);
658 return GL_FALSE;
659 }
660
661 if (!check_valid_to_render(ctx, name))
662 return GL_FALSE;
663
664 return GL_TRUE;
665 }
666
667 static inline GLboolean
668 valid_draw_indirect_elements(struct gl_context *ctx,
669 GLenum mode, GLenum type, const GLvoid *indirect,
670 GLsizeiptr size, const char *name)
671 {
672 if (!valid_elements_type(ctx, type, name))
673 return GL_FALSE;
674
675 /*
676 * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
677 * may not come from a client array and must come from an index buffer.
678 * If no element array buffer is bound, an INVALID_OPERATION error is
679 * generated.
680 */
681 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
682 _mesa_error(ctx, GL_INVALID_OPERATION,
683 "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name);
684 return GL_FALSE;
685 }
686
687 return valid_draw_indirect(ctx, mode, indirect, size, name);
688 }
689
690 static inline GLboolean
691 valid_draw_indirect_multi(struct gl_context *ctx,
692 GLsizei primcount, GLsizei stride,
693 const char *name)
694 {
695
696 /* From the ARB_multi_draw_indirect specification:
697 * "INVALID_VALUE is generated by MultiDrawArraysIndirect or
698 * MultiDrawElementsIndirect if <primcount> is negative."
699 *
700 * "<primcount> must be positive, otherwise an INVALID_VALUE error will
701 * be generated."
702 */
703 if (primcount < 0) {
704 _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);
705 return GL_FALSE;
706 }
707
708
709 /* From the ARB_multi_draw_indirect specification:
710 * "<stride> must be a multiple of four, otherwise an INVALID_VALUE
711 * error is generated."
712 */
713 if (stride % 4) {
714 _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name);
715 return GL_FALSE;
716 }
717
718 return GL_TRUE;
719 }
720
721 GLboolean
722 _mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
723 GLenum mode,
724 const GLvoid *indirect)
725 {
726 const unsigned drawArraysNumParams = 4;
727
728 FLUSH_CURRENT(ctx, 0);
729
730 return valid_draw_indirect(ctx, mode,
731 indirect, drawArraysNumParams * sizeof(GLuint),
732 "glDrawArraysIndirect");
733 }
734
735 GLboolean
736 _mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
737 GLenum mode, GLenum type,
738 const GLvoid *indirect)
739 {
740 const unsigned drawElementsNumParams = 5;
741
742 FLUSH_CURRENT(ctx, 0);
743
744 return valid_draw_indirect_elements(ctx, mode, type,
745 indirect, drawElementsNumParams * sizeof(GLuint),
746 "glDrawElementsIndirect");
747 }
748
749 GLboolean
750 _mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
751 GLenum mode,
752 const GLvoid *indirect,
753 GLsizei primcount, GLsizei stride)
754 {
755 GLsizeiptr size = 0;
756 const unsigned drawArraysNumParams = 4;
757
758 FLUSH_CURRENT(ctx, 0);
759
760 /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */
761 assert(stride != 0);
762
763 if (!valid_draw_indirect_multi(ctx, primcount, stride,
764 "glMultiDrawArraysIndirect"))
765 return GL_FALSE;
766
767 /* number of bytes of the indirect buffer which will be read */
768 size = primcount
769 ? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint)
770 : 0;
771
772 if (!valid_draw_indirect(ctx, mode, indirect, size,
773 "glMultiDrawArraysIndirect"))
774 return GL_FALSE;
775
776 return GL_TRUE;
777 }
778
779 GLboolean
780 _mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
781 GLenum mode, GLenum type,
782 const GLvoid *indirect,
783 GLsizei primcount, GLsizei stride)
784 {
785 GLsizeiptr size = 0;
786 const unsigned drawElementsNumParams = 5;
787
788 FLUSH_CURRENT(ctx, 0);
789
790 /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */
791 assert(stride != 0);
792
793 if (!valid_draw_indirect_multi(ctx, primcount, stride,
794 "glMultiDrawElementsIndirect"))
795 return GL_FALSE;
796
797 /* number of bytes of the indirect buffer which will be read */
798 size = primcount
799 ? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint)
800 : 0;
801
802 if (!valid_draw_indirect_elements(ctx, mode, type,
803 indirect, size,
804 "glMultiDrawElementsIndirect"))
805 return GL_FALSE;
806
807 return GL_TRUE;
808 }