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