9c2e29e6472272a1285f7fe734aff8af7c924b29
[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 /* The overwhelmingly common case is (mode <= GL_TRIANGLE_FAN). Test that
117 * first and exit. You would think that a switch-statement would be the
118 * right approach, but at least GCC 4.7.2 generates some pretty dire code
119 * for the common case.
120 */
121 if (likely(mode <= GL_TRIANGLE_FAN))
122 return true;
123
124 if (mode <= GL_POLYGON)
125 return (ctx->API == API_OPENGL_COMPAT);
126
127 if (mode <= GL_TRIANGLE_STRIP_ADJACENCY)
128 return _mesa_has_geometry_shaders(ctx);
129
130 return false;
131 }
132
133
134 /**
135 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
136 * etc? Also, do additional checking related to transformation feedback.
137 * Note: this function cannot be called during glNewList(GL_COMPILE) because
138 * this code depends on current transform feedback state.
139 */
140 GLboolean
141 _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
142 {
143 bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode);
144
145 if (!valid_enum) {
146 _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
147 return GL_FALSE;
148 }
149
150 /* From the ARB_geometry_shader4 spec:
151 *
152 * The error INVALID_OPERATION is generated if Begin, or any command that
153 * implicitly calls Begin, is called when a geometry shader is active and:
154 *
155 * * the input primitive type of the current geometry shader is
156 * POINTS and <mode> is not POINTS,
157 *
158 * * the input primitive type of the current geometry shader is
159 * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP,
160 *
161 * * the input primitive type of the current geometry shader is
162 * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or
163 * TRIANGLE_FAN,
164 *
165 * * the input primitive type of the current geometry shader is
166 * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or
167 * LINE_STRIP_ADJACENCY_ARB, or
168 *
169 * * the input primitive type of the current geometry shader is
170 * TRIANGLES_ADJACENCY_ARB and <mode> is not
171 * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
172 *
173 */
174 if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
175 const GLenum geom_mode =
176 ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
177 switch (mode) {
178 case GL_POINTS:
179 valid_enum = (geom_mode == GL_POINTS);
180 break;
181 case GL_LINES:
182 case GL_LINE_LOOP:
183 case GL_LINE_STRIP:
184 valid_enum = (geom_mode == GL_LINES);
185 break;
186 case GL_TRIANGLES:
187 case GL_TRIANGLE_STRIP:
188 case GL_TRIANGLE_FAN:
189 valid_enum = (geom_mode == GL_TRIANGLES);
190 break;
191 case GL_QUADS:
192 case GL_QUAD_STRIP:
193 case GL_POLYGON:
194 valid_enum = false;
195 break;
196 case GL_LINES_ADJACENCY:
197 case GL_LINE_STRIP_ADJACENCY:
198 valid_enum = (geom_mode == GL_LINES_ADJACENCY);
199 break;
200 case GL_TRIANGLES_ADJACENCY:
201 case GL_TRIANGLE_STRIP_ADJACENCY:
202 valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY);
203 break;
204 default:
205 valid_enum = false;
206 break;
207 }
208 if (!valid_enum) {
209 _mesa_error(ctx, GL_INVALID_OPERATION,
210 "%s(mode=%s vs geometry shader input %s)",
211 name,
212 _mesa_lookup_prim_by_nr(mode),
213 _mesa_lookup_prim_by_nr(geom_mode));
214 return GL_FALSE;
215 }
216 }
217
218 /* From the GL_EXT_transform_feedback spec:
219 *
220 * "The error INVALID_OPERATION is generated if Begin, or any command
221 * that performs an explicit Begin, is called when:
222 *
223 * * a geometry shader is not active and <mode> does not match the
224 * allowed begin modes for the current transform feedback state as
225 * given by table X.1.
226 *
227 * * a geometry shader is active and the output primitive type of the
228 * geometry shader does not match the allowed begin modes for the
229 * current transform feedback state as given by table X.1.
230 *
231 */
232 if (_mesa_is_xfb_active_and_unpaused(ctx)) {
233 GLboolean pass = GL_TRUE;
234
235 if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
236 switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
237 case GL_POINTS:
238 pass = ctx->TransformFeedback.Mode == GL_POINTS;
239 break;
240 case GL_LINE_STRIP:
241 pass = ctx->TransformFeedback.Mode == GL_LINES;
242 break;
243 case GL_TRIANGLE_STRIP:
244 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
245 break;
246 default:
247 pass = GL_FALSE;
248 }
249 }
250 else {
251 switch (mode) {
252 case GL_POINTS:
253 pass = ctx->TransformFeedback.Mode == GL_POINTS;
254 break;
255 case GL_LINES:
256 case GL_LINE_STRIP:
257 case GL_LINE_LOOP:
258 pass = ctx->TransformFeedback.Mode == GL_LINES;
259 break;
260 default:
261 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
262 break;
263 }
264 }
265 if (!pass) {
266 _mesa_error(ctx, GL_INVALID_OPERATION,
267 "%s(mode=%s vs transform feedback %s)",
268 name,
269 _mesa_lookup_prim_by_nr(mode),
270 _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
271 return GL_FALSE;
272 }
273 }
274
275 return GL_TRUE;
276 }
277
278 /**
279 * Verify that the element type is valid.
280 *
281 * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
282 */
283 static bool
284 valid_elements_type(struct gl_context *ctx, GLenum type, const char *name)
285 {
286 switch (type) {
287 case GL_UNSIGNED_BYTE:
288 case GL_UNSIGNED_SHORT:
289 case GL_UNSIGNED_INT:
290 return true;
291
292 default:
293 _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name,
294 _mesa_lookup_enum_by_nr(type));
295 return false;
296 }
297 }
298
299 static bool
300 validate_DrawElements_common(struct gl_context *ctx,
301 GLenum mode, GLsizei count, GLenum type,
302 const GLvoid *indices,
303 const char *caller)
304 {
305 /* From the GLES3 specification, section 2.14.2 (Transform Feedback
306 * Primitive Capture):
307 *
308 * The error INVALID_OPERATION is also generated by DrawElements,
309 * DrawElementsInstanced, and DrawRangeElements while transform feedback
310 * is active and not paused, regardless of mode.
311 */
312 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
313 _mesa_error(ctx, GL_INVALID_OPERATION,
314 "%s(transform feedback active)", caller);
315 return false;
316 }
317
318 if (count < 0) {
319 _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller);
320 return false;
321 }
322
323 if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
324 return false;
325 }
326
327 if (!valid_elements_type(ctx, type, caller))
328 return false;
329
330 if (!check_valid_to_render(ctx, caller))
331 return false;
332
333 /* Not using a VBO for indices, so avoid NULL pointer derefs later.
334 */
335 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
336 return false;
337
338 if (count == 0)
339 return false;
340
341 return true;
342 }
343
344 /**
345 * Error checking for glDrawElements(). Includes parameter checking
346 * and VBO bounds checking.
347 * \return GL_TRUE if OK to render, GL_FALSE if error found
348 */
349 GLboolean
350 _mesa_validate_DrawElements(struct gl_context *ctx,
351 GLenum mode, GLsizei count, GLenum type,
352 const GLvoid *indices)
353 {
354 FLUSH_CURRENT(ctx, 0);
355
356 return validate_DrawElements_common(ctx, mode, count, type, indices,
357 "glDrawElements");
358 }
359
360
361 /**
362 * Error checking for glMultiDrawElements(). Includes parameter checking
363 * and VBO bounds checking.
364 * \return GL_TRUE if OK to render, GL_FALSE if error found
365 */
366 GLboolean
367 _mesa_validate_MultiDrawElements(struct gl_context *ctx,
368 GLenum mode, const GLsizei *count,
369 GLenum type, const GLvoid * const *indices,
370 GLuint primcount)
371 {
372 unsigned i;
373
374 FLUSH_CURRENT(ctx, 0);
375
376 for (i = 0; i < primcount; i++) {
377 if (count[i] < 0) {
378 _mesa_error(ctx, GL_INVALID_VALUE,
379 "glMultiDrawElements(count)" );
380 return GL_FALSE;
381 }
382 }
383
384 if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) {
385 return GL_FALSE;
386 }
387
388 if (!valid_elements_type(ctx, type, "glMultiDrawElements"))
389 return GL_FALSE;
390
391 if (!check_valid_to_render(ctx, "glMultiDrawElements"))
392 return GL_FALSE;
393
394 /* Not using a VBO for indices, so avoid NULL pointer derefs later.
395 */
396 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
397 for (i = 0; i < primcount; i++) {
398 if (!indices[i])
399 return GL_FALSE;
400 }
401 }
402
403 return GL_TRUE;
404 }
405
406
407 /**
408 * Error checking for glDrawRangeElements(). Includes parameter checking
409 * and VBO bounds checking.
410 * \return GL_TRUE if OK to render, GL_FALSE if error found
411 */
412 GLboolean
413 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
414 GLuint start, GLuint end,
415 GLsizei count, GLenum type,
416 const GLvoid *indices)
417 {
418 FLUSH_CURRENT(ctx, 0);
419
420 if (end < start) {
421 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
422 return GL_FALSE;
423 }
424
425 return validate_DrawElements_common(ctx, mode, count, type, indices,
426 "glDrawRangeElements");
427 }
428
429
430 /**
431 * Called from the tnl module to error check the function parameters and
432 * verify that we really can draw something.
433 * \return GL_TRUE if OK to render, GL_FALSE if error found
434 */
435 GLboolean
436 _mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLsizei count)
437 {
438 struct gl_transform_feedback_object *xfb_obj
439 = ctx->TransformFeedback.CurrentObject;
440 FLUSH_CURRENT(ctx, 0);
441
442 if (count < 0) {
443 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
444 return GL_FALSE;
445 }
446
447 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
448 return GL_FALSE;
449 }
450
451 if (!check_valid_to_render(ctx, "glDrawArrays"))
452 return GL_FALSE;
453
454 /* From the GLES3 specification, section 2.14.2 (Transform Feedback
455 * Primitive Capture):
456 *
457 * The error INVALID_OPERATION is generated by DrawArrays and
458 * DrawArraysInstanced if recording the vertices of a primitive to the
459 * buffer objects being used for transform feedback purposes would result
460 * in either exceeding the limits of any buffer object’s size, or in
461 * exceeding the end position offset + size − 1, as set by
462 * BindBufferRange.
463 *
464 * This is in contrast to the behaviour of desktop GL, where the extra
465 * primitives are silently dropped from the transform feedback buffer.
466 */
467 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
468 size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
469 if (xfb_obj->GlesRemainingPrims < prim_count) {
470 _mesa_error(ctx, GL_INVALID_OPERATION,
471 "glDrawArrays(exceeds transform feedback size)");
472 return GL_FALSE;
473 }
474 xfb_obj->GlesRemainingPrims -= prim_count;
475 }
476
477 if (count == 0)
478 return GL_FALSE;
479
480 return GL_TRUE;
481 }
482
483
484 GLboolean
485 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
486 GLsizei count, GLsizei numInstances)
487 {
488 struct gl_transform_feedback_object *xfb_obj
489 = ctx->TransformFeedback.CurrentObject;
490 FLUSH_CURRENT(ctx, 0);
491
492 if (count < 0) {
493 _mesa_error(ctx, GL_INVALID_VALUE,
494 "glDrawArraysInstanced(count=%d)", count);
495 return GL_FALSE;
496 }
497
498 if (first < 0) {
499 _mesa_error(ctx, GL_INVALID_VALUE,
500 "glDrawArraysInstanced(start=%d)", first);
501 return GL_FALSE;
502 }
503
504 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
505 return GL_FALSE;
506 }
507
508 if (numInstances <= 0) {
509 if (numInstances < 0)
510 _mesa_error(ctx, GL_INVALID_VALUE,
511 "glDrawArraysInstanced(numInstances=%d)", numInstances);
512 return GL_FALSE;
513 }
514
515 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
516 return GL_FALSE;
517
518 /* From the GLES3 specification, section 2.14.2 (Transform Feedback
519 * Primitive Capture):
520 *
521 * The error INVALID_OPERATION is generated by DrawArrays and
522 * DrawArraysInstanced if recording the vertices of a primitive to the
523 * buffer objects being used for transform feedback purposes would result
524 * in either exceeding the limits of any buffer object’s size, or in
525 * exceeding the end position offset + size − 1, as set by
526 * BindBufferRange.
527 *
528 * This is in contrast to the behaviour of desktop GL, where the extra
529 * primitives are silently dropped from the transform feedback buffer.
530 */
531 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
532 size_t prim_count
533 = vbo_count_tessellated_primitives(mode, count, numInstances);
534 if (xfb_obj->GlesRemainingPrims < prim_count) {
535 _mesa_error(ctx, GL_INVALID_OPERATION,
536 "glDrawArraysInstanced(exceeds transform feedback size)");
537 return GL_FALSE;
538 }
539 xfb_obj->GlesRemainingPrims -= prim_count;
540 }
541
542 if (count == 0)
543 return GL_FALSE;
544
545 return GL_TRUE;
546 }
547
548
549 GLboolean
550 _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
551 GLenum mode, GLsizei count, GLenum type,
552 const GLvoid *indices, GLsizei numInstances)
553 {
554 FLUSH_CURRENT(ctx, 0);
555
556 if (numInstances < 0) {
557 _mesa_error(ctx, GL_INVALID_VALUE,
558 "glDrawElementsInstanced(numInstances=%d)", numInstances);
559 return GL_FALSE;
560 }
561
562 return validate_DrawElements_common(ctx, mode, count, type, indices,
563 "glDrawElementsInstanced")
564 && (numInstances > 0);
565 }
566
567
568 GLboolean
569 _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
570 GLenum mode,
571 struct gl_transform_feedback_object *obj,
572 GLuint stream,
573 GLsizei numInstances)
574 {
575 FLUSH_CURRENT(ctx, 0);
576
577 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) {
578 return GL_FALSE;
579 }
580
581 if (!obj) {
582 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
583 return GL_FALSE;
584 }
585
586 if (stream >= ctx->Const.MaxVertexStreams) {
587 _mesa_error(ctx, GL_INVALID_VALUE,
588 "glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
589 return GL_FALSE;
590 }
591
592 if (!obj->EndedAnytime) {
593 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
594 return GL_FALSE;
595 }
596
597 if (numInstances <= 0) {
598 if (numInstances < 0)
599 _mesa_error(ctx, GL_INVALID_VALUE,
600 "glDrawTransformFeedback*Instanced(numInstances=%d)",
601 numInstances);
602 return GL_FALSE;
603 }
604
605 if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) {
606 return GL_FALSE;
607 }
608
609 return GL_TRUE;
610 }
611
612 static GLboolean
613 valid_draw_indirect(struct gl_context *ctx,
614 GLenum mode, const GLvoid *indirect,
615 GLsizei size, const char *name)
616 {
617 const GLsizeiptr end = (GLsizeiptr)indirect + size;
618
619 if (!_mesa_valid_prim_mode(ctx, mode, name))
620 return GL_FALSE;
621
622
623 /* From the ARB_draw_indirect specification:
624 * "An INVALID_OPERATION error is generated [...] if <indirect> is no
625 * word aligned."
626 */
627 if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) {
628 _mesa_error(ctx, GL_INVALID_OPERATION,
629 "%s(indirect is not aligned)", name);
630 return GL_FALSE;
631 }
632
633 if (!_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
634 _mesa_error(ctx, GL_INVALID_OPERATION,
635 "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);
636 return GL_FALSE;
637 }
638
639 if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) {
640 _mesa_error(ctx, GL_INVALID_OPERATION,
641 "%s(DRAW_INDIRECT_BUFFER is mapped)", name);
642 return GL_FALSE;
643 }
644
645 /* From the ARB_draw_indirect specification:
646 * "An INVALID_OPERATION error is generated if the commands source data
647 * beyond the end of the buffer object [...]"
648 */
649 if (ctx->DrawIndirectBuffer->Size < end) {
650 _mesa_error(ctx, GL_INVALID_OPERATION,
651 "%s(DRAW_INDIRECT_BUFFER too small)", name);
652 return GL_FALSE;
653 }
654
655 if (!check_valid_to_render(ctx, name))
656 return GL_FALSE;
657
658 return GL_TRUE;
659 }
660
661 static inline GLboolean
662 valid_draw_indirect_elements(struct gl_context *ctx,
663 GLenum mode, GLenum type, const GLvoid *indirect,
664 GLsizeiptr size, const char *name)
665 {
666 if (!valid_elements_type(ctx, type, name))
667 return GL_FALSE;
668
669 /*
670 * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
671 * may not come from a client array and must come from an index buffer.
672 * If no element array buffer is bound, an INVALID_OPERATION error is
673 * generated.
674 */
675 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
676 _mesa_error(ctx, GL_INVALID_OPERATION,
677 "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name);
678 return GL_FALSE;
679 }
680
681 return valid_draw_indirect(ctx, mode, indirect, size, name);
682 }
683
684 static inline GLboolean
685 valid_draw_indirect_multi(struct gl_context *ctx,
686 GLsizei primcount, GLsizei stride,
687 const char *name)
688 {
689
690 /* From the ARB_multi_draw_indirect specification:
691 * "INVALID_VALUE is generated by MultiDrawArraysIndirect or
692 * MultiDrawElementsIndirect if <primcount> is negative."
693 *
694 * "<primcount> must be positive, otherwise an INVALID_VALUE error will
695 * be generated."
696 */
697 if (primcount < 0) {
698 _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);
699 return GL_FALSE;
700 }
701
702
703 /* From the ARB_multi_draw_indirect specification:
704 * "<stride> must be a multiple of four, otherwise an INVALID_VALUE
705 * error is generated."
706 */
707 if (stride % 4) {
708 _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name);
709 return GL_FALSE;
710 }
711
712 return GL_TRUE;
713 }
714
715 GLboolean
716 _mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
717 GLenum mode,
718 const GLvoid *indirect)
719 {
720 const unsigned drawArraysNumParams = 4;
721
722 FLUSH_CURRENT(ctx, 0);
723
724 return valid_draw_indirect(ctx, mode,
725 indirect, drawArraysNumParams * sizeof(GLuint),
726 "glDrawArraysIndirect");
727 }
728
729 GLboolean
730 _mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
731 GLenum mode, GLenum type,
732 const GLvoid *indirect)
733 {
734 const unsigned drawElementsNumParams = 5;
735
736 FLUSH_CURRENT(ctx, 0);
737
738 return valid_draw_indirect_elements(ctx, mode, type,
739 indirect, drawElementsNumParams * sizeof(GLuint),
740 "glDrawElementsIndirect");
741 }
742
743 GLboolean
744 _mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
745 GLenum mode,
746 const GLvoid *indirect,
747 GLsizei primcount, GLsizei stride)
748 {
749 GLsizeiptr size = 0;
750 const unsigned drawArraysNumParams = 4;
751
752 FLUSH_CURRENT(ctx, 0);
753
754 /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */
755 assert(stride != 0);
756
757 if (!valid_draw_indirect_multi(ctx, primcount, stride,
758 "glMultiDrawArraysIndirect"))
759 return GL_FALSE;
760
761 /* number of bytes of the indirect buffer which will be read */
762 size = primcount
763 ? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint)
764 : 0;
765
766 if (!valid_draw_indirect(ctx, mode, indirect, size,
767 "glMultiDrawArraysIndirect"))
768 return GL_FALSE;
769
770 return GL_TRUE;
771 }
772
773 GLboolean
774 _mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
775 GLenum mode, GLenum type,
776 const GLvoid *indirect,
777 GLsizei primcount, GLsizei stride)
778 {
779 GLsizeiptr size = 0;
780 const unsigned drawElementsNumParams = 5;
781
782 FLUSH_CURRENT(ctx, 0);
783
784 /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */
785 assert(stride != 0);
786
787 if (!valid_draw_indirect_multi(ctx, primcount, stride,
788 "glMultiDrawElementsIndirect"))
789 return GL_FALSE;
790
791 /* number of bytes of the indirect buffer which will be read */
792 size = primcount
793 ? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint)
794 : 0;
795
796 if (!valid_draw_indirect_elements(ctx, mode, type,
797 indirect, size,
798 "glMultiDrawElementsIndirect"))
799 return GL_FALSE;
800
801 return GL_TRUE;
802 }