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