Home | History | Annotate | Download | only in main
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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