api_validate.c revision 762c9766c93697af8d7fbaa729aed118789dbe8e
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 */ 38static GLsizei 39index_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 */ 57GLuint 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.MapBufferRange(ctx, 0, elementBuf->Size, 69 GL_MAP_READ_BIT, 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, elementBuf); 93 } 94 95 return max; 96} 97 98 99/** 100 * Check if OK to draw arrays/elements. 101 */ 102static GLboolean 103check_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 120 case API_OPENGLES: 121 /* For OpenGL ES, only draw if we have vertex positions 122 */ 123 if (!ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) 124 return GL_FALSE; 125 break; 126#endif 127 128#if FEATURE_GL 129 case API_OPENGL: 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#endif 151 152 default: 153 ASSERT_NO_FEATURE(); 154 } 155 156 return GL_TRUE; 157} 158 159 160/** 161 * Do bounds checking on array element indexes. Check that the vertices 162 * pointed to by the indices don't lie outside buffer object bounds. 163 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds 164 */ 165static GLboolean 166check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type, 167 const GLvoid *indices, GLint basevertex) 168{ 169 struct _mesa_prim prim; 170 struct _mesa_index_buffer ib; 171 GLuint min, max; 172 173 /* Only the X Server needs to do this -- otherwise, accessing outside 174 * array/BO bounds allows application termination. 175 */ 176 if (!ctx->Const.CheckArrayBounds) 177 return GL_TRUE; 178 179 memset(&prim, 0, sizeof(prim)); 180 prim.count = count; 181 182 memset(&ib, 0, sizeof(ib)); 183 ib.type = type; 184 ib.ptr = indices; 185 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; 186 187 vbo_get_minmax_index(ctx, &prim, &ib, &min, &max); 188 189 if ((int)(min + basevertex) < 0 || 190 max + basevertex > ctx->Array.ArrayObj->_MaxElement) { 191 /* the max element is out of bounds of one or more enabled arrays */ 192 _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)", 193 max, ctx->Array.ArrayObj->_MaxElement); 194 return GL_FALSE; 195 } 196 197 return GL_TRUE; 198} 199 200 201/** 202 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), 203 * etc? The set of legal values depends on whether geometry shaders/programs 204 * are supported. 205 */ 206GLboolean 207_mesa_valid_prim_mode(const struct gl_context *ctx, GLenum mode) 208{ 209 if (ctx->Extensions.ARB_geometry_shader4 && 210 mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) { 211 return GL_FALSE; 212 } 213 else if (mode > GL_POLYGON) { 214 return GL_FALSE; 215 } 216 else { 217 return GL_TRUE; 218 } 219} 220 221 222/** 223 * Error checking for glDrawElements(). Includes parameter checking 224 * and VBO bounds checking. 225 * \return GL_TRUE if OK to render, GL_FALSE if error found 226 */ 227GLboolean 228_mesa_validate_DrawElements(struct gl_context *ctx, 229 GLenum mode, GLsizei count, GLenum type, 230 const GLvoid *indices, GLint basevertex) 231{ 232 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 233 234 if (count <= 0) { 235 if (count < 0) 236 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 237 return GL_FALSE; 238 } 239 240 if (!_mesa_valid_prim_mode(ctx, mode)) { 241 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 242 return GL_FALSE; 243 } 244 245 if (type != GL_UNSIGNED_INT && 246 type != GL_UNSIGNED_BYTE && 247 type != GL_UNSIGNED_SHORT) 248 { 249 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 250 return GL_FALSE; 251 } 252 253 if (!check_valid_to_render(ctx, "glDrawElements")) 254 return GL_FALSE; 255 256 /* Vertex buffer object tests */ 257 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->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.ArrayObj->ElementArrayBufferObj->Size) { 261 _mesa_warning(ctx, "glDrawElements 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 * Error checking for glDrawRangeElements(). Includes parameter checking 280 * and VBO bounds checking. 281 * \return GL_TRUE if OK to render, GL_FALSE if error found 282 */ 283GLboolean 284_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode, 285 GLuint start, GLuint end, 286 GLsizei count, GLenum type, 287 const GLvoid *indices, GLint basevertex) 288{ 289 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 290 291 if (count <= 0) { 292 if (count < 0) 293 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 294 return GL_FALSE; 295 } 296 297 if (!_mesa_valid_prim_mode(ctx, mode)) { 298 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 299 return GL_FALSE; 300 } 301 302 if (end < start) { 303 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 304 return GL_FALSE; 305 } 306 307 if (type != GL_UNSIGNED_INT && 308 type != GL_UNSIGNED_BYTE && 309 type != GL_UNSIGNED_SHORT) { 310 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 311 return GL_FALSE; 312 } 313 314 if (!check_valid_to_render(ctx, "glDrawRangeElements")) 315 return GL_FALSE; 316 317 /* Vertex buffer object tests */ 318 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 319 /* use indices in the buffer object */ 320 /* make sure count doesn't go outside buffer bounds */ 321 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { 322 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 323 return GL_FALSE; 324 } 325 } 326 else { 327 /* not using a VBO */ 328 if (!indices) 329 return GL_FALSE; 330 } 331 332 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 333 return GL_FALSE; 334 335 return GL_TRUE; 336} 337 338 339/** 340 * Called from the tnl module to error check the function parameters and 341 * verify that we really can draw something. 342 * \return GL_TRUE if OK to render, GL_FALSE if error found 343 */ 344GLboolean 345_mesa_validate_DrawArrays(struct gl_context *ctx, 346 GLenum mode, GLint start, GLsizei count) 347{ 348 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 349 350 if (count <= 0) { 351 if (count < 0) 352 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 353 return GL_FALSE; 354 } 355 356 if (!_mesa_valid_prim_mode(ctx, mode)) { 357 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 358 return GL_FALSE; 359 } 360 361 if (!check_valid_to_render(ctx, "glDrawArrays")) 362 return GL_FALSE; 363 364 if (ctx->Const.CheckArrayBounds) { 365 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 366 return GL_FALSE; 367 } 368 369 return GL_TRUE; 370} 371 372 373GLboolean 374_mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first, 375 GLsizei count, GLsizei numInstances) 376{ 377 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 378 379 if (count <= 0) { 380 if (count < 0) 381 _mesa_error(ctx, GL_INVALID_VALUE, 382 "glDrawArraysInstanced(count=%d)", count); 383 return GL_FALSE; 384 } 385 386 if (!_mesa_valid_prim_mode(ctx, mode)) { 387 _mesa_error(ctx, GL_INVALID_ENUM, 388 "glDrawArraysInstanced(mode=0x%x)", mode); 389 return GL_FALSE; 390 } 391 392 if (numInstances <= 0) { 393 if (numInstances < 0) 394 _mesa_error(ctx, GL_INVALID_VALUE, 395 "glDrawArraysInstanced(numInstances=%d)", numInstances); 396 return GL_FALSE; 397 } 398 399 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)")) 400 return GL_FALSE; 401 402 if (ctx->CompileFlag) { 403 _mesa_error(ctx, GL_INVALID_OPERATION, 404 "glDrawArraysInstanced(display list"); 405 return GL_FALSE; 406 } 407 408 if (ctx->Const.CheckArrayBounds) { 409 if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 410 return GL_FALSE; 411 } 412 413 return GL_TRUE; 414} 415 416 417GLboolean 418_mesa_validate_DrawElementsInstanced(struct gl_context *ctx, 419 GLenum mode, GLsizei count, GLenum type, 420 const GLvoid *indices, GLsizei numInstances, 421 GLint basevertex) 422{ 423 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 424 425 if (count <= 0) { 426 if (count < 0) 427 _mesa_error(ctx, GL_INVALID_VALUE, 428 "glDrawElementsInstanced(count=%d)", count); 429 return GL_FALSE; 430 } 431 432 if (!_mesa_valid_prim_mode(ctx, mode)) { 433 _mesa_error(ctx, GL_INVALID_ENUM, 434 "glDrawElementsInstanced(mode = 0x%x)", mode); 435 return GL_FALSE; 436 } 437 438 if (type != GL_UNSIGNED_INT && 439 type != GL_UNSIGNED_BYTE && 440 type != GL_UNSIGNED_SHORT) { 441 _mesa_error(ctx, GL_INVALID_ENUM, 442 "glDrawElementsInstanced(type=0x%x)", type); 443 return GL_FALSE; 444 } 445 446 if (numInstances <= 0) { 447 if (numInstances < 0) 448 _mesa_error(ctx, GL_INVALID_VALUE, 449 "glDrawElementsInstanced(numInstances=%d)", numInstances); 450 return GL_FALSE; 451 } 452 453 if (!check_valid_to_render(ctx, "glDrawElementsInstanced")) 454 return GL_FALSE; 455 456 /* Vertex buffer object tests */ 457 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 458 /* use indices in the buffer object */ 459 /* make sure count doesn't go outside buffer bounds */ 460 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { 461 _mesa_warning(ctx, 462 "glDrawElementsInstanced index out of buffer bounds"); 463 return GL_FALSE; 464 } 465 } 466 else { 467 /* not using a VBO */ 468 if (!indices) 469 return GL_FALSE; 470 } 471 472 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 473 return GL_FALSE; 474 475 return GL_TRUE; 476} 477