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