1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR 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 "mfeatures.h"
32 #include "mtypes.h"
33 #include "enums.h"
34 #include "vbo/vbo.h"
35 #include <stdbool.h>
36 
37 
38 /**
39  * \return  number of bytes in array [count] of type.
40  */
41 static GLsizei
index_bytes(GLenum type,GLsizei count)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  * Find the max index in the given element/index buffer
59  */
60 GLuint
_mesa_max_buffer_index(struct gl_context * ctx,GLuint count,GLenum type,const void * indices,struct gl_buffer_object * elementBuf)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       /* Actual address is the sum of pointers */
74       indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
75    }
76 
77    if (type == GL_UNSIGNED_INT) {
78       for (i = 0; i < count; i++)
79          if (((GLuint *) indices)[i] > max)
80             max = ((GLuint *) indices)[i];
81    }
82    else if (type == GL_UNSIGNED_SHORT) {
83       for (i = 0; i < count; i++)
84          if (((GLushort *) indices)[i] > max)
85             max = ((GLushort *) indices)[i];
86    }
87    else {
88       ASSERT(type == GL_UNSIGNED_BYTE);
89       for (i = 0; i < count; i++)
90          if (((GLubyte *) indices)[i] > max)
91             max = ((GLubyte *) indices)[i];
92    }
93 
94    if (map) {
95       ctx->Driver.UnmapBuffer(ctx, elementBuf);
96    }
97 
98    return max;
99 }
100 
101 
102 /**
103  * Check if OK to draw arrays/elements.
104  */
105 static GLboolean
check_valid_to_render(struct gl_context * ctx,const char * function)106 check_valid_to_render(struct gl_context *ctx, const char *function)
107 {
108    if (!_mesa_valid_to_render(ctx, function)) {
109       return GL_FALSE;
110    }
111 
112    switch (ctx->API) {
113 #if FEATURE_es2_glsl
114    case API_OPENGLES2:
115       /* For ES2, we can draw if any vertex array is enabled (and we
116        * should always have a vertex program/shader). */
117       if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current)
118 	 return GL_FALSE;
119       break;
120 #endif
121 
122 #if FEATURE_ES1
123    case API_OPENGLES:
124       /* For OpenGL ES, only draw if we have vertex positions
125        */
126       if (!ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled)
127 	 return GL_FALSE;
128       break;
129 #endif
130 
131 #if FEATURE_GL
132    case API_OPENGL:
133    case API_OPENGL_CORE:
134       {
135          const struct gl_shader_program *vsProg =
136             ctx->Shader.CurrentVertexProgram;
137          GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus);
138          GLboolean haveVertexProgram = ctx->VertexProgram._Enabled;
139          if (haveVertexShader || haveVertexProgram) {
140             /* Draw regardless of whether or not we have any vertex arrays.
141              * (Ex: could draw a point using a constant vertex pos)
142              */
143             return GL_TRUE;
144          }
145          else {
146             /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
147              * array [0]).
148              */
149             return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
150                     ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
151          }
152       }
153       break;
154 #endif
155 
156    default:
157       ASSERT_NO_FEATURE();
158    }
159 
160    return GL_TRUE;
161 }
162 
163 
164 /**
165  * Do bounds checking on array element indexes.  Check that the vertices
166  * pointed to by the indices don't lie outside buffer object bounds.
167  * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
168  */
169 static GLboolean
check_index_bounds(struct gl_context * ctx,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)170 check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
171 		   const GLvoid *indices, GLint basevertex)
172 {
173    struct _mesa_prim prim;
174    struct _mesa_index_buffer ib;
175    GLuint min, max;
176 
177    /* Only the X Server needs to do this -- otherwise, accessing outside
178     * array/BO bounds allows application termination.
179     */
180    if (!ctx->Const.CheckArrayBounds)
181       return GL_TRUE;
182 
183    memset(&prim, 0, sizeof(prim));
184    prim.count = count;
185 
186    memset(&ib, 0, sizeof(ib));
187    ib.type = type;
188    ib.ptr = indices;
189    ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
190 
191    vbo_get_minmax_indices(ctx, &prim, &ib, &min, &max, 1);
192 
193    if ((int)(min + basevertex) < 0 ||
194        max + basevertex >= ctx->Array.ArrayObj->_MaxElement) {
195       /* the max element is out of bounds of one or more enabled arrays */
196       _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
197                     max, ctx->Array.ArrayObj->_MaxElement);
198       return GL_FALSE;
199    }
200 
201    return GL_TRUE;
202 }
203 
204 
205 /**
206  * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
207  * etc?  The set of legal values depends on whether geometry shaders/programs
208  * are supported.
209  */
210 GLboolean
_mesa_valid_prim_mode(struct gl_context * ctx,GLenum mode,const char * name)211 _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
212 {
213    bool valid_enum;
214 
215    switch (mode) {
216    case GL_POINTS:
217    case GL_LINES:
218    case GL_LINE_LOOP:
219    case GL_LINE_STRIP:
220    case GL_TRIANGLES:
221    case GL_TRIANGLE_STRIP:
222    case GL_TRIANGLE_FAN:
223       valid_enum = true;
224       break;
225    case GL_QUADS:
226    case GL_QUAD_STRIP:
227    case GL_POLYGON:
228       valid_enum = (ctx->API == API_OPENGL);
229       break;
230    case GL_LINES_ADJACENCY:
231    case GL_LINE_STRIP_ADJACENCY:
232    case GL_TRIANGLES_ADJACENCY:
233    case GL_TRIANGLE_STRIP_ADJACENCY:
234       valid_enum = _mesa_is_desktop_gl(ctx)
235          && ctx->Extensions.ARB_geometry_shader4;
236       break;
237    default:
238       valid_enum = false;
239       break;
240    }
241 
242    if (!valid_enum) {
243       _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
244       return GL_FALSE;
245    }
246 
247    /* From the GL_EXT_transform_feedback spec:
248     *
249     *     "The error INVALID_OPERATION is generated if Begin, or any command
250     *      that performs an explicit Begin, is called when:
251     *
252     *      * a geometry shader is not active and <mode> does not match the
253     *        allowed begin modes for the current transform feedback state as
254     *        given by table X.1.
255     *
256     *      * a geometry shader is active and the output primitive type of the
257     *        geometry shader does not match the allowed begin modes for the
258     *        current transform feedback state as given by table X.1.
259     *
260     */
261    if (ctx->TransformFeedback.CurrentObject->Active &&
262        !ctx->TransformFeedback.CurrentObject->Paused) {
263       GLboolean pass = GL_TRUE;
264 
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       if (!pass) {
279 	 _mesa_error(ctx, GL_INVALID_OPERATION,
280 		     "%s(mode=%s vs transform feedback %s)",
281 		     name,
282 		     _mesa_lookup_prim_by_nr(mode),
283 		     _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
284 	 return GL_FALSE;
285       }
286    }
287 
288    return GL_TRUE;
289 }
290 
291 /**
292  * Verify that the element type is valid.
293  *
294  * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
295  */
296 static bool
valid_elements_type(struct gl_context * ctx,GLenum type,const char * name)297 valid_elements_type(struct gl_context *ctx, GLenum type, const char *name)
298 {
299    switch (type) {
300    case GL_UNSIGNED_BYTE:
301    case GL_UNSIGNED_SHORT:
302    case GL_UNSIGNED_INT:
303       return true;
304 
305    default:
306       _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name,
307                   _mesa_lookup_enum_by_nr(type));
308       return false;
309    }
310 }
311 
312 /**
313  * Error checking for glDrawElements().  Includes parameter checking
314  * and VBO bounds checking.
315  * \return GL_TRUE if OK to render, GL_FALSE if error found
316  */
317 GLboolean
_mesa_validate_DrawElements(struct gl_context * ctx,GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)318 _mesa_validate_DrawElements(struct gl_context *ctx,
319 			    GLenum mode, GLsizei count, GLenum type,
320 			    const GLvoid *indices, GLint basevertex)
321 {
322    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
323    FLUSH_CURRENT(ctx, 0);
324 
325    if (count <= 0) {
326       if (count < 0)
327 	 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
328       return GL_FALSE;
329    }
330 
331    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) {
332       return GL_FALSE;
333    }
334 
335    if (!valid_elements_type(ctx, type, "glDrawElements"))
336       return GL_FALSE;
337 
338    if (!check_valid_to_render(ctx, "glDrawElements"))
339       return GL_FALSE;
340 
341    /* Vertex buffer object tests */
342    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
343       /* use indices in the buffer object */
344       /* make sure count doesn't go outside buffer bounds */
345       if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
346          _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
347          return GL_FALSE;
348       }
349    }
350    else {
351       /* not using a VBO */
352       if (!indices)
353          return GL_FALSE;
354    }
355 
356    if (!check_index_bounds(ctx, count, type, indices, basevertex))
357       return GL_FALSE;
358 
359    return GL_TRUE;
360 }
361 
362 
363 /**
364  * Error checking for glMultiDrawElements().  Includes parameter checking
365  * and VBO bounds checking.
366  * \return GL_TRUE if OK to render, GL_FALSE if error found
367  */
368 GLboolean
_mesa_validate_MultiDrawElements(struct gl_context * ctx,GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLuint primcount,const GLint * basevertex)369 _mesa_validate_MultiDrawElements(struct gl_context *ctx,
370                                  GLenum mode, const GLsizei *count,
371                                  GLenum type, const GLvoid * const *indices,
372                                  GLuint primcount, const GLint *basevertex)
373 {
374    unsigned i;
375 
376    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
377    FLUSH_CURRENT(ctx, 0);
378 
379    for (i = 0; i < primcount; i++) {
380       if (count[i] <= 0) {
381          if (count[i] < 0)
382             _mesa_error(ctx, GL_INVALID_VALUE,
383                         "glMultiDrawElements(count)" );
384          return GL_FALSE;
385       }
386    }
387 
388    if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) {
389       return GL_FALSE;
390    }
391 
392    if (!valid_elements_type(ctx, type, "glMultiDrawElements"))
393       return GL_FALSE;
394 
395    if (!check_valid_to_render(ctx, "glMultiDrawElements"))
396       return GL_FALSE;
397 
398    /* Vertex buffer object tests */
399    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
400       /* use indices in the buffer object */
401       /* make sure count doesn't go outside buffer bounds */
402       for (i = 0; i < primcount; i++) {
403          if (index_bytes(type, count[i]) >
404              ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
405             _mesa_warning(ctx,
406                           "glMultiDrawElements index out of buffer bounds");
407             return GL_FALSE;
408          }
409       }
410    }
411    else {
412       /* not using a VBO */
413       for (i = 0; i < primcount; i++) {
414          if (!indices[i])
415             return GL_FALSE;
416       }
417    }
418 
419    for (i = 0; i < primcount; i++) {
420       if (!check_index_bounds(ctx, count[i], type, indices[i],
421                               basevertex ? basevertex[i] : 0))
422          return GL_FALSE;
423    }
424 
425    return GL_TRUE;
426 }
427 
428 
429 /**
430  * Error checking for glDrawRangeElements().  Includes parameter checking
431  * and VBO bounds checking.
432  * \return GL_TRUE if OK to render, GL_FALSE if error found
433  */
434 GLboolean
_mesa_validate_DrawRangeElements(struct gl_context * ctx,GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)435 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
436 				 GLuint start, GLuint end,
437 				 GLsizei count, GLenum type,
438 				 const GLvoid *indices, GLint basevertex)
439 {
440    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
441    FLUSH_CURRENT(ctx, 0);
442 
443    if (count <= 0) {
444       if (count < 0)
445 	 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
446       return GL_FALSE;
447    }
448 
449    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) {
450       return GL_FALSE;
451    }
452 
453    if (end < start) {
454       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
455       return GL_FALSE;
456    }
457 
458    if (!valid_elements_type(ctx, type, "glDrawRangeElements"))
459       return GL_FALSE;
460 
461    if (!check_valid_to_render(ctx, "glDrawRangeElements"))
462       return GL_FALSE;
463 
464    /* Vertex buffer object tests */
465    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
466       /* use indices in the buffer object */
467       /* make sure count doesn't go outside buffer bounds */
468       if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
469          _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
470          return GL_FALSE;
471       }
472    }
473    else {
474       /* not using a VBO */
475       if (!indices)
476          return GL_FALSE;
477    }
478 
479    if (!check_index_bounds(ctx, count, type, indices, basevertex))
480       return GL_FALSE;
481 
482    return GL_TRUE;
483 }
484 
485 
486 /**
487  * Called from the tnl module to error check the function parameters and
488  * verify that we really can draw something.
489  * \return GL_TRUE if OK to render, GL_FALSE if error found
490  */
491 GLboolean
_mesa_validate_DrawArrays(struct gl_context * ctx,GLenum mode,GLint start,GLsizei count)492 _mesa_validate_DrawArrays(struct gl_context *ctx,
493 			  GLenum mode, GLint start, GLsizei count)
494 {
495    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
496    FLUSH_CURRENT(ctx, 0);
497 
498    if (count <= 0) {
499       if (count < 0)
500          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
501       return GL_FALSE;
502    }
503 
504    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
505       return GL_FALSE;
506    }
507 
508    if (!check_valid_to_render(ctx, "glDrawArrays"))
509       return GL_FALSE;
510 
511    if (ctx->Const.CheckArrayBounds) {
512       if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
513          return GL_FALSE;
514    }
515 
516    return GL_TRUE;
517 }
518 
519 
520 GLboolean
_mesa_validate_DrawArraysInstanced(struct gl_context * ctx,GLenum mode,GLint first,GLsizei count,GLsizei numInstances)521 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
522                                    GLsizei count, GLsizei numInstances)
523 {
524    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
525    FLUSH_CURRENT(ctx, 0);
526 
527    if (count <= 0) {
528       if (count < 0)
529          _mesa_error(ctx, GL_INVALID_VALUE,
530                      "glDrawArraysInstanced(count=%d)", count);
531       return GL_FALSE;
532    }
533 
534    if (first < 0) {
535       _mesa_error(ctx, GL_INVALID_VALUE,
536 		  "glDrawArraysInstanced(start=%d)", first);
537       return GL_FALSE;
538    }
539 
540    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
541       return GL_FALSE;
542    }
543 
544    if (numInstances <= 0) {
545       if (numInstances < 0)
546          _mesa_error(ctx, GL_INVALID_VALUE,
547                      "glDrawArraysInstanced(numInstances=%d)", numInstances);
548       return GL_FALSE;
549    }
550 
551    if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
552       return GL_FALSE;
553 
554    if (ctx->Const.CheckArrayBounds) {
555       if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
556          return GL_FALSE;
557    }
558 
559    return GL_TRUE;
560 }
561 
562 
563 GLboolean
_mesa_validate_DrawElementsInstanced(struct gl_context * ctx,GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei numInstances,GLint basevertex)564 _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
565                                      GLenum mode, GLsizei count, GLenum type,
566                                      const GLvoid *indices, GLsizei numInstances,
567                                      GLint basevertex)
568 {
569    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
570    FLUSH_CURRENT(ctx, 0);
571 
572    if (count <= 0) {
573       if (count < 0)
574 	 _mesa_error(ctx, GL_INVALID_VALUE,
575                      "glDrawElementsInstanced(count=%d)", count);
576       return GL_FALSE;
577    }
578 
579    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) {
580       return GL_FALSE;
581    }
582 
583    if (!valid_elements_type(ctx, type, "glDrawElementsInstanced"))
584       return GL_FALSE;
585 
586    if (numInstances <= 0) {
587       if (numInstances < 0)
588          _mesa_error(ctx, GL_INVALID_VALUE,
589                      "glDrawElementsInstanced(numInstances=%d)", numInstances);
590       return GL_FALSE;
591    }
592 
593    if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
594       return GL_FALSE;
595 
596    /* Vertex buffer object tests */
597    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
598       /* use indices in the buffer object */
599       /* make sure count doesn't go outside buffer bounds */
600       if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
601          _mesa_warning(ctx,
602                        "glDrawElementsInstanced index out of buffer bounds");
603          return GL_FALSE;
604       }
605    }
606    else {
607       /* not using a VBO */
608       if (!indices)
609          return GL_FALSE;
610    }
611 
612    if (!check_index_bounds(ctx, count, type, indices, basevertex))
613       return GL_FALSE;
614 
615    return GL_TRUE;
616 }
617 
618 
619 #if FEATURE_EXT_transform_feedback
620 
621 GLboolean
_mesa_validate_DrawTransformFeedback(struct gl_context * ctx,GLenum mode,struct gl_transform_feedback_object * obj,GLuint stream,GLsizei numInstances)622 _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
623                                      GLenum mode,
624                                      struct gl_transform_feedback_object *obj,
625                                      GLuint stream,
626                                      GLsizei numInstances)
627 {
628    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
629    FLUSH_CURRENT(ctx, 0);
630 
631    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) {
632       return GL_FALSE;
633    }
634 
635    if (!obj) {
636       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
637       return GL_FALSE;
638    }
639 
640    if (!obj->EndedAnytime) {
641       _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
642       return GL_FALSE;
643    }
644 
645    if (stream >= ctx->Const.MaxVertexStreams) {
646       _mesa_error(ctx, GL_INVALID_VALUE,
647                   "glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
648       return GL_FALSE;
649    }
650 
651    if (numInstances <= 0) {
652       if (numInstances < 0)
653          _mesa_error(ctx, GL_INVALID_VALUE,
654                      "glDrawTransformFeedback*Instanced(numInstances=%d)",
655                      numInstances);
656       return GL_FALSE;
657    }
658 
659    if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) {
660       return GL_FALSE;
661    }
662 
663    return GL_TRUE;
664 }
665 
666 #endif
667