api_validate.c revision 467e3aa3de0e1f5b357975d35c1312f7566af577
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 * \return number of bytes in array [count] of type. 40 */ 41static GLsizei 42index_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 */ 60GLuint 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 */ 105static GLboolean 106check_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 case API_OPENGLES2: 114 /* For ES2, we can draw if any vertex array is enabled (and we 115 * should always have a vertex program/shader). */ 116 if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current) 117 return GL_FALSE; 118 break; 119 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 127 case API_OPENGL_COMPAT: 128 case API_OPENGL_CORE: 129 { 130 const struct gl_shader_program *vsProg = 131 ctx->Shader.CurrentVertexProgram; 132 GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus); 133 GLboolean haveVertexProgram = ctx->VertexProgram._Enabled; 134 if (haveVertexShader || haveVertexProgram) { 135 /* Draw regardless of whether or not we have any vertex arrays. 136 * (Ex: could draw a point using a constant vertex pos) 137 */ 138 return GL_TRUE; 139 } 140 else { 141 /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic 142 * array [0]). 143 */ 144 return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled || 145 ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled); 146 } 147 } 148 break; 149 150 default: 151 assert(!"Invalid API value in check_valid_to_render()"); 152 } 153 154 return GL_TRUE; 155} 156 157 158/** 159 * Do bounds checking on array element indexes. Check that the vertices 160 * pointed to by the indices don't lie outside buffer object bounds. 161 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds 162 */ 163static GLboolean 164check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type, 165 const GLvoid *indices, GLint basevertex) 166{ 167 struct _mesa_prim prim; 168 struct _mesa_index_buffer ib; 169 GLuint min, max; 170 171 /* Only the X Server needs to do this -- otherwise, accessing outside 172 * array/BO bounds allows application termination. 173 */ 174 if (!ctx->Const.CheckArrayBounds) 175 return GL_TRUE; 176 177 memset(&prim, 0, sizeof(prim)); 178 prim.count = count; 179 180 memset(&ib, 0, sizeof(ib)); 181 ib.type = type; 182 ib.ptr = indices; 183 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; 184 185 vbo_get_minmax_indices(ctx, &prim, &ib, &min, &max, 1); 186 187 if ((int)(min + basevertex) < 0 || 188 max + basevertex >= ctx->Array.ArrayObj->_MaxElement) { 189 /* the max element is out of bounds of one or more enabled arrays */ 190 _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)", 191 max, ctx->Array.ArrayObj->_MaxElement); 192 return GL_FALSE; 193 } 194 195 return GL_TRUE; 196} 197 198 199/** 200 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), 201 * etc? The set of legal values depends on whether geometry shaders/programs 202 * are supported. 203 * Note: This may be called during display list compilation. 204 */ 205bool 206_mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode) 207{ 208 switch (mode) { 209 case GL_POINTS: 210 case GL_LINES: 211 case GL_LINE_LOOP: 212 case GL_LINE_STRIP: 213 case GL_TRIANGLES: 214 case GL_TRIANGLE_STRIP: 215 case GL_TRIANGLE_FAN: 216 return true; 217 case GL_QUADS: 218 case GL_QUAD_STRIP: 219 case GL_POLYGON: 220 return (ctx->API == API_OPENGL_COMPAT); 221 case GL_LINES_ADJACENCY: 222 case GL_LINE_STRIP_ADJACENCY: 223 case GL_TRIANGLES_ADJACENCY: 224 case GL_TRIANGLE_STRIP_ADJACENCY: 225 return _mesa_has_geometry_shaders(ctx); 226 default: 227 return false; 228 } 229} 230 231 232/** 233 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), 234 * etc? Also, do additional checking related to transformation feedback. 235 * Note: this function cannot be called during glNewList(GL_COMPILE) because 236 * this code depends on current transform feedback state. 237 */ 238GLboolean 239_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name) 240{ 241 bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode); 242 243 if (!valid_enum) { 244 _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode); 245 return GL_FALSE; 246 } 247 248 /* From the ARB_geometry_shader4 spec: 249 * 250 * The error INVALID_OPERATION is generated if Begin, or any command that 251 * implicitly calls Begin, is called when a geometry shader is active and: 252 * 253 * * the input primitive type of the current geometry shader is 254 * POINTS and <mode> is not POINTS, 255 * 256 * * the input primitive type of the current geometry shader is 257 * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP, 258 * 259 * * the input primitive type of the current geometry shader is 260 * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or 261 * TRIANGLE_FAN, 262 * 263 * * the input primitive type of the current geometry shader is 264 * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or 265 * LINE_STRIP_ADJACENCY_ARB, or 266 * 267 * * the input primitive type of the current geometry shader is 268 * TRIANGLES_ADJACENCY_ARB and <mode> is not 269 * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB. 270 * 271 */ 272 if (ctx->Shader.CurrentGeometryProgram) { 273 const GLenum geom_mode = 274 ctx->Shader.CurrentGeometryProgram->Geom.InputType; 275 switch (mode) { 276 case GL_POINTS: 277 valid_enum = (geom_mode == GL_POINTS); 278 break; 279 case GL_LINES: 280 case GL_LINE_LOOP: 281 case GL_LINE_STRIP: 282 valid_enum = (geom_mode == GL_LINES); 283 break; 284 case GL_TRIANGLES: 285 case GL_TRIANGLE_STRIP: 286 case GL_TRIANGLE_FAN: 287 valid_enum = (geom_mode == GL_TRIANGLES); 288 break; 289 case GL_QUADS: 290 case GL_QUAD_STRIP: 291 case GL_POLYGON: 292 valid_enum = false; 293 break; 294 case GL_LINES_ADJACENCY: 295 case GL_LINE_STRIP_ADJACENCY: 296 valid_enum = (geom_mode == GL_LINES_ADJACENCY); 297 break; 298 case GL_TRIANGLES_ADJACENCY: 299 case GL_TRIANGLE_STRIP_ADJACENCY: 300 valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY); 301 break; 302 default: 303 valid_enum = false; 304 break; 305 } 306 if (!valid_enum) { 307 _mesa_error(ctx, GL_INVALID_OPERATION, 308 "%s(mode=%s vs geometry shader input %s)", 309 name, 310 _mesa_lookup_prim_by_nr(mode), 311 _mesa_lookup_prim_by_nr(geom_mode)); 312 return GL_FALSE; 313 } 314 } 315 316 /* From the GL_EXT_transform_feedback spec: 317 * 318 * "The error INVALID_OPERATION is generated if Begin, or any command 319 * that performs an explicit Begin, is called when: 320 * 321 * * a geometry shader is not active and <mode> does not match the 322 * allowed begin modes for the current transform feedback state as 323 * given by table X.1. 324 * 325 * * a geometry shader is active and the output primitive type of the 326 * geometry shader does not match the allowed begin modes for the 327 * current transform feedback state as given by table X.1. 328 * 329 */ 330 if (_mesa_is_xfb_active_and_unpaused(ctx)) { 331 GLboolean pass = GL_TRUE; 332 333 if(ctx->Shader.CurrentGeometryProgram) { 334 switch (ctx->Shader.CurrentGeometryProgram->Geom.OutputType) { 335 case GL_POINTS: 336 pass = ctx->TransformFeedback.Mode == GL_POINTS; 337 break; 338 case GL_LINE_STRIP: 339 pass = ctx->TransformFeedback.Mode == GL_LINES; 340 break; 341 case GL_TRIANGLE_STRIP: 342 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; 343 break; 344 default: 345 pass = GL_FALSE; 346 } 347 } 348 else { 349 switch (mode) { 350 case GL_POINTS: 351 pass = ctx->TransformFeedback.Mode == GL_POINTS; 352 break; 353 case GL_LINES: 354 case GL_LINE_STRIP: 355 case GL_LINE_LOOP: 356 pass = ctx->TransformFeedback.Mode == GL_LINES; 357 break; 358 default: 359 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; 360 break; 361 } 362 } 363 if (!pass) { 364 _mesa_error(ctx, GL_INVALID_OPERATION, 365 "%s(mode=%s vs transform feedback %s)", 366 name, 367 _mesa_lookup_prim_by_nr(mode), 368 _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode)); 369 return GL_FALSE; 370 } 371 } 372 373 return GL_TRUE; 374} 375 376/** 377 * Verify that the element type is valid. 378 * 379 * Generates \c GL_INVALID_ENUM and returns \c false if it is not. 380 */ 381static bool 382valid_elements_type(struct gl_context *ctx, GLenum type, const char *name) 383{ 384 switch (type) { 385 case GL_UNSIGNED_BYTE: 386 case GL_UNSIGNED_SHORT: 387 case GL_UNSIGNED_INT: 388 return true; 389 390 default: 391 _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name, 392 _mesa_lookup_enum_by_nr(type)); 393 return false; 394 } 395} 396 397/** 398 * Error checking for glDrawElements(). Includes parameter checking 399 * and VBO bounds checking. 400 * \return GL_TRUE if OK to render, GL_FALSE if error found 401 */ 402GLboolean 403_mesa_validate_DrawElements(struct gl_context *ctx, 404 GLenum mode, GLsizei count, GLenum type, 405 const GLvoid *indices, GLint basevertex) 406{ 407 FLUSH_CURRENT(ctx, 0); 408 409 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 410 * Primitive Capture): 411 * 412 * The error INVALID_OPERATION is also generated by DrawElements, 413 * DrawElementsInstanced, and DrawRangeElements while transform feedback 414 * is active and not paused, regardless of mode. 415 */ 416 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 417 _mesa_error(ctx, GL_INVALID_OPERATION, 418 "glDrawElements(transform feedback active)"); 419 return GL_FALSE; 420 } 421 422 if (count < 0) { 423 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 424 return GL_FALSE; 425 } 426 427 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) { 428 return GL_FALSE; 429 } 430 431 if (!valid_elements_type(ctx, type, "glDrawElements")) 432 return GL_FALSE; 433 434 if (!check_valid_to_render(ctx, "glDrawElements")) 435 return GL_FALSE; 436 437 /* Vertex buffer object tests */ 438 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 439 /* use indices in the buffer object */ 440 /* make sure count doesn't go outside buffer bounds */ 441 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { 442 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 443 return GL_FALSE; 444 } 445 } 446 else { 447 /* not using a VBO */ 448 if (!indices) 449 return GL_FALSE; 450 } 451 452 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 453 return GL_FALSE; 454 455 if (count == 0) 456 return GL_FALSE; 457 458 return GL_TRUE; 459} 460 461 462/** 463 * Error checking for glMultiDrawElements(). Includes parameter checking 464 * and VBO bounds checking. 465 * \return GL_TRUE if OK to render, GL_FALSE if error found 466 */ 467GLboolean 468_mesa_validate_MultiDrawElements(struct gl_context *ctx, 469 GLenum mode, const GLsizei *count, 470 GLenum type, const GLvoid * const *indices, 471 GLuint primcount, const GLint *basevertex) 472{ 473 unsigned i; 474 475 FLUSH_CURRENT(ctx, 0); 476 477 for (i = 0; i < primcount; i++) { 478 if (count[i] < 0) { 479 _mesa_error(ctx, GL_INVALID_VALUE, 480 "glMultiDrawElements(count)" ); 481 return GL_FALSE; 482 } 483 } 484 485 if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) { 486 return GL_FALSE; 487 } 488 489 if (!valid_elements_type(ctx, type, "glMultiDrawElements")) 490 return GL_FALSE; 491 492 if (!check_valid_to_render(ctx, "glMultiDrawElements")) 493 return GL_FALSE; 494 495 /* Vertex buffer object tests */ 496 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 497 /* use indices in the buffer object */ 498 /* make sure count doesn't go outside buffer bounds */ 499 for (i = 0; i < primcount; i++) { 500 if (index_bytes(type, count[i]) > 501 ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { 502 _mesa_warning(ctx, 503 "glMultiDrawElements index out of buffer bounds"); 504 return GL_FALSE; 505 } 506 } 507 } 508 else { 509 /* not using a VBO */ 510 for (i = 0; i < primcount; i++) { 511 if (!indices[i]) 512 return GL_FALSE; 513 } 514 } 515 516 for (i = 0; i < primcount; i++) { 517 if (!check_index_bounds(ctx, count[i], type, indices[i], 518 basevertex ? basevertex[i] : 0)) 519 return GL_FALSE; 520 } 521 522 return GL_TRUE; 523} 524 525 526/** 527 * Error checking for glDrawRangeElements(). Includes parameter checking 528 * and VBO bounds checking. 529 * \return GL_TRUE if OK to render, GL_FALSE if error found 530 */ 531GLboolean 532_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode, 533 GLuint start, GLuint end, 534 GLsizei count, GLenum type, 535 const GLvoid *indices, GLint basevertex) 536{ 537 FLUSH_CURRENT(ctx, 0); 538 539 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 540 * Primitive Capture): 541 * 542 * The error INVALID_OPERATION is also generated by DrawElements, 543 * DrawElementsInstanced, and DrawRangeElements while transform feedback 544 * is active and not paused, regardless of mode. 545 */ 546 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 547 _mesa_error(ctx, GL_INVALID_OPERATION, 548 "glDrawElements(transform feedback active)"); 549 return GL_FALSE; 550 } 551 552 if (count < 0) { 553 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 554 return GL_FALSE; 555 } 556 557 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) { 558 return GL_FALSE; 559 } 560 561 if (end < start) { 562 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 563 return GL_FALSE; 564 } 565 566 if (!valid_elements_type(ctx, type, "glDrawRangeElements")) 567 return GL_FALSE; 568 569 if (!check_valid_to_render(ctx, "glDrawRangeElements")) 570 return GL_FALSE; 571 572 /* Vertex buffer object tests */ 573 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 574 /* use indices in the buffer object */ 575 /* make sure count doesn't go outside buffer bounds */ 576 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { 577 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 578 return GL_FALSE; 579 } 580 } 581 else { 582 /* not using a VBO */ 583 if (!indices) 584 return GL_FALSE; 585 } 586 587 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 588 return GL_FALSE; 589 590 if (count == 0) 591 return GL_FALSE; 592 593 return GL_TRUE; 594} 595 596 597/** 598 * Called from the tnl module to error check the function parameters and 599 * verify that we really can draw something. 600 * \return GL_TRUE if OK to render, GL_FALSE if error found 601 */ 602GLboolean 603_mesa_validate_DrawArrays(struct gl_context *ctx, 604 GLenum mode, GLint start, GLsizei count) 605{ 606 struct gl_transform_feedback_object *xfb_obj 607 = ctx->TransformFeedback.CurrentObject; 608 FLUSH_CURRENT(ctx, 0); 609 610 if (count < 0) { 611 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 612 return GL_FALSE; 613 } 614 615 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) { 616 return GL_FALSE; 617 } 618 619 if (!check_valid_to_render(ctx, "glDrawArrays")) 620 return GL_FALSE; 621 622 if (ctx->Const.CheckArrayBounds) { 623 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 624 return GL_FALSE; 625 } 626 627 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 628 * Primitive Capture): 629 * 630 * The error INVALID_OPERATION is generated by DrawArrays and 631 * DrawArraysInstanced if recording the vertices of a primitive to the 632 * buffer objects being used for transform feedback purposes would result 633 * in either exceeding the limits of any buffer object’s size, or in 634 * exceeding the end position offset + size − 1, as set by 635 * BindBufferRange. 636 * 637 * This is in contrast to the behaviour of desktop GL, where the extra 638 * primitives are silently dropped from the transform feedback buffer. 639 */ 640 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 641 size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1); 642 if (xfb_obj->GlesRemainingPrims < prim_count) { 643 _mesa_error(ctx, GL_INVALID_OPERATION, 644 "glDrawArrays(exceeds transform feedback size)"); 645 return GL_FALSE; 646 } 647 xfb_obj->GlesRemainingPrims -= prim_count; 648 } 649 650 if (count == 0) 651 return GL_FALSE; 652 653 return GL_TRUE; 654} 655 656 657GLboolean 658_mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first, 659 GLsizei count, GLsizei numInstances) 660{ 661 struct gl_transform_feedback_object *xfb_obj 662 = ctx->TransformFeedback.CurrentObject; 663 FLUSH_CURRENT(ctx, 0); 664 665 if (count < 0) { 666 _mesa_error(ctx, GL_INVALID_VALUE, 667 "glDrawArraysInstanced(count=%d)", count); 668 return GL_FALSE; 669 } 670 671 if (first < 0) { 672 _mesa_error(ctx, GL_INVALID_VALUE, 673 "glDrawArraysInstanced(start=%d)", first); 674 return GL_FALSE; 675 } 676 677 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) { 678 return GL_FALSE; 679 } 680 681 if (numInstances <= 0) { 682 if (numInstances < 0) 683 _mesa_error(ctx, GL_INVALID_VALUE, 684 "glDrawArraysInstanced(numInstances=%d)", numInstances); 685 return GL_FALSE; 686 } 687 688 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)")) 689 return GL_FALSE; 690 691 if (ctx->Const.CheckArrayBounds) { 692 if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 693 return GL_FALSE; 694 } 695 696 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 697 * Primitive Capture): 698 * 699 * The error INVALID_OPERATION is generated by DrawArrays and 700 * DrawArraysInstanced if recording the vertices of a primitive to the 701 * buffer objects being used for transform feedback purposes would result 702 * in either exceeding the limits of any buffer object’s size, or in 703 * exceeding the end position offset + size − 1, as set by 704 * BindBufferRange. 705 * 706 * This is in contrast to the behaviour of desktop GL, where the extra 707 * primitives are silently dropped from the transform feedback buffer. 708 */ 709 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 710 size_t prim_count 711 = vbo_count_tessellated_primitives(mode, count, numInstances); 712 if (xfb_obj->GlesRemainingPrims < prim_count) { 713 _mesa_error(ctx, GL_INVALID_OPERATION, 714 "glDrawArraysInstanced(exceeds transform feedback size)"); 715 return GL_FALSE; 716 } 717 xfb_obj->GlesRemainingPrims -= prim_count; 718 } 719 720 if (count == 0) 721 return GL_FALSE; 722 723 return GL_TRUE; 724} 725 726 727GLboolean 728_mesa_validate_DrawElementsInstanced(struct gl_context *ctx, 729 GLenum mode, GLsizei count, GLenum type, 730 const GLvoid *indices, GLsizei numInstances, 731 GLint basevertex) 732{ 733 FLUSH_CURRENT(ctx, 0); 734 735 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 736 * Primitive Capture): 737 * 738 * The error INVALID_OPERATION is also generated by DrawElements, 739 * DrawElementsInstanced, and DrawRangeElements while transform feedback 740 * is active and not paused, regardless of mode. 741 */ 742 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 743 _mesa_error(ctx, GL_INVALID_OPERATION, 744 "glDrawElements(transform feedback active)"); 745 return GL_FALSE; 746 } 747 748 if (count < 0) { 749 _mesa_error(ctx, GL_INVALID_VALUE, 750 "glDrawElementsInstanced(count=%d)", count); 751 return GL_FALSE; 752 } 753 754 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) { 755 return GL_FALSE; 756 } 757 758 if (!valid_elements_type(ctx, type, "glDrawElementsInstanced")) 759 return GL_FALSE; 760 761 if (numInstances <= 0) { 762 if (numInstances < 0) 763 _mesa_error(ctx, GL_INVALID_VALUE, 764 "glDrawElementsInstanced(numInstances=%d)", numInstances); 765 return GL_FALSE; 766 } 767 768 if (!check_valid_to_render(ctx, "glDrawElementsInstanced")) 769 return GL_FALSE; 770 771 /* Vertex buffer object tests */ 772 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 773 /* use indices in the buffer object */ 774 /* make sure count doesn't go outside buffer bounds */ 775 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { 776 _mesa_warning(ctx, 777 "glDrawElementsInstanced index out of buffer bounds"); 778 return GL_FALSE; 779 } 780 } 781 else { 782 /* not using a VBO */ 783 if (!indices) 784 return GL_FALSE; 785 } 786 787 if (count == 0) 788 return GL_FALSE; 789 790 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 791 return GL_FALSE; 792 793 return GL_TRUE; 794} 795 796 797GLboolean 798_mesa_validate_DrawTransformFeedback(struct gl_context *ctx, 799 GLenum mode, 800 struct gl_transform_feedback_object *obj, 801 GLuint stream, 802 GLsizei numInstances) 803{ 804 FLUSH_CURRENT(ctx, 0); 805 806 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) { 807 return GL_FALSE; 808 } 809 810 if (!obj) { 811 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)"); 812 return GL_FALSE; 813 } 814 815 if (!obj->EndedAnytime) { 816 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*"); 817 return GL_FALSE; 818 } 819 820 if (stream >= ctx->Const.MaxVertexStreams) { 821 _mesa_error(ctx, GL_INVALID_VALUE, 822 "glDrawTransformFeedbackStream*(index>=MaxVertexStream)"); 823 return GL_FALSE; 824 } 825 826 if (numInstances <= 0) { 827 if (numInstances < 0) 828 _mesa_error(ctx, GL_INVALID_VALUE, 829 "glDrawTransformFeedback*Instanced(numInstances=%d)", 830 numInstances); 831 return GL_FALSE; 832 } 833 834 if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) { 835 return GL_FALSE; 836 } 837 838 return GL_TRUE; 839} 840