OSDN Git Service

53b00211bc196aedee478863355c09cd8df4d913
[android-x86/external-mesa.git] / src / mesa / main / api_validate.c
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 "transformfeedback.h"
36 #include <stdbool.h>
37
38
39 /**
40  * \return  number of bytes in array [count] of type.
41  */
42 static GLsizei
43 index_bytes(GLenum type, GLsizei count)
44 {
45    if (type == GL_UNSIGNED_INT) {
46       return count * sizeof(GLuint);
47    }
48    else if (type == GL_UNSIGNED_BYTE) {
49       return count * sizeof(GLubyte);
50    }
51    else {
52       ASSERT(type == GL_UNSIGNED_SHORT);
53       return count * sizeof(GLushort);
54    }
55 }
56
57
58 /**
59  * Find the max index in the given element/index buffer
60  */
61 GLuint
62 _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type,
63                        const void *indices,
64                        struct gl_buffer_object *elementBuf)
65 {
66    const GLubyte *map = NULL;
67    GLuint max = 0;
68    GLuint i;
69
70    if (_mesa_is_bufferobj(elementBuf)) {
71       /* elements are in a user-defined buffer object.  need to map it */
72       map = ctx->Driver.MapBufferRange(ctx, 0, elementBuf->Size,
73                                        GL_MAP_READ_BIT, elementBuf);
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);
97    }
98
99    return max;
100 }
101
102
103 /**
104  * Check if OK to draw arrays/elements.
105  */
106 static GLboolean
107 check_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 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
121    case API_OPENGLES:
122       /* For OpenGL ES, only draw if we have vertex positions
123        */
124       if (!ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled)
125          return GL_FALSE;
126       break;
127
128    case API_OPENGL_COMPAT:
129    case API_OPENGL_CORE:
130       {
131          const struct gl_shader_program *vsProg =
132             ctx->Shader.CurrentVertexProgram;
133          GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus);
134          GLboolean haveVertexProgram = ctx->VertexProgram._Enabled;
135          if (haveVertexShader || haveVertexProgram) {
136             /* Draw regardless of whether or not we have any vertex arrays.
137              * (Ex: could draw a point using a constant vertex pos)
138              */
139             return GL_TRUE;
140          }
141          else {
142             /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
143              * array [0]).
144              */
145             return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
146                     ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
147          }
148       }
149       break;
150
151    default:
152       assert(!"Invalid API value in check_valid_to_render()");
153    }
154
155    return GL_TRUE;
156 }
157
158
159 /**
160  * Do bounds checking on array element indexes.  Check that the vertices
161  * pointed to by the indices don't lie outside buffer object bounds.
162  * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
163  */
164 static GLboolean
165 check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
166                    const GLvoid *indices, GLint basevertex)
167 {
168    struct _mesa_prim prim;
169    struct _mesa_index_buffer ib;
170    GLuint min, max;
171
172    /* Only the X Server needs to do this -- otherwise, accessing outside
173     * array/BO bounds allows application termination.
174     */
175    if (!ctx->Const.CheckArrayBounds)
176       return GL_TRUE;
177
178    memset(&prim, 0, sizeof(prim));
179    prim.count = count;
180
181    memset(&ib, 0, sizeof(ib));
182    ib.type = type;
183    ib.ptr = indices;
184    ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
185
186    vbo_get_minmax_indices(ctx, &prim, &ib, &min, &max, 1);
187
188    if ((int)(min + basevertex) < 0 ||
189        max + basevertex >= ctx->Array.ArrayObj->_MaxElement) {
190       /* the max element is out of bounds of one or more enabled arrays */
191       _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
192                     max, ctx->Array.ArrayObj->_MaxElement);
193       return GL_FALSE;
194    }
195
196    return GL_TRUE;
197 }
198
199
200 /**
201  * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
202  * etc?  The set of legal values depends on whether geometry shaders/programs
203  * are supported.
204  */
205 GLboolean
206 _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
207 {
208    bool valid_enum;
209
210    switch (mode) {
211    case GL_POINTS:
212    case GL_LINES:
213    case GL_LINE_LOOP:
214    case GL_LINE_STRIP:
215    case GL_TRIANGLES:
216    case GL_TRIANGLE_STRIP:
217    case GL_TRIANGLE_FAN:
218       valid_enum = true;
219       break;
220    case GL_QUADS:
221    case GL_QUAD_STRIP:
222    case GL_POLYGON:
223       valid_enum = (ctx->API == API_OPENGL_COMPAT);
224       break;
225    case GL_LINES_ADJACENCY:
226    case GL_LINE_STRIP_ADJACENCY:
227    case GL_TRIANGLES_ADJACENCY:
228    case GL_TRIANGLE_STRIP_ADJACENCY:
229       valid_enum = _mesa_is_desktop_gl(ctx)
230          && ctx->Extensions.ARB_geometry_shader4;
231       break;
232    default:
233       valid_enum = false;
234       break;
235    }
236
237    if (!valid_enum) {
238       _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
239       return GL_FALSE;
240    }
241
242    /* From the GL_EXT_transform_feedback spec:
243     *
244     *     "The error INVALID_OPERATION is generated if Begin, or any command
245     *      that performs an explicit Begin, is called when:
246     *
247     *      * a geometry shader is not active and <mode> does not match the
248     *        allowed begin modes for the current transform feedback state as
249     *        given by table X.1.
250     *
251     *      * a geometry shader is active and the output primitive type of the
252     *        geometry shader does not match the allowed begin modes for the
253     *        current transform feedback state as given by table X.1.
254     *
255     */
256    if (_mesa_is_xfb_active_and_unpaused(ctx)) {
257       GLboolean pass = GL_TRUE;
258
259       switch (mode) {
260       case GL_POINTS:
261          pass = ctx->TransformFeedback.Mode == GL_POINTS;
262          break;
263       case GL_LINES:
264       case GL_LINE_STRIP:
265       case GL_LINE_LOOP:
266          pass = ctx->TransformFeedback.Mode == GL_LINES;
267          break;
268       default:
269          pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
270          break;
271       }
272       if (!pass) {
273          _mesa_error(ctx, GL_INVALID_OPERATION,
274                      "%s(mode=%s vs transform feedback %s)",
275                      name,
276                      _mesa_lookup_prim_by_nr(mode),
277                      _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
278          return GL_FALSE;
279       }
280    }
281
282    return GL_TRUE;
283 }
284
285 /**
286  * Verify that the element type is valid.
287  *
288  * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
289  */
290 static bool
291 valid_elements_type(struct gl_context *ctx, GLenum type, const char *name)
292 {
293    switch (type) {
294    case GL_UNSIGNED_BYTE:
295    case GL_UNSIGNED_SHORT:
296    case GL_UNSIGNED_INT:
297       return true;
298
299    default:
300       _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name,
301                   _mesa_lookup_enum_by_nr(type));
302       return false;
303    }
304 }
305
306 /**
307  * Error checking for glDrawElements().  Includes parameter checking
308  * and VBO bounds checking.
309  * \return GL_TRUE if OK to render, GL_FALSE if error found
310  */
311 GLboolean
312 _mesa_validate_DrawElements(struct gl_context *ctx,
313                             GLenum mode, GLsizei count, GLenum type,
314                             const GLvoid *indices, GLint basevertex)
315 {
316    FLUSH_CURRENT(ctx, 0);
317
318    /* From the GLES3 specification, section 2.14.2 (Transform Feedback
319     * Primitive Capture):
320     *
321     *   The error INVALID_OPERATION is also generated by DrawElements,
322     *   DrawElementsInstanced, and DrawRangeElements while transform feedback
323     *   is active and not paused, regardless of mode.
324     */
325    if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
326       _mesa_error(ctx, GL_INVALID_OPERATION,
327                   "glDrawElements(transform feedback active)");
328       return GL_FALSE;
329    }
330
331    if (count <= 0) {
332       if (count < 0)
333          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
334       return GL_FALSE;
335    }
336
337    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) {
338       return GL_FALSE;
339    }
340
341    if (!valid_elements_type(ctx, type, "glDrawElements"))
342       return GL_FALSE;
343
344    if (!check_valid_to_render(ctx, "glDrawElements"))
345       return GL_FALSE;
346
347    /* Vertex buffer object tests */
348    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
349       /* use indices in the buffer object */
350       /* make sure count doesn't go outside buffer bounds */
351       if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
352          _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
353          return GL_FALSE;
354       }
355    }
356    else {
357       /* not using a VBO */
358       if (!indices)
359          return GL_FALSE;
360    }
361
362    if (!check_index_bounds(ctx, count, type, indices, basevertex))
363       return GL_FALSE;
364
365    return GL_TRUE;
366 }
367
368
369 /**
370  * Error checking for glMultiDrawElements().  Includes parameter checking
371  * and VBO bounds checking.
372  * \return GL_TRUE if OK to render, GL_FALSE if error found
373  */
374 GLboolean
375 _mesa_validate_MultiDrawElements(struct gl_context *ctx,
376                                  GLenum mode, const GLsizei *count,
377                                  GLenum type, const GLvoid * const *indices,
378                                  GLuint primcount, const GLint *basevertex)
379 {
380    unsigned i;
381
382    FLUSH_CURRENT(ctx, 0);
383
384    for (i = 0; i < primcount; i++) {
385       if (count[i] <= 0) {
386          if (count[i] < 0)
387             _mesa_error(ctx, GL_INVALID_VALUE,
388                         "glMultiDrawElements(count)" );
389          return GL_FALSE;
390       }
391    }
392
393    if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) {
394       return GL_FALSE;
395    }
396
397    if (!valid_elements_type(ctx, type, "glMultiDrawElements"))
398       return GL_FALSE;
399
400    if (!check_valid_to_render(ctx, "glMultiDrawElements"))
401       return GL_FALSE;
402
403    /* Vertex buffer object tests */
404    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
405       /* use indices in the buffer object */
406       /* make sure count doesn't go outside buffer bounds */
407       for (i = 0; i < primcount; i++) {
408          if (index_bytes(type, count[i]) >
409              ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
410             _mesa_warning(ctx,
411                           "glMultiDrawElements index out of buffer bounds");
412             return GL_FALSE;
413          }
414       }
415    }
416    else {
417       /* not using a VBO */
418       for (i = 0; i < primcount; i++) {
419          if (!indices[i])
420             return GL_FALSE;
421       }
422    }
423
424    for (i = 0; i < primcount; i++) {
425       if (!check_index_bounds(ctx, count[i], type, indices[i],
426                               basevertex ? basevertex[i] : 0))
427          return GL_FALSE;
428    }
429
430    return GL_TRUE;
431 }
432
433
434 /**
435  * Error checking for glDrawRangeElements().  Includes parameter checking
436  * and VBO bounds checking.
437  * \return GL_TRUE if OK to render, GL_FALSE if error found
438  */
439 GLboolean
440 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
441                                  GLuint start, GLuint end,
442                                  GLsizei count, GLenum type,
443                                  const GLvoid *indices, GLint basevertex)
444 {
445    FLUSH_CURRENT(ctx, 0);
446
447    /* From the GLES3 specification, section 2.14.2 (Transform Feedback
448     * Primitive Capture):
449     *
450     *   The error INVALID_OPERATION is also generated by DrawElements,
451     *   DrawElementsInstanced, and DrawRangeElements while transform feedback
452     *   is active and not paused, regardless of mode.
453     */
454    if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
455       _mesa_error(ctx, GL_INVALID_OPERATION,
456                   "glDrawElements(transform feedback active)");
457       return GL_FALSE;
458    }
459
460    if (count <= 0) {
461       if (count < 0)
462          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
463       return GL_FALSE;
464    }
465
466    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) {
467       return GL_FALSE;
468    }
469
470    if (end < start) {
471       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
472       return GL_FALSE;
473    }
474
475    if (!valid_elements_type(ctx, type, "glDrawRangeElements"))
476       return GL_FALSE;
477
478    if (!check_valid_to_render(ctx, "glDrawRangeElements"))
479       return GL_FALSE;
480
481    /* Vertex buffer object tests */
482    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
483       /* use indices in the buffer object */
484       /* make sure count doesn't go outside buffer bounds */
485       if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
486          _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
487          return GL_FALSE;
488       }
489    }
490    else {
491       /* not using a VBO */
492       if (!indices)
493          return GL_FALSE;
494    }
495
496    if (!check_index_bounds(ctx, count, type, indices, basevertex))
497       return GL_FALSE;
498
499    return GL_TRUE;
500 }
501
502
503 /**
504  * Called from the tnl module to error check the function parameters and
505  * verify that we really can draw something.
506  * \return GL_TRUE if OK to render, GL_FALSE if error found
507  */
508 GLboolean
509 _mesa_validate_DrawArrays(struct gl_context *ctx,
510                           GLenum mode, GLint start, GLsizei count)
511 {
512    struct gl_transform_feedback_object *xfb_obj
513       = ctx->TransformFeedback.CurrentObject;
514    FLUSH_CURRENT(ctx, 0);
515
516    if (count <= 0) {
517       if (count < 0)
518          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
519       return GL_FALSE;
520    }
521
522    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
523       return GL_FALSE;
524    }
525
526    if (!check_valid_to_render(ctx, "glDrawArrays"))
527       return GL_FALSE;
528
529    if (ctx->Const.CheckArrayBounds) {
530       if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
531          return GL_FALSE;
532    }
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    return GL_TRUE;
558 }
559
560
561 GLboolean
562 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
563                                    GLsizei count, GLsizei numInstances)
564 {
565    struct gl_transform_feedback_object *xfb_obj
566       = ctx->TransformFeedback.CurrentObject;
567    FLUSH_CURRENT(ctx, 0);
568
569    if (count <= 0) {
570       if (count < 0)
571          _mesa_error(ctx, GL_INVALID_VALUE,
572                      "glDrawArraysInstanced(count=%d)", count);
573       return GL_FALSE;
574    }
575
576    if (first < 0) {
577       _mesa_error(ctx, GL_INVALID_VALUE,
578                   "glDrawArraysInstanced(start=%d)", first);
579       return GL_FALSE;
580    }
581
582    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
583       return GL_FALSE;
584    }
585
586    if (numInstances <= 0) {
587       if (numInstances < 0)
588          _mesa_error(ctx, GL_INVALID_VALUE,
589                      "glDrawArraysInstanced(numInstances=%d)", numInstances);
590       return GL_FALSE;
591    }
592
593    if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
594       return GL_FALSE;
595
596    if (ctx->Const.CheckArrayBounds) {
597       if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
598          return GL_FALSE;
599    }
600
601    /* From the GLES3 specification, section 2.14.2 (Transform Feedback
602     * Primitive Capture):
603     *
604     *   The error INVALID_OPERATION is generated by DrawArrays and
605     *   DrawArraysInstanced if recording the vertices of a primitive to the
606     *   buffer objects being used for transform feedback purposes would result
607     *   in either exceeding the limits of any buffer object’s size, or in
608     *   exceeding the end position offset + size − 1, as set by
609     *   BindBufferRange.
610     *
611     * This is in contrast to the behaviour of desktop GL, where the extra
612     * primitives are silently dropped from the transform feedback buffer.
613     */
614    if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
615       size_t prim_count
616          = vbo_count_tessellated_primitives(mode, count, numInstances);
617       if (xfb_obj->GlesRemainingPrims < prim_count) {
618          _mesa_error(ctx, GL_INVALID_OPERATION,
619                      "glDrawArraysInstanced(exceeds transform feedback size)");
620          return GL_FALSE;
621       }
622       xfb_obj->GlesRemainingPrims -= prim_count;
623    }
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       if (count < 0)
652          _mesa_error(ctx, GL_INVALID_VALUE,
653                      "glDrawElementsInstanced(count=%d)", count);
654       return GL_FALSE;
655    }
656
657    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) {
658       return GL_FALSE;
659    }
660
661    if (!valid_elements_type(ctx, type, "glDrawElementsInstanced"))
662       return GL_FALSE;
663
664    if (numInstances <= 0) {
665       if (numInstances < 0)
666          _mesa_error(ctx, GL_INVALID_VALUE,
667                      "glDrawElementsInstanced(numInstances=%d)", numInstances);
668       return GL_FALSE;
669    }
670
671    if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
672       return GL_FALSE;
673
674    /* Vertex buffer object tests */
675    if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
676       /* use indices in the buffer object */
677       /* make sure count doesn't go outside buffer bounds */
678       if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
679          _mesa_warning(ctx,
680                        "glDrawElementsInstanced index out of buffer bounds");
681          return GL_FALSE;
682       }
683    }
684    else {
685       /* not using a VBO */
686       if (!indices)
687          return GL_FALSE;
688    }
689
690    if (!check_index_bounds(ctx, count, type, indices, basevertex))
691       return GL_FALSE;
692
693    return GL_TRUE;
694 }
695
696
697 GLboolean
698 _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
699                                      GLenum mode,
700                                      struct gl_transform_feedback_object *obj,
701                                      GLuint stream,
702                                      GLsizei numInstances)
703 {
704    FLUSH_CURRENT(ctx, 0);
705
706    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) {
707       return GL_FALSE;
708    }
709
710    if (!obj) {
711       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
712       return GL_FALSE;
713    }
714
715    if (!obj->EndedAnytime) {
716       _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
717       return GL_FALSE;
718    }
719
720    if (stream >= ctx->Const.MaxVertexStreams) {
721       _mesa_error(ctx, GL_INVALID_VALUE,
722                   "glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
723       return GL_FALSE;
724    }
725
726    if (numInstances <= 0) {
727       if (numInstances < 0)
728          _mesa_error(ctx, GL_INVALID_VALUE,
729                      "glDrawTransformFeedback*Instanced(numInstances=%d)",
730                      numInstances);
731       return GL_FALSE;
732    }
733
734    if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) {
735       return GL_FALSE;
736    }
737
738    return GL_TRUE;
739 }