Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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 "glheader.h"
  26. #include "api_validate.h"
  27. #include "bufferobj.h"
  28. #include "context.h"
  29. #include "imports.h"
  30. #include "mfeatures.h"
  31. #include "mtypes.h"
  32. #include "vbo/vbo.h"
  33.  
  34.  
  35. /**
  36.  * \return  number of bytes in array [count] of type.
  37.  */
  38. static GLsizei
  39. index_bytes(GLenum type, GLsizei count)
  40. {
  41.    if (type == GL_UNSIGNED_INT) {
  42.       return count * sizeof(GLuint);
  43.    }
  44.    else if (type == GL_UNSIGNED_BYTE) {
  45.       return count * sizeof(GLubyte);
  46.    }
  47.    else {
  48.       ASSERT(type == GL_UNSIGNED_SHORT);
  49.       return count * sizeof(GLushort);
  50.    }
  51. }
  52.  
  53.  
  54. /**
  55.  * Find the max index in the given element/index buffer
  56.  */
  57. GLuint
  58. _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type,
  59.                        const void *indices,
  60.                        struct gl_buffer_object *elementBuf)
  61. {
  62.    const GLubyte *map = NULL;
  63.    GLuint max = 0;
  64.    GLuint i;
  65.  
  66.    if (_mesa_is_bufferobj(elementBuf)) {
  67.       /* elements are in a user-defined buffer object.  need to map it */
  68.       map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER,
  69.                                   GL_READ_ONLY, elementBuf);
  70.       /* Actual address is the sum of pointers */
  71.       indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
  72.    }
  73.  
  74.    if (type == GL_UNSIGNED_INT) {
  75.       for (i = 0; i < count; i++)
  76.          if (((GLuint *) indices)[i] > max)
  77.             max = ((GLuint *) indices)[i];
  78.    }
  79.    else if (type == GL_UNSIGNED_SHORT) {
  80.       for (i = 0; i < count; i++)
  81.          if (((GLushort *) indices)[i] > max)
  82.             max = ((GLushort *) indices)[i];
  83.    }
  84.    else {
  85.       ASSERT(type == GL_UNSIGNED_BYTE);
  86.       for (i = 0; i < count; i++)
  87.          if (((GLubyte *) indices)[i] > max)
  88.             max = ((GLubyte *) indices)[i];
  89.    }
  90.  
  91.    if (map) {
  92.       ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf);
  93.    }
  94.  
  95.    return max;
  96. }
  97.  
  98.  
  99. /**
  100.  * Check if OK to draw arrays/elements.
  101.  */
  102. static GLboolean
  103. check_valid_to_render(struct gl_context *ctx, const char *function)
  104. {
  105.    if (!_mesa_valid_to_render(ctx, function)) {
  106.       return GL_FALSE;
  107.    }
  108.  
  109.    switch (ctx->API) {
  110. #if FEATURE_es2_glsl
  111.    case API_OPENGLES2:
  112.       /* For ES2, we can draw if any vertex array is enabled (and we
  113.        * should always have a vertex program/shader). */
  114.       if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current)
  115.          return GL_FALSE;
  116.       break;
  117. #endif
  118.  
  119. #if FEATURE_ES1 || FEATURE_GL
  120.    case API_OPENGLES:
  121.    case API_OPENGL:
  122.       /* For regular OpenGL, only draw if we have vertex positions
  123.        * (regardless of whether or not we have a vertex program/shader). */
  124.       if (!ctx->Array.ArrayObj->Vertex.Enabled &&
  125.           !ctx->Array.ArrayObj->VertexAttrib[0].Enabled)
  126.          return GL_FALSE;
  127.       break;
  128. #endif
  129.  
  130.    default:
  131.       ASSERT_NO_FEATURE();
  132.    }
  133.  
  134.    return GL_TRUE;
  135. }
  136.  
  137.  
  138. /**
  139.  * Do bounds checking on array element indexes.  Check that the vertices
  140.  * pointed to by the indices don't lie outside buffer object bounds.
  141.  * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
  142.  */
  143. static GLboolean
  144. check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
  145.                    const GLvoid *indices, GLint basevertex)
  146. {
  147.    struct _mesa_prim prim;
  148.    struct _mesa_index_buffer ib;
  149.    GLuint min, max;
  150.  
  151.    /* Only the X Server needs to do this -- otherwise, accessing outside
  152.     * array/BO bounds allows application termination.
  153.     */
  154.    if (!ctx->Const.CheckArrayBounds)
  155.       return GL_TRUE;
  156.  
  157.    memset(&prim, 0, sizeof(prim));
  158.    prim.count = count;
  159.  
  160.    memset(&ib, 0, sizeof(ib));
  161.    ib.type = type;
  162.    ib.ptr = indices;
  163.    ib.obj = ctx->Array.ElementArrayBufferObj;
  164.  
  165.    vbo_get_minmax_index(ctx, &prim, &ib, &min, &max);
  166.  
  167.    if ((int)(min + basevertex) < 0 ||
  168.        max + basevertex > ctx->Array.ArrayObj->_MaxElement) {
  169.       /* the max element is out of bounds of one or more enabled arrays */
  170.       _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
  171.                     max, ctx->Array.ArrayObj->_MaxElement);
  172.       return GL_FALSE;
  173.    }
  174.  
  175.    return GL_TRUE;
  176. }
  177.  
  178.  
  179. /**
  180.  * Error checking for glDrawElements().  Includes parameter checking
  181.  * and VBO bounds checking.
  182.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  183.  */
  184. GLboolean
  185. _mesa_validate_DrawElements(struct gl_context *ctx,
  186.                             GLenum mode, GLsizei count, GLenum type,
  187.                             const GLvoid *indices, GLint basevertex)
  188. {
  189.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  190.  
  191.    if (count <= 0) {
  192.       if (count < 0)
  193.          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
  194.       return GL_FALSE;
  195.    }
  196.  
  197.    if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
  198.       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" );
  199.       return GL_FALSE;
  200.    }
  201.  
  202.    if (type != GL_UNSIGNED_INT &&
  203.        type != GL_UNSIGNED_BYTE &&
  204.        type != GL_UNSIGNED_SHORT)
  205.    {
  206.       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
  207.       return GL_FALSE;
  208.    }
  209.  
  210.    if (!check_valid_to_render(ctx, "glDrawElements"))
  211.       return GL_FALSE;
  212.  
  213.    /* Vertex buffer object tests */
  214.    if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
  215.       /* use indices in the buffer object */
  216.       /* make sure count doesn't go outside buffer bounds */
  217.       if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) {
  218.          _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
  219.          return GL_FALSE;
  220.       }
  221.    }
  222.    else {
  223.       /* not using a VBO */
  224.       if (!indices)
  225.          return GL_FALSE;
  226.    }
  227.  
  228.    if (!check_index_bounds(ctx, count, type, indices, basevertex))
  229.       return GL_FALSE;
  230.  
  231.    return GL_TRUE;
  232. }
  233.  
  234.  
  235. /**
  236.  * Error checking for glDrawRangeElements().  Includes parameter checking
  237.  * and VBO bounds checking.
  238.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  239.  */
  240. GLboolean
  241. _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
  242.                                  GLuint start, GLuint end,
  243.                                  GLsizei count, GLenum type,
  244.                                  const GLvoid *indices, GLint basevertex)
  245. {
  246.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  247.  
  248.    if (count <= 0) {
  249.       if (count < 0)
  250.          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
  251.       return GL_FALSE;
  252.    }
  253.  
  254.    if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
  255.       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" );
  256.       return GL_FALSE;
  257.    }
  258.  
  259.    if (end < start) {
  260.       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
  261.       return GL_FALSE;
  262.    }
  263.  
  264.    if (type != GL_UNSIGNED_INT &&
  265.        type != GL_UNSIGNED_BYTE &&
  266.        type != GL_UNSIGNED_SHORT) {
  267.       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" );
  268.       return GL_FALSE;
  269.    }
  270.  
  271.    if (!check_valid_to_render(ctx, "glDrawRangeElements"))
  272.       return GL_FALSE;
  273.  
  274.    /* Vertex buffer object tests */
  275.    if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
  276.       /* use indices in the buffer object */
  277.       /* make sure count doesn't go outside buffer bounds */
  278.       if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) {
  279.          _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
  280.          return GL_FALSE;
  281.       }
  282.    }
  283.    else {
  284.       /* not using a VBO */
  285.       if (!indices)
  286.          return GL_FALSE;
  287.    }
  288.  
  289.    if (!check_index_bounds(ctx, count, type, indices, basevertex))
  290.       return GL_FALSE;
  291.  
  292.    return GL_TRUE;
  293. }
  294.  
  295.  
  296. /**
  297.  * Called from the tnl module to error check the function parameters and
  298.  * verify that we really can draw something.
  299.  * \return GL_TRUE if OK to render, GL_FALSE if error found
  300.  */
  301. GLboolean
  302. _mesa_validate_DrawArrays(struct gl_context *ctx,
  303.                           GLenum mode, GLint start, GLsizei count)
  304. {
  305.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  306.  
  307.    if (count <= 0) {
  308.       if (count < 0)
  309.          _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
  310.       return GL_FALSE;
  311.    }
  312.  
  313.    if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
  314.       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
  315.       return GL_FALSE;
  316.    }
  317.  
  318.    if (!check_valid_to_render(ctx, "glDrawArrays"))
  319.       return GL_FALSE;
  320.  
  321.    if (ctx->Const.CheckArrayBounds) {
  322.       if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
  323.          return GL_FALSE;
  324.    }
  325.  
  326.    return GL_TRUE;
  327. }
  328.  
  329.  
  330. GLboolean
  331. _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
  332.                                    GLsizei count, GLsizei primcount)
  333. {
  334.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  335.  
  336.    if (count <= 0) {
  337.       if (count < 0)
  338.          _mesa_error(ctx, GL_INVALID_VALUE,
  339.                      "glDrawArraysInstanced(count=%d)", count);
  340.       return GL_FALSE;
  341.    }
  342.  
  343.    if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
  344.       _mesa_error(ctx, GL_INVALID_ENUM,
  345.                   "glDrawArraysInstanced(mode=0x%x)", mode);
  346.       return GL_FALSE;
  347.    }
  348.  
  349.    if (primcount <= 0) {
  350.       if (primcount < 0)
  351.          _mesa_error(ctx, GL_INVALID_VALUE,
  352.                      "glDrawArraysInstanced(primcount=%d)", primcount);
  353.       return GL_FALSE;
  354.    }
  355.  
  356.    if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
  357.       return GL_FALSE;
  358.  
  359.    if (ctx->CompileFlag) {
  360.       _mesa_error(ctx, GL_INVALID_OPERATION,
  361.                   "glDrawArraysInstanced(display list");
  362.       return GL_FALSE;
  363.    }
  364.  
  365.    if (ctx->Const.CheckArrayBounds) {
  366.       if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
  367.          return GL_FALSE;
  368.    }
  369.  
  370.    return GL_TRUE;
  371. }
  372.  
  373.  
  374. GLboolean
  375. _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
  376.                                      GLenum mode, GLsizei count, GLenum type,
  377.                                      const GLvoid *indices, GLsizei primcount)
  378. {
  379.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  380.  
  381.    if (count <= 0) {
  382.       if (count < 0)
  383.          _mesa_error(ctx, GL_INVALID_VALUE,
  384.                      "glDrawElementsInstanced(count=%d)", count);
  385.       return GL_FALSE;
  386.    }
  387.  
  388.    if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
  389.       _mesa_error(ctx, GL_INVALID_ENUM,
  390.                   "glDrawElementsInstanced(mode = 0x%x)", mode);
  391.       return GL_FALSE;
  392.    }
  393.  
  394.    if (type != GL_UNSIGNED_INT &&
  395.        type != GL_UNSIGNED_BYTE &&
  396.        type != GL_UNSIGNED_SHORT) {
  397.       _mesa_error(ctx, GL_INVALID_ENUM,
  398.                   "glDrawElementsInstanced(type=0x%x)", type);
  399.       return GL_FALSE;
  400.    }
  401.  
  402.    if (primcount <= 0) {
  403.       if (primcount < 0)
  404.          _mesa_error(ctx, GL_INVALID_VALUE,
  405.                      "glDrawElementsInstanced(primcount=%d)", primcount);
  406.       return GL_FALSE;
  407.    }
  408.  
  409.    if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
  410.       return GL_FALSE;
  411.  
  412.    /* Vertex buffer object tests */
  413.    if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
  414.       /* use indices in the buffer object */
  415.       /* make sure count doesn't go outside buffer bounds */
  416.       if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) {
  417.          _mesa_warning(ctx,
  418.                        "glDrawElementsInstanced index out of buffer bounds");
  419.          return GL_FALSE;
  420.       }
  421.    }
  422.    else {
  423.       /* not using a VBO */
  424.       if (!indices)
  425.          return GL_FALSE;
  426.    }
  427.  
  428.    if (!check_index_bounds(ctx, count, type, indices, 0))
  429.       return GL_FALSE;
  430.  
  431.    return GL_TRUE;
  432. }
  433.