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