Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. #include <stdbool.h>
  26. #include "glheader.h"
  27. #include "api_validate.h"
  28. #include "bufferobj.h"
  29. #include "context.h"
  30. #include "imports.h"
  31. #include "mtypes.h"
  32. #include "enums.h"
  33. #include "vbo/vbo.h"
  34. #include "transformfeedback.h"
  35. #include <stdbool.h>
  36.  
  37.  
  38. /**
  39.  * Check if OK to draw arrays/elements.
  40.  */
  41. static bool
  42. check_valid_to_render(struct gl_context *ctx, const char *function)
  43. {
  44.    if (!_mesa_valid_to_render(ctx, function)) {
  45.       return false;
  46.    }
  47.  
  48.    switch (ctx->API) {
  49.    case API_OPENGLES2:
  50.       /* For ES2, we can draw if we have a vertex program/shader). */
  51.       return ctx->VertexProgram._Current != NULL;
  52.  
  53.    case API_OPENGLES:
  54.       /* For OpenGL ES, only draw if we have vertex positions
  55.        */
  56.       if (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
  57.          return false;
  58.       break;
  59.  
  60.    case API_OPENGL_CORE:
  61.       /* Section 10.4 (Drawing Commands Using Vertex Arrays) of the OpenGL 4.5
  62.        * Core Profile spec says:
  63.        *
  64.        *     "An INVALID_OPERATION error is generated if no vertex array
  65.        *     object is bound (see section 10.3.1)."
  66.        */
  67.       if (ctx->Array.VAO == ctx->Array.DefaultVAO) {
  68.          _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no VAO bound)", function);
  69.          return false;
  70.       }
  71.  
  72.       /* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec
  73.        * says:
  74.        *
  75.        *     "If there is no active program for the vertex or fragment shader
  76.        *     stages, the results of vertex and/or fragment processing will be
  77.        *     undefined. However, this is not an error."
  78.        *
  79.        * The fragment shader is not tested here because other state (e.g.,
  80.        * GL_RASTERIZER_DISCARD) affects whether or not we actually care.
  81.        */
  82.       return ctx->VertexProgram._Current != NULL;
  83.  
  84.    case API_OPENGL_COMPAT:
  85.       if (ctx->VertexProgram._Current != NULL) {
  86.          /* Draw regardless of whether or not we have any vertex arrays.
  87.           * (Ex: could draw a point using a constant vertex pos)
  88.           */
  89.          return true;
  90.       } else {
  91.          /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
  92.           * array [0]).
  93.           */
  94.          return (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
  95.                  ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
  96.       }
  97.       break;
  98.  
  99.    default:
  100.       unreachable("Invalid API value in check_valid_to_render()");
  101.    }
  102.  
  103.    return true;
  104. }
  105.  
  106.  
  107. /**
  108.  * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
  109.  * etc?  The set of legal values depends on whether geometry shaders/programs
  110.  * are supported.
  111.  * Note: This may be called during display list compilation.
  112.  */
  113. bool
  114. _mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode)
  115. {
  116.    /* The overwhelmingly common case is (mode <= GL_TRIANGLE_FAN).  Test that
  117.     * first and exit.  You would think that a switch-statement would be the
  118.     * right approach, but at least GCC 4.7.2 generates some pretty dire code
  119.     * for the common case.
  120.     */
  121.    if (likely(mode <= GL_TRIANGLE_FAN))
  122.       return true;
  123.  
  124.    if (mode <= GL_POLYGON)
  125.       return (ctx->API == API_OPENGL_COMPAT);
  126.  
  127.    if (mode <= GL_TRIANGLE_STRIP_ADJACENCY)
  128.       return _mesa_has_geometry_shaders(ctx);
  129.  
  130.    return false;
  131. }
  132.  
  133.  
  134. /**
  135.  * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
  136.  * etc?  Also, do additional checking related to transformation feedback.
  137.  * Note: this function cannot be called during glNewList(GL_COMPILE) because
  138.  * this code depends on current transform feedback state.
  139.  */
  140. GLboolean
  141. _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
  142. {
  143.    bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode);
  144.  
  145.    if (!valid_enum) {
  146.       _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
  147.       return GL_FALSE;
  148.    }
  149.  
  150.    /* From the ARB_geometry_shader4 spec:
  151.     *
  152.     * The error INVALID_OPERATION is generated if Begin, or any command that
  153.     * implicitly calls Begin, is called when a geometry shader is active and:
  154.     *
  155.     * * the input primitive type of the current geometry shader is
  156.     *   POINTS and <mode> is not POINTS,
  157.     *
  158.     * * the input primitive type of the current geometry shader is
  159.     *   LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP,
  160.     *
  161.     * * the input primitive type of the current geometry shader is
  162.     *   TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or
  163.     *   TRIANGLE_FAN,
  164.     *
  165.     * * the input primitive type of the current geometry shader is
  166.     *   LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or
  167.     *   LINE_STRIP_ADJACENCY_ARB, or
  168.     *
  169.     * * the input primitive type of the current geometry shader is
  170.     *   TRIANGLES_ADJACENCY_ARB and <mode> is not
  171.     *   TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
  172.     *
  173.    */
  174.    if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
  175.       const GLenum geom_mode =
  176.          ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
  177.       switch (mode) {
  178.       case GL_POINTS:
  179.          valid_enum = (geom_mode == GL_POINTS);
  180.          break;
  181.       case GL_LINES:
  182.       case GL_LINE_LOOP:
  183.       case GL_LINE_STRIP:
  184.          valid_enum = (geom_mode == GL_LINES);
  185.          break;
  186.       case GL_TRIANGLES:
  187.       case GL_TRIANGLE_STRIP:
  188.       case GL_TRIANGLE_FAN:
  189.          valid_enum = (geom_mode == GL_TRIANGLES);
  190.          break;
  191.       case GL_QUADS:
  192.       case GL_QUAD_STRIP:
  193.       case GL_POLYGON:
  194.          valid_enum = false;
  195.          break;
  196.       case GL_LINES_ADJACENCY:
  197.       case GL_LINE_STRIP_ADJACENCY:
  198.          valid_enum = (geom_mode == GL_LINES_ADJACENCY);
  199.          break;
  200.       case GL_TRIANGLES_ADJACENCY:
  201.       case GL_TRIANGLE_STRIP_ADJACENCY:
  202.          valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY);
  203.          break;
  204.       default:
  205.          valid_enum = false;
  206.          break;
  207.       }
  208.       if (!valid_enum) {
  209.          _mesa_error(ctx, GL_INVALID_OPERATION,
  210.                      "%s(mode=%s vs geometry shader input %s)",
  211.                      name,
  212.                      _mesa_lookup_prim_by_nr(mode),
  213.                      _mesa_lookup_prim_by_nr(geom_mode));
  214.          return GL_FALSE;
  215.       }
  216.    }
  217.  
  218.    /* From the GL_EXT_transform_feedback spec:
  219.     *
  220.     *     "The error INVALID_OPERATION is generated if Begin, or any command
  221.     *      that performs an explicit Begin, is called when:
  222.     *
  223.     *      * a geometry shader is not active and <mode> does not match the
  224.     *        allowed begin modes for the current transform feedback state as
  225.     *        given by table X.1.
  226.     *
  227.     *      * a geometry shader is active and the output primitive type of the
  228.     *        geometry shader does not match the allowed begin modes for the
  229.     *        current transform feedback state as given by table X.1.
  230.     *
  231.     */
  232.    if (_mesa_is_xfb_active_and_unpaused(ctx)) {
  233.       GLboolean pass = GL_TRUE;
  234.  
  235.       if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
  236.          switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
  237.          case GL_POINTS:
  238.             pass = ctx->TransformFeedback.Mode == GL_POINTS;
  239.             break;
  240.          case GL_LINE_STRIP:
  241.             pass = ctx->TransformFeedback.Mode == GL_LINES;
  242.             break;
  243.          case GL_TRIANGLE_STRIP:
  244.             pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
  245.             break;
  246.          default:
  247.             pass = GL_FALSE;
  248.          }
  249.       }
  250.       else {
  251.          switch (mode) {
  252.          case GL_POINTS:
  253.             pass = ctx->TransformFeedback.Mode == GL_POINTS;
  254.             break;
  255.          case GL_LINES:
  256.          case GL_LINE_STRIP:
  257.          case GL_LINE_LOOP:
  258.             pass = ctx->TransformFeedback.Mode == GL_LINES;
  259.             break;
  260.          default:
  261.             pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
  262.             break;
  263.          }
  264.       }
  265.       if (!pass) {
  266.          _mesa_error(ctx, GL_INVALID_OPERATION,
  267.                          "%s(mode=%s vs transform feedback %s)",
  268.                          name,
  269.                          _mesa_lookup_prim_by_nr(mode),
  270.                          _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
  271.          return GL_FALSE;
  272.       }
  273.    }
  274.  
  275.    return GL_TRUE;
  276. }
  277.  
  278. /**
  279.  * Verify that the element type is valid.
  280.  *
  281.  * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
  282.  */
  283. static bool
  284. valid_elements_type(struct gl_context *ctx, GLenum type, const char *name)
  285. {
  286.    switch (type) {
  287.    case GL_UNSIGNED_BYTE:
  288.    case GL_UNSIGNED_SHORT:
  289.    case GL_UNSIGNED_INT:
  290.       return true;
  291.  
  292.    default:
  293.       _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name,
  294.                   _mesa_lookup_enum_by_nr(type));
  295.       return false;
  296.    }
  297. }
  298.  
  299. static bool
  300. validate_DrawElements_common(struct gl_context *ctx,
  301.                              GLenum mode, GLsizei count, GLenum type,
  302.                              const GLvoid *indices,
  303.                              const char *caller)
  304. {
  305.    /* From the GLES3 specification, section 2.14.2 (Transform Feedback
  306.     * Primitive Capture):
  307.     *
  308.     *   The error INVALID_OPERATION is also generated by DrawElements,
  309.     *   DrawElementsInstanced, and DrawRangeElements while transform feedback
  310.     *   is active and not paused, regardless of mode.
  311.     */
  312.    if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
  313.       _mesa_error(ctx, GL_INVALID_OPERATION,
  314.                   "%s(transform feedback active)", caller);
  315.       return false;
  316.    }
  317.  
  318.    if (count < 0) {
  319.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller);
  320.       return false;
  321.    }
  322.  
  323.    if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
  324.       return false;
  325.    }
  326.  
  327.    if (!valid_elements_type(ctx, type, caller))
  328.       return false;
  329.  
  330.    if (!check_valid_to_render(ctx, caller))
  331.       return false;
  332.  
  333.    /* Not using a VBO for indices, so avoid NULL pointer derefs later.
  334.     */
  335.    if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
  336.       return false;
  337.  
  338.    if (count == 0)
  339.       return false;
  340.  
  341.    return true;
  342. }
  343.  
  344. /**
  345.  * Error checking for glDrawElements().  Includes parameter checking
  346.  * and VBO bounds checking.
  347.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  348.  */
  349. GLboolean
  350. _mesa_validate_DrawElements(struct gl_context *ctx,
  351.                             GLenum mode, GLsizei count, GLenum type,
  352.                             const GLvoid *indices)
  353. {
  354.    FLUSH_CURRENT(ctx, 0);
  355.  
  356.    return validate_DrawElements_common(ctx, mode, count, type, indices,
  357.                                        "glDrawElements");
  358. }
  359.  
  360.  
  361. /**
  362.  * Error checking for glMultiDrawElements().  Includes parameter checking
  363.  * and VBO bounds checking.
  364.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  365.  */
  366. GLboolean
  367. _mesa_validate_MultiDrawElements(struct gl_context *ctx,
  368.                                  GLenum mode, const GLsizei *count,
  369.                                  GLenum type, const GLvoid * const *indices,
  370.                                  GLuint primcount)
  371. {
  372.    unsigned i;
  373.  
  374.    FLUSH_CURRENT(ctx, 0);
  375.  
  376.    for (i = 0; i < primcount; i++) {
  377.       if (count[i] < 0) {
  378.          _mesa_error(ctx, GL_INVALID_VALUE,
  379.                      "glMultiDrawElements(count)" );
  380.          return GL_FALSE;
  381.       }
  382.    }
  383.  
  384.    if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) {
  385.       return GL_FALSE;
  386.    }
  387.  
  388.    if (!valid_elements_type(ctx, type, "glMultiDrawElements"))
  389.       return GL_FALSE;
  390.  
  391.    if (!check_valid_to_render(ctx, "glMultiDrawElements"))
  392.       return GL_FALSE;
  393.  
  394.    /* Not using a VBO for indices, so avoid NULL pointer derefs later.
  395.     */
  396.    if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
  397.       for (i = 0; i < primcount; i++) {
  398.          if (!indices[i])
  399.             return GL_FALSE;
  400.       }
  401.    }
  402.  
  403.    return GL_TRUE;
  404. }
  405.  
  406.  
  407. /**
  408.  * Error checking for glDrawRangeElements().  Includes parameter checking
  409.  * and VBO bounds checking.
  410.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  411.  */
  412. GLboolean
  413. _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
  414.                                  GLuint start, GLuint end,
  415.                                  GLsizei count, GLenum type,
  416.                                  const GLvoid *indices)
  417. {
  418.    FLUSH_CURRENT(ctx, 0);
  419.  
  420.    if (end < start) {
  421.       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
  422.       return GL_FALSE;
  423.    }
  424.  
  425.    return validate_DrawElements_common(ctx, mode, count, type, indices,
  426.                                        "glDrawRangeElements");
  427. }
  428.  
  429.  
  430. /**
  431.  * Called from the tnl module to error check the function parameters and
  432.  * verify that we really can draw something.
  433.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  434.  */
  435. GLboolean
  436. _mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLsizei count)
  437. {
  438.    struct gl_transform_feedback_object *xfb_obj
  439.       = ctx->TransformFeedback.CurrentObject;
  440.    FLUSH_CURRENT(ctx, 0);
  441.  
  442.    if (count < 0) {
  443.       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
  444.       return GL_FALSE;
  445.    }
  446.  
  447.    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
  448.       return GL_FALSE;
  449.    }
  450.  
  451.    if (!check_valid_to_render(ctx, "glDrawArrays"))
  452.       return GL_FALSE;
  453.  
  454.    /* From the GLES3 specification, section 2.14.2 (Transform Feedback
  455.     * Primitive Capture):
  456.     *
  457.     *   The error INVALID_OPERATION is generated by DrawArrays and
  458.     *   DrawArraysInstanced if recording the vertices of a primitive to the
  459.     *   buffer objects being used for transform feedback purposes would result
  460.     *   in either exceeding the limits of any buffer object’s size, or in
  461.     *   exceeding the end position offset + size − 1, as set by
  462.     *   BindBufferRange.
  463.     *
  464.     * This is in contrast to the behaviour of desktop GL, where the extra
  465.     * primitives are silently dropped from the transform feedback buffer.
  466.     */
  467.    if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
  468.       size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
  469.       if (xfb_obj->GlesRemainingPrims < prim_count) {
  470.          _mesa_error(ctx, GL_INVALID_OPERATION,
  471.                      "glDrawArrays(exceeds transform feedback size)");
  472.          return GL_FALSE;
  473.       }
  474.       xfb_obj->GlesRemainingPrims -= prim_count;
  475.    }
  476.  
  477.    if (count == 0)
  478.       return GL_FALSE;
  479.  
  480.    return GL_TRUE;
  481. }
  482.  
  483.  
  484. GLboolean
  485. _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
  486.                                    GLsizei count, GLsizei numInstances)
  487. {
  488.    struct gl_transform_feedback_object *xfb_obj
  489.       = ctx->TransformFeedback.CurrentObject;
  490.    FLUSH_CURRENT(ctx, 0);
  491.  
  492.    if (count < 0) {
  493.       _mesa_error(ctx, GL_INVALID_VALUE,
  494.                   "glDrawArraysInstanced(count=%d)", count);
  495.       return GL_FALSE;
  496.    }
  497.  
  498.    if (first < 0) {
  499.       _mesa_error(ctx, GL_INVALID_VALUE,
  500.                   "glDrawArraysInstanced(start=%d)", first);
  501.       return GL_FALSE;
  502.    }
  503.  
  504.    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
  505.       return GL_FALSE;
  506.    }
  507.  
  508.    if (numInstances <= 0) {
  509.       if (numInstances < 0)
  510.          _mesa_error(ctx, GL_INVALID_VALUE,
  511.                      "glDrawArraysInstanced(numInstances=%d)", numInstances);
  512.       return GL_FALSE;
  513.    }
  514.  
  515.    if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
  516.       return GL_FALSE;
  517.  
  518.    /* From the GLES3 specification, section 2.14.2 (Transform Feedback
  519.     * Primitive Capture):
  520.     *
  521.     *   The error INVALID_OPERATION is generated by DrawArrays and
  522.     *   DrawArraysInstanced if recording the vertices of a primitive to the
  523.     *   buffer objects being used for transform feedback purposes would result
  524.     *   in either exceeding the limits of any buffer object’s size, or in
  525.     *   exceeding the end position offset + size − 1, as set by
  526.     *   BindBufferRange.
  527.     *
  528.     * This is in contrast to the behaviour of desktop GL, where the extra
  529.     * primitives are silently dropped from the transform feedback buffer.
  530.     */
  531.    if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
  532.       size_t prim_count
  533.          = vbo_count_tessellated_primitives(mode, count, numInstances);
  534.       if (xfb_obj->GlesRemainingPrims < prim_count) {
  535.          _mesa_error(ctx, GL_INVALID_OPERATION,
  536.                      "glDrawArraysInstanced(exceeds transform feedback size)");
  537.          return GL_FALSE;
  538.       }
  539.       xfb_obj->GlesRemainingPrims -= prim_count;
  540.    }
  541.  
  542.    if (count == 0)
  543.       return GL_FALSE;
  544.  
  545.    return GL_TRUE;
  546. }
  547.  
  548.  
  549. GLboolean
  550. _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
  551.                                      GLenum mode, GLsizei count, GLenum type,
  552.                                      const GLvoid *indices, GLsizei numInstances)
  553. {
  554.    FLUSH_CURRENT(ctx, 0);
  555.  
  556.    if (numInstances < 0) {
  557.       _mesa_error(ctx, GL_INVALID_VALUE,
  558.                   "glDrawElementsInstanced(numInstances=%d)", numInstances);
  559.       return GL_FALSE;
  560.    }
  561.  
  562.    return validate_DrawElements_common(ctx, mode, count, type, indices,
  563.                                        "glDrawElementsInstanced")
  564.       && (numInstances > 0);
  565. }
  566.  
  567.  
  568. GLboolean
  569. _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
  570.                                      GLenum mode,
  571.                                      struct gl_transform_feedback_object *obj,
  572.                                      GLuint stream,
  573.                                      GLsizei numInstances)
  574. {
  575.    FLUSH_CURRENT(ctx, 0);
  576.  
  577.    if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) {
  578.       return GL_FALSE;
  579.    }
  580.  
  581.    if (!obj) {
  582.       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
  583.       return GL_FALSE;
  584.    }
  585.  
  586.    if (stream >= ctx->Const.MaxVertexStreams) {
  587.       _mesa_error(ctx, GL_INVALID_VALUE,
  588.                   "glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
  589.       return GL_FALSE;
  590.    }
  591.  
  592.    if (!obj->EndedAnytime) {
  593.       _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
  594.       return GL_FALSE;
  595.    }
  596.  
  597.    if (numInstances <= 0) {
  598.       if (numInstances < 0)
  599.          _mesa_error(ctx, GL_INVALID_VALUE,
  600.                      "glDrawTransformFeedback*Instanced(numInstances=%d)",
  601.                      numInstances);
  602.       return GL_FALSE;
  603.    }
  604.  
  605.    if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) {
  606.       return GL_FALSE;
  607.    }
  608.  
  609.    return GL_TRUE;
  610. }
  611.  
  612. static GLboolean
  613. valid_draw_indirect(struct gl_context *ctx,
  614.                     GLenum mode, const GLvoid *indirect,
  615.                     GLsizei size, const char *name)
  616. {
  617.    const GLsizeiptr end = (GLsizeiptr)indirect + size;
  618.  
  619.    if (!_mesa_valid_prim_mode(ctx, mode, name))
  620.       return GL_FALSE;
  621.  
  622.  
  623.    /* From the ARB_draw_indirect specification:
  624.     * "An INVALID_OPERATION error is generated [...] if <indirect> is no
  625.     *  word aligned."
  626.     */
  627.    if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) {
  628.       _mesa_error(ctx, GL_INVALID_OPERATION,
  629.                   "%s(indirect is not aligned)", name);
  630.       return GL_FALSE;
  631.    }
  632.  
  633.    if (!_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
  634.       _mesa_error(ctx, GL_INVALID_OPERATION,
  635.                   "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);
  636.       return GL_FALSE;
  637.    }
  638.  
  639.    if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) {
  640.       _mesa_error(ctx, GL_INVALID_OPERATION,
  641.                   "%s(DRAW_INDIRECT_BUFFER is mapped)", name);
  642.       return GL_FALSE;
  643.    }
  644.  
  645.    /* From the ARB_draw_indirect specification:
  646.     * "An INVALID_OPERATION error is generated if the commands source data
  647.     *  beyond the end of the buffer object [...]"
  648.     */
  649.    if (ctx->DrawIndirectBuffer->Size < end) {
  650.       _mesa_error(ctx, GL_INVALID_OPERATION,
  651.                   "%s(DRAW_INDIRECT_BUFFER too small)", name);
  652.       return GL_FALSE;
  653.    }
  654.  
  655.    if (!check_valid_to_render(ctx, name))
  656.       return GL_FALSE;
  657.  
  658.    return GL_TRUE;
  659. }
  660.  
  661. static inline GLboolean
  662. valid_draw_indirect_elements(struct gl_context *ctx,
  663.                              GLenum mode, GLenum type, const GLvoid *indirect,
  664.                              GLsizeiptr size, const char *name)
  665. {
  666.    if (!valid_elements_type(ctx, type, name))
  667.       return GL_FALSE;
  668.  
  669.    /*
  670.     * Unlike regular DrawElementsInstancedBaseVertex commands, the indices
  671.     * may not come from a client array and must come from an index buffer.
  672.     * If no element array buffer is bound, an INVALID_OPERATION error is
  673.     * generated.
  674.     */
  675.    if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
  676.       _mesa_error(ctx, GL_INVALID_OPERATION,
  677.                   "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name);
  678.       return GL_FALSE;
  679.    }
  680.  
  681.    return valid_draw_indirect(ctx, mode, indirect, size, name);
  682. }
  683.  
  684. static inline GLboolean
  685. valid_draw_indirect_multi(struct gl_context *ctx,
  686.                           GLsizei primcount, GLsizei stride,
  687.                           const char *name)
  688. {
  689.  
  690.    /* From the ARB_multi_draw_indirect specification:
  691.     * "INVALID_VALUE is generated by MultiDrawArraysIndirect or
  692.     *  MultiDrawElementsIndirect if <primcount> is negative."
  693.     *
  694.     * "<primcount> must be positive, otherwise an INVALID_VALUE error will
  695.     *  be generated."
  696.     */
  697.    if (primcount < 0) {
  698.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name);
  699.       return GL_FALSE;
  700.    }
  701.  
  702.  
  703.    /* From the ARB_multi_draw_indirect specification:
  704.     * "<stride> must be a multiple of four, otherwise an INVALID_VALUE
  705.     *  error is generated."
  706.     */
  707.    if (stride % 4) {
  708.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name);
  709.       return GL_FALSE;
  710.    }
  711.  
  712.    return GL_TRUE;
  713. }
  714.  
  715. GLboolean
  716. _mesa_validate_DrawArraysIndirect(struct gl_context *ctx,
  717.                                   GLenum mode,
  718.                                   const GLvoid *indirect)
  719. {
  720.    const unsigned drawArraysNumParams = 4;
  721.  
  722.    FLUSH_CURRENT(ctx, 0);
  723.  
  724.    return valid_draw_indirect(ctx, mode,
  725.                               indirect, drawArraysNumParams * sizeof(GLuint),
  726.                               "glDrawArraysIndirect");
  727. }
  728.  
  729. GLboolean
  730. _mesa_validate_DrawElementsIndirect(struct gl_context *ctx,
  731.                                     GLenum mode, GLenum type,
  732.                                     const GLvoid *indirect)
  733. {
  734.    const unsigned drawElementsNumParams = 5;
  735.  
  736.    FLUSH_CURRENT(ctx, 0);
  737.  
  738.    return valid_draw_indirect_elements(ctx, mode, type,
  739.                                        indirect, drawElementsNumParams * sizeof(GLuint),
  740.                                        "glDrawElementsIndirect");
  741. }
  742.  
  743. GLboolean
  744. _mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx,
  745.                                        GLenum mode,
  746.                                        const GLvoid *indirect,
  747.                                        GLsizei primcount, GLsizei stride)
  748. {
  749.    GLsizeiptr size = 0;
  750.    const unsigned drawArraysNumParams = 4;
  751.  
  752.    FLUSH_CURRENT(ctx, 0);
  753.  
  754.    /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */
  755.    assert(stride != 0);
  756.  
  757.    if (!valid_draw_indirect_multi(ctx, primcount, stride,
  758.                                   "glMultiDrawArraysIndirect"))
  759.       return GL_FALSE;
  760.  
  761.    /* number of bytes of the indirect buffer which will be read */
  762.    size = primcount
  763.       ? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint)
  764.       : 0;
  765.  
  766.    if (!valid_draw_indirect(ctx, mode, indirect, size,
  767.                             "glMultiDrawArraysIndirect"))
  768.       return GL_FALSE;
  769.  
  770.    return GL_TRUE;
  771. }
  772.  
  773. GLboolean
  774. _mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx,
  775.                                          GLenum mode, GLenum type,
  776.                                          const GLvoid *indirect,
  777.                                          GLsizei primcount, GLsizei stride)
  778. {
  779.    GLsizeiptr size = 0;
  780.    const unsigned drawElementsNumParams = 5;
  781.  
  782.    FLUSH_CURRENT(ctx, 0);
  783.  
  784.    /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */
  785.    assert(stride != 0);
  786.  
  787.    if (!valid_draw_indirect_multi(ctx, primcount, stride,
  788.                                   "glMultiDrawElementsIndirect"))
  789.       return GL_FALSE;
  790.  
  791.    /* number of bytes of the indirect buffer which will be read */
  792.    size = primcount
  793.       ? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint)
  794.       : 0;
  795.  
  796.    if (!valid_draw_indirect_elements(ctx, mode, type,
  797.                                      indirect, size,
  798.                                      "glMultiDrawElementsIndirect"))
  799.       return GL_FALSE;
  800.  
  801.    return GL_TRUE;
  802. }
  803.