api_validate.c revision 980fa564e4c01c7b95099a13fb2d8926c510da01
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 "mtypes.h" 31#include "vbo/vbo.h" 32 33 34/** 35 * \return number of bytes in array [count] of type. 36 */ 37static GLsizei 38index_bytes(GLenum type, GLsizei count) 39{ 40 if (type == GL_UNSIGNED_INT) { 41 return count * sizeof(GLuint); 42 } 43 else if (type == GL_UNSIGNED_BYTE) { 44 return count * sizeof(GLubyte); 45 } 46 else { 47 ASSERT(type == GL_UNSIGNED_SHORT); 48 return count * sizeof(GLushort); 49 } 50} 51 52 53/** 54 * Find the max index in the given element/index buffer 55 */ 56GLuint 57_mesa_max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, 58 const void *indices, 59 struct gl_buffer_object *elementBuf) 60{ 61 const GLubyte *map = NULL; 62 GLuint max = 0; 63 GLuint i; 64 65 if (_mesa_is_bufferobj(elementBuf)) { 66 /* elements are in a user-defined buffer object. need to map it */ 67 map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, 68 GL_READ_ONLY, elementBuf); 69 /* Actual address is the sum of pointers */ 70 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); 71 } 72 73 if (type == GL_UNSIGNED_INT) { 74 for (i = 0; i < count; i++) 75 if (((GLuint *) indices)[i] > max) 76 max = ((GLuint *) indices)[i]; 77 } 78 else if (type == GL_UNSIGNED_SHORT) { 79 for (i = 0; i < count; i++) 80 if (((GLushort *) indices)[i] > max) 81 max = ((GLushort *) indices)[i]; 82 } 83 else { 84 ASSERT(type == GL_UNSIGNED_BYTE); 85 for (i = 0; i < count; i++) 86 if (((GLubyte *) indices)[i] > max) 87 max = ((GLubyte *) indices)[i]; 88 } 89 90 if (map) { 91 ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); 92 } 93 94 return max; 95} 96 97 98/** 99 * Check if OK to draw arrays/elements. 100 */ 101static GLboolean 102check_valid_to_render(GLcontext *ctx, const char *function) 103{ 104 if (!_mesa_valid_to_render(ctx, function)) { 105 return GL_FALSE; 106 } 107 108#if FEATURE_es2_glsl 109 /* For ES2, we can draw if any vertex array is enabled (and we should 110 * always have a vertex program/shader). 111 */ 112 if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current) 113 return GL_FALSE; 114#else 115 /* For regular OpenGL, only draw if we have vertex positions (regardless 116 * of whether or not we have a vertex program/shader). 117 */ 118 if (!ctx->Array.ArrayObj->Vertex.Enabled && 119 !ctx->Array.ArrayObj->VertexAttrib[0].Enabled) 120 return GL_FALSE; 121#endif 122 123 return GL_TRUE; 124} 125 126static GLboolean 127check_index_bounds(GLcontext *ctx, GLsizei count, GLenum type, 128 const GLvoid *indices, GLint basevertex) 129{ 130 struct _mesa_prim prim; 131 struct _mesa_index_buffer ib; 132 GLuint min, max; 133 134 /* Only the X Server needs to do this -- otherwise, accessing outside 135 * array/BO bounds allows application termination. 136 */ 137 if (!ctx->Const.CheckArrayBounds) 138 return GL_TRUE; 139 140 memset(&prim, 0, sizeof(prim)); 141 prim.count = count; 142 143 memset(&ib, 0, sizeof(ib)); 144 ib.type = type; 145 ib.ptr = indices; 146 ib.obj = ctx->Array.ElementArrayBufferObj; 147 148 vbo_get_minmax_index(ctx, &prim, &ib, &min, &max); 149 150 if (min + basevertex < 0 || 151 max + basevertex > ctx->Array.ArrayObj->_MaxElement) { 152 /* the max element is out of bounds of one or more enabled arrays */ 153 _mesa_warning(ctx, "glDrawElements() index=%u is " 154 "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); 155 return GL_FALSE; 156 } 157 158 return GL_TRUE; 159} 160 161/** 162 * Error checking for glDrawElements(). Includes parameter checking 163 * and VBO bounds checking. 164 * \return GL_TRUE if OK to render, GL_FALSE if error found 165 */ 166GLboolean 167_mesa_validate_DrawElements(GLcontext *ctx, 168 GLenum mode, GLsizei count, GLenum type, 169 const GLvoid *indices, GLint basevertex) 170{ 171 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 172 173 if (count <= 0) { 174 if (count < 0) 175 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 176 return GL_FALSE; 177 } 178 179 if (mode > GL_POLYGON) { 180 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 181 return GL_FALSE; 182 } 183 184 if (type != GL_UNSIGNED_INT && 185 type != GL_UNSIGNED_BYTE && 186 type != GL_UNSIGNED_SHORT) 187 { 188 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 189 return GL_FALSE; 190 } 191 192 if (!check_valid_to_render(ctx, "glDrawElements")) 193 return GL_FALSE; 194 195 /* Vertex buffer object tests */ 196 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 197 /* use indices in the buffer object */ 198 /* make sure count doesn't go outside buffer bounds */ 199 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 200 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 201 return GL_FALSE; 202 } 203 } 204 else { 205 /* not using a VBO */ 206 if (!indices) 207 return GL_FALSE; 208 } 209 210 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 211 return GL_FALSE; 212 213 return GL_TRUE; 214} 215 216 217/** 218 * Error checking for glDrawRangeElements(). Includes parameter checking 219 * and VBO bounds checking. 220 * \return GL_TRUE if OK to render, GL_FALSE if error found 221 */ 222GLboolean 223_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 224 GLuint start, GLuint end, 225 GLsizei count, GLenum type, 226 const GLvoid *indices, GLint basevertex) 227{ 228 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 229 230 if (count <= 0) { 231 if (count < 0) 232 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 233 return GL_FALSE; 234 } 235 236 if (mode > GL_POLYGON) { 237 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 238 return GL_FALSE; 239 } 240 241 if (end < start) { 242 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 243 return GL_FALSE; 244 } 245 246 if (type != GL_UNSIGNED_INT && 247 type != GL_UNSIGNED_BYTE && 248 type != GL_UNSIGNED_SHORT) { 249 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 250 return GL_FALSE; 251 } 252 253 if (!check_valid_to_render(ctx, "glDrawRangeElements")) 254 return GL_FALSE; 255 256 /* Vertex buffer object tests */ 257 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 258 /* use indices in the buffer object */ 259 /* make sure count doesn't go outside buffer bounds */ 260 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 261 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 262 return GL_FALSE; 263 } 264 } 265 else { 266 /* not using a VBO */ 267 if (!indices) 268 return GL_FALSE; 269 } 270 271 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 272 return GL_FALSE; 273 274 return GL_TRUE; 275} 276 277 278/** 279 * Called from the tnl module to error check the function parameters and 280 * verify that we really can draw something. 281 * \return GL_TRUE if OK to render, GL_FALSE if error found 282 */ 283GLboolean 284_mesa_validate_DrawArrays(GLcontext *ctx, 285 GLenum mode, GLint start, GLsizei count) 286{ 287 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 288 289 if (count <= 0) { 290 if (count < 0) 291 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 292 return GL_FALSE; 293 } 294 295 if (mode > GL_POLYGON) { 296 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 297 return GL_FALSE; 298 } 299 300 if (!check_valid_to_render(ctx, "glDrawArrays")) 301 return GL_FALSE; 302 303 if (ctx->Const.CheckArrayBounds) { 304 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 305 return GL_FALSE; 306 } 307 308 return GL_TRUE; 309} 310