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