api_validate.c revision f4b4ae8c241943b8ca65e7a00f272fe23ed73727
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 MAP_INTERNAL); 74 /* Actual address is the sum of pointers */ 75 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); 76 } 77 78 if (type == GL_UNSIGNED_INT) { 79 for (i = 0; i < count; i++) 80 if (((GLuint *) indices)[i] > max) 81 max = ((GLuint *) indices)[i]; 82 } 83 else if (type == GL_UNSIGNED_SHORT) { 84 for (i = 0; i < count; i++) 85 if (((GLushort *) indices)[i] > max) 86 max = ((GLushort *) indices)[i]; 87 } 88 else { 89 ASSERT(type == GL_UNSIGNED_BYTE); 90 for (i = 0; i < count; i++) 91 if (((GLubyte *) indices)[i] > max) 92 max = ((GLubyte *) indices)[i]; 93 } 94 95 if (map) { 96 ctx->Driver.UnmapBuffer(ctx, elementBuf, MAP_INTERNAL); 97 } 98 99 return max; 100} 101 102 103/** 104 * Check if OK to draw arrays/elements. 105 */ 106static GLboolean 107check_valid_to_render(struct gl_context *ctx, const char *function) 108{ 109 if (!_mesa_valid_to_render(ctx, function)) { 110 return GL_FALSE; 111 } 112 113 switch (ctx->API) { 114 case API_OPENGLES2: 115 /* For ES2, we can draw if we have a vertex program/shader). */ 116 if (!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.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled) 124 return GL_FALSE; 125 break; 126 127 case API_OPENGL_CORE: 128 if (ctx->Array.VAO == ctx->Array.DefaultVAO) 129 return GL_FALSE; 130 /* fallthrough */ 131 case API_OPENGL_COMPAT: 132 { 133 const struct gl_shader_program *vsProg = 134 ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX]; 135 GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus); 136 GLboolean haveVertexProgram = ctx->VertexProgram._Enabled; 137 if (haveVertexShader || haveVertexProgram) { 138 /* Draw regardless of whether or not we have any vertex arrays. 139 * (Ex: could draw a point using a constant vertex pos) 140 */ 141 return GL_TRUE; 142 } 143 else { 144 /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic 145 * array [0]). 146 */ 147 return (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled || 148 ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled); 149 } 150 } 151 break; 152 153 default: 154 assert(!"Invalid API value in check_valid_to_render()"); 155 } 156 157 return GL_TRUE; 158} 159 160 161/** 162 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), 163 * etc? The set of legal values depends on whether geometry shaders/programs 164 * are supported. 165 * Note: This may be called during display list compilation. 166 */ 167bool 168_mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode) 169{ 170 switch (mode) { 171 case GL_POINTS: 172 case GL_LINES: 173 case GL_LINE_LOOP: 174 case GL_LINE_STRIP: 175 case GL_TRIANGLES: 176 case GL_TRIANGLE_STRIP: 177 case GL_TRIANGLE_FAN: 178 return true; 179 case GL_QUADS: 180 case GL_QUAD_STRIP: 181 case GL_POLYGON: 182 return (ctx->API == API_OPENGL_COMPAT); 183 case GL_LINES_ADJACENCY: 184 case GL_LINE_STRIP_ADJACENCY: 185 case GL_TRIANGLES_ADJACENCY: 186 case GL_TRIANGLE_STRIP_ADJACENCY: 187 return _mesa_has_geometry_shaders(ctx); 188 default: 189 return false; 190 } 191} 192 193 194/** 195 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), 196 * etc? Also, do additional checking related to transformation feedback. 197 * Note: this function cannot be called during glNewList(GL_COMPILE) because 198 * this code depends on current transform feedback state. 199 */ 200GLboolean 201_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name) 202{ 203 bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode); 204 205 if (!valid_enum) { 206 _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode); 207 return GL_FALSE; 208 } 209 210 /* From the ARB_geometry_shader4 spec: 211 * 212 * The error INVALID_OPERATION is generated if Begin, or any command that 213 * implicitly calls Begin, is called when a geometry shader is active and: 214 * 215 * * the input primitive type of the current geometry shader is 216 * POINTS and <mode> is not POINTS, 217 * 218 * * the input primitive type of the current geometry shader is 219 * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP, 220 * 221 * * the input primitive type of the current geometry shader is 222 * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or 223 * TRIANGLE_FAN, 224 * 225 * * the input primitive type of the current geometry shader is 226 * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or 227 * LINE_STRIP_ADJACENCY_ARB, or 228 * 229 * * the input primitive type of the current geometry shader is 230 * TRIANGLES_ADJACENCY_ARB and <mode> is not 231 * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB. 232 * 233 */ 234 if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) { 235 const GLenum geom_mode = 236 ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType; 237 switch (mode) { 238 case GL_POINTS: 239 valid_enum = (geom_mode == GL_POINTS); 240 break; 241 case GL_LINES: 242 case GL_LINE_LOOP: 243 case GL_LINE_STRIP: 244 valid_enum = (geom_mode == GL_LINES); 245 break; 246 case GL_TRIANGLES: 247 case GL_TRIANGLE_STRIP: 248 case GL_TRIANGLE_FAN: 249 valid_enum = (geom_mode == GL_TRIANGLES); 250 break; 251 case GL_QUADS: 252 case GL_QUAD_STRIP: 253 case GL_POLYGON: 254 valid_enum = false; 255 break; 256 case GL_LINES_ADJACENCY: 257 case GL_LINE_STRIP_ADJACENCY: 258 valid_enum = (geom_mode == GL_LINES_ADJACENCY); 259 break; 260 case GL_TRIANGLES_ADJACENCY: 261 case GL_TRIANGLE_STRIP_ADJACENCY: 262 valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY); 263 break; 264 default: 265 valid_enum = false; 266 break; 267 } 268 if (!valid_enum) { 269 _mesa_error(ctx, GL_INVALID_OPERATION, 270 "%s(mode=%s vs geometry shader input %s)", 271 name, 272 _mesa_lookup_prim_by_nr(mode), 273 _mesa_lookup_prim_by_nr(geom_mode)); 274 return GL_FALSE; 275 } 276 } 277 278 /* From the GL_EXT_transform_feedback spec: 279 * 280 * "The error INVALID_OPERATION is generated if Begin, or any command 281 * that performs an explicit Begin, is called when: 282 * 283 * * a geometry shader is not active and <mode> does not match the 284 * allowed begin modes for the current transform feedback state as 285 * given by table X.1. 286 * 287 * * a geometry shader is active and the output primitive type of the 288 * geometry shader does not match the allowed begin modes for the 289 * current transform feedback state as given by table X.1. 290 * 291 */ 292 if (_mesa_is_xfb_active_and_unpaused(ctx)) { 293 GLboolean pass = GL_TRUE; 294 295 if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) { 296 switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) { 297 case GL_POINTS: 298 pass = ctx->TransformFeedback.Mode == GL_POINTS; 299 break; 300 case GL_LINE_STRIP: 301 pass = ctx->TransformFeedback.Mode == GL_LINES; 302 break; 303 case GL_TRIANGLE_STRIP: 304 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; 305 break; 306 default: 307 pass = GL_FALSE; 308 } 309 } 310 else { 311 switch (mode) { 312 case GL_POINTS: 313 pass = ctx->TransformFeedback.Mode == GL_POINTS; 314 break; 315 case GL_LINES: 316 case GL_LINE_STRIP: 317 case GL_LINE_LOOP: 318 pass = ctx->TransformFeedback.Mode == GL_LINES; 319 break; 320 default: 321 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; 322 break; 323 } 324 } 325 if (!pass) { 326 _mesa_error(ctx, GL_INVALID_OPERATION, 327 "%s(mode=%s vs transform feedback %s)", 328 name, 329 _mesa_lookup_prim_by_nr(mode), 330 _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode)); 331 return GL_FALSE; 332 } 333 } 334 335 return GL_TRUE; 336} 337 338/** 339 * Verify that the element type is valid. 340 * 341 * Generates \c GL_INVALID_ENUM and returns \c false if it is not. 342 */ 343static bool 344valid_elements_type(struct gl_context *ctx, GLenum type, const char *name) 345{ 346 switch (type) { 347 case GL_UNSIGNED_BYTE: 348 case GL_UNSIGNED_SHORT: 349 case GL_UNSIGNED_INT: 350 return true; 351 352 default: 353 _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name, 354 _mesa_lookup_enum_by_nr(type)); 355 return false; 356 } 357} 358 359/** 360 * Error checking for glDrawElements(). Includes parameter checking 361 * and VBO bounds checking. 362 * \return GL_TRUE if OK to render, GL_FALSE if error found 363 */ 364GLboolean 365_mesa_validate_DrawElements(struct gl_context *ctx, 366 GLenum mode, GLsizei count, GLenum type, 367 const GLvoid *indices, GLint basevertex) 368{ 369 FLUSH_CURRENT(ctx, 0); 370 371 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 372 * Primitive Capture): 373 * 374 * The error INVALID_OPERATION is also generated by DrawElements, 375 * DrawElementsInstanced, and DrawRangeElements while transform feedback 376 * is active and not paused, regardless of mode. 377 */ 378 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 379 _mesa_error(ctx, GL_INVALID_OPERATION, 380 "glDrawElements(transform feedback active)"); 381 return GL_FALSE; 382 } 383 384 if (count < 0) { 385 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 386 return GL_FALSE; 387 } 388 389 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) { 390 return GL_FALSE; 391 } 392 393 if (!valid_elements_type(ctx, type, "glDrawElements")) 394 return GL_FALSE; 395 396 if (!check_valid_to_render(ctx, "glDrawElements")) 397 return GL_FALSE; 398 399 /* Vertex buffer object tests */ 400 if (_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) { 401 /* use indices in the buffer object */ 402 /* make sure count doesn't go outside buffer bounds */ 403 if (index_bytes(type, count) > ctx->Array.VAO->IndexBufferObj->Size) { 404 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 405 return GL_FALSE; 406 } 407 } 408 else { 409 /* not using a VBO */ 410 if (!indices) 411 return GL_FALSE; 412 } 413 414 if (count == 0) 415 return GL_FALSE; 416 417 return GL_TRUE; 418} 419 420 421/** 422 * Error checking for glMultiDrawElements(). Includes parameter checking 423 * and VBO bounds checking. 424 * \return GL_TRUE if OK to render, GL_FALSE if error found 425 */ 426GLboolean 427_mesa_validate_MultiDrawElements(struct gl_context *ctx, 428 GLenum mode, const GLsizei *count, 429 GLenum type, const GLvoid * const *indices, 430 GLuint primcount, const GLint *basevertex) 431{ 432 unsigned i; 433 434 FLUSH_CURRENT(ctx, 0); 435 436 for (i = 0; i < primcount; i++) { 437 if (count[i] < 0) { 438 _mesa_error(ctx, GL_INVALID_VALUE, 439 "glMultiDrawElements(count)" ); 440 return GL_FALSE; 441 } 442 } 443 444 if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) { 445 return GL_FALSE; 446 } 447 448 if (!valid_elements_type(ctx, type, "glMultiDrawElements")) 449 return GL_FALSE; 450 451 if (!check_valid_to_render(ctx, "glMultiDrawElements")) 452 return GL_FALSE; 453 454 /* Vertex buffer object tests */ 455 if (_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) { 456 /* use indices in the buffer object */ 457 /* make sure count doesn't go outside buffer bounds */ 458 for (i = 0; i < primcount; i++) { 459 if (index_bytes(type, count[i]) > 460 ctx->Array.VAO->IndexBufferObj->Size) { 461 _mesa_warning(ctx, 462 "glMultiDrawElements index out of buffer bounds"); 463 return GL_FALSE; 464 } 465 } 466 } 467 else { 468 /* not using a VBO */ 469 for (i = 0; i < primcount; i++) { 470 if (!indices[i]) 471 return GL_FALSE; 472 } 473 } 474 475 return GL_TRUE; 476} 477 478 479/** 480 * Error checking for glDrawRangeElements(). Includes parameter checking 481 * and VBO bounds checking. 482 * \return GL_TRUE if OK to render, GL_FALSE if error found 483 */ 484GLboolean 485_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode, 486 GLuint start, GLuint end, 487 GLsizei count, GLenum type, 488 const GLvoid *indices, GLint basevertex) 489{ 490 FLUSH_CURRENT(ctx, 0); 491 492 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 493 * Primitive Capture): 494 * 495 * The error INVALID_OPERATION is also generated by DrawElements, 496 * DrawElementsInstanced, and DrawRangeElements while transform feedback 497 * is active and not paused, regardless of mode. 498 */ 499 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 500 _mesa_error(ctx, GL_INVALID_OPERATION, 501 "glDrawElements(transform feedback active)"); 502 return GL_FALSE; 503 } 504 505 if (count < 0) { 506 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 507 return GL_FALSE; 508 } 509 510 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) { 511 return GL_FALSE; 512 } 513 514 if (end < start) { 515 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 516 return GL_FALSE; 517 } 518 519 if (!valid_elements_type(ctx, type, "glDrawRangeElements")) 520 return GL_FALSE; 521 522 if (!check_valid_to_render(ctx, "glDrawRangeElements")) 523 return GL_FALSE; 524 525 /* Vertex buffer object tests */ 526 if (_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) { 527 /* use indices in the buffer object */ 528 /* make sure count doesn't go outside buffer bounds */ 529 if (index_bytes(type, count) > ctx->Array.VAO->IndexBufferObj->Size) { 530 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 531 return GL_FALSE; 532 } 533 } 534 else { 535 /* not using a VBO */ 536 if (!indices) 537 return GL_FALSE; 538 } 539 540 if (count == 0) 541 return GL_FALSE; 542 543 return GL_TRUE; 544} 545 546 547/** 548 * Called from the tnl module to error check the function parameters and 549 * verify that we really can draw something. 550 * \return GL_TRUE if OK to render, GL_FALSE if error found 551 */ 552GLboolean 553_mesa_validate_DrawArrays(struct gl_context *ctx, 554 GLenum mode, GLint start, GLsizei count) 555{ 556 struct gl_transform_feedback_object *xfb_obj 557 = ctx->TransformFeedback.CurrentObject; 558 FLUSH_CURRENT(ctx, 0); 559 560 if (count < 0) { 561 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 562 return GL_FALSE; 563 } 564 565 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) { 566 return GL_FALSE; 567 } 568 569 if (!check_valid_to_render(ctx, "glDrawArrays")) 570 return GL_FALSE; 571 572 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 573 * Primitive Capture): 574 * 575 * The error INVALID_OPERATION is generated by DrawArrays and 576 * DrawArraysInstanced if recording the vertices of a primitive to the 577 * buffer objects being used for transform feedback purposes would result 578 * in either exceeding the limits of any buffer object’s size, or in 579 * exceeding the end position offset + size − 1, as set by 580 * BindBufferRange. 581 * 582 * This is in contrast to the behaviour of desktop GL, where the extra 583 * primitives are silently dropped from the transform feedback buffer. 584 */ 585 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 586 size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1); 587 if (xfb_obj->GlesRemainingPrims < prim_count) { 588 _mesa_error(ctx, GL_INVALID_OPERATION, 589 "glDrawArrays(exceeds transform feedback size)"); 590 return GL_FALSE; 591 } 592 xfb_obj->GlesRemainingPrims -= prim_count; 593 } 594 595 if (count == 0) 596 return GL_FALSE; 597 598 return GL_TRUE; 599} 600 601 602GLboolean 603_mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first, 604 GLsizei count, GLsizei numInstances) 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, 612 "glDrawArraysInstanced(count=%d)", count); 613 return GL_FALSE; 614 } 615 616 if (first < 0) { 617 _mesa_error(ctx, GL_INVALID_VALUE, 618 "glDrawArraysInstanced(start=%d)", first); 619 return GL_FALSE; 620 } 621 622 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) { 623 return GL_FALSE; 624 } 625 626 if (numInstances <= 0) { 627 if (numInstances < 0) 628 _mesa_error(ctx, GL_INVALID_VALUE, 629 "glDrawArraysInstanced(numInstances=%d)", numInstances); 630 return GL_FALSE; 631 } 632 633 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)")) 634 return GL_FALSE; 635 636 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 637 * Primitive Capture): 638 * 639 * The error INVALID_OPERATION is generated by DrawArrays and 640 * DrawArraysInstanced if recording the vertices of a primitive to the 641 * buffer objects being used for transform feedback purposes would result 642 * in either exceeding the limits of any buffer object’s size, or in 643 * exceeding the end position offset + size − 1, as set by 644 * BindBufferRange. 645 * 646 * This is in contrast to the behaviour of desktop GL, where the extra 647 * primitives are silently dropped from the transform feedback buffer. 648 */ 649 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 650 size_t prim_count 651 = vbo_count_tessellated_primitives(mode, count, numInstances); 652 if (xfb_obj->GlesRemainingPrims < prim_count) { 653 _mesa_error(ctx, GL_INVALID_OPERATION, 654 "glDrawArraysInstanced(exceeds transform feedback size)"); 655 return GL_FALSE; 656 } 657 xfb_obj->GlesRemainingPrims -= prim_count; 658 } 659 660 if (count == 0) 661 return GL_FALSE; 662 663 return GL_TRUE; 664} 665 666 667GLboolean 668_mesa_validate_DrawElementsInstanced(struct gl_context *ctx, 669 GLenum mode, GLsizei count, GLenum type, 670 const GLvoid *indices, GLsizei numInstances, 671 GLint basevertex) 672{ 673 FLUSH_CURRENT(ctx, 0); 674 675 /* From the GLES3 specification, section 2.14.2 (Transform Feedback 676 * Primitive Capture): 677 * 678 * The error INVALID_OPERATION is also generated by DrawElements, 679 * DrawElementsInstanced, and DrawRangeElements while transform feedback 680 * is active and not paused, regardless of mode. 681 */ 682 if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { 683 _mesa_error(ctx, GL_INVALID_OPERATION, 684 "glDrawElements(transform feedback active)"); 685 return GL_FALSE; 686 } 687 688 if (count < 0) { 689 _mesa_error(ctx, GL_INVALID_VALUE, 690 "glDrawElementsInstanced(count=%d)", count); 691 return GL_FALSE; 692 } 693 694 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) { 695 return GL_FALSE; 696 } 697 698 if (!valid_elements_type(ctx, type, "glDrawElementsInstanced")) 699 return GL_FALSE; 700 701 if (numInstances <= 0) { 702 if (numInstances < 0) 703 _mesa_error(ctx, GL_INVALID_VALUE, 704 "glDrawElementsInstanced(numInstances=%d)", numInstances); 705 return GL_FALSE; 706 } 707 708 if (!check_valid_to_render(ctx, "glDrawElementsInstanced")) 709 return GL_FALSE; 710 711 /* Vertex buffer object tests */ 712 if (_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) { 713 /* use indices in the buffer object */ 714 /* make sure count doesn't go outside buffer bounds */ 715 if (index_bytes(type, count) > ctx->Array.VAO->IndexBufferObj->Size) { 716 _mesa_warning(ctx, 717 "glDrawElementsInstanced index out of buffer bounds"); 718 return GL_FALSE; 719 } 720 } 721 else { 722 /* not using a VBO */ 723 if (!indices) 724 return GL_FALSE; 725 } 726 727 if (count == 0) 728 return GL_FALSE; 729 730 return GL_TRUE; 731} 732 733 734GLboolean 735_mesa_validate_DrawTransformFeedback(struct gl_context *ctx, 736 GLenum mode, 737 struct gl_transform_feedback_object *obj, 738 GLuint stream, 739 GLsizei numInstances) 740{ 741 FLUSH_CURRENT(ctx, 0); 742 743 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) { 744 return GL_FALSE; 745 } 746 747 if (!obj) { 748 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)"); 749 return GL_FALSE; 750 } 751 752 if (!obj->EndedAnytime) { 753 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*"); 754 return GL_FALSE; 755 } 756 757 if (stream >= ctx->Const.MaxVertexStreams) { 758 _mesa_error(ctx, GL_INVALID_VALUE, 759 "glDrawTransformFeedbackStream*(index>=MaxVertexStream)"); 760 return GL_FALSE; 761 } 762 763 if (numInstances <= 0) { 764 if (numInstances < 0) 765 _mesa_error(ctx, GL_INVALID_VALUE, 766 "glDrawTransformFeedback*Instanced(numInstances=%d)", 767 numInstances); 768 return GL_FALSE; 769 } 770 771 if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) { 772 return GL_FALSE; 773 } 774 775 return GL_TRUE; 776} 777 778static GLboolean 779valid_draw_indirect(struct gl_context *ctx, 780 GLenum mode, const GLvoid *indirect, 781 GLsizei size, const char *name) 782{ 783 const GLsizeiptr end = (GLsizeiptr)indirect + size; 784 785 if (!_mesa_valid_prim_mode(ctx, mode, name)) 786 return GL_FALSE; 787 788 789 /* From the ARB_draw_indirect specification: 790 * "An INVALID_OPERATION error is generated [...] if <indirect> is no 791 * word aligned." 792 */ 793 if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) { 794 _mesa_error(ctx, GL_INVALID_OPERATION, 795 "%s(indirect is not aligned)", name); 796 return GL_FALSE; 797 } 798 799 if (!_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) { 800 _mesa_error(ctx, GL_INVALID_OPERATION, 801 "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name); 802 return GL_FALSE; 803 } 804 805 if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) { 806 _mesa_error(ctx, GL_INVALID_OPERATION, 807 "%s(DRAW_INDIRECT_BUFFER is mapped)", name); 808 return GL_FALSE; 809 } 810 811 /* From the ARB_draw_indirect specification: 812 * "An INVALID_OPERATION error is generated if the commands source data 813 * beyond the end of the buffer object [...]" 814 */ 815 if (ctx->DrawIndirectBuffer->Size < end) { 816 _mesa_error(ctx, GL_INVALID_OPERATION, 817 "%s(DRAW_INDIRECT_BUFFER too small)", name); 818 return GL_FALSE; 819 } 820 821 if (!check_valid_to_render(ctx, name)) 822 return GL_FALSE; 823 824 return GL_TRUE; 825} 826 827static inline GLboolean 828valid_draw_indirect_elements(struct gl_context *ctx, 829 GLenum mode, GLenum type, const GLvoid *indirect, 830 GLsizeiptr size, const char *name) 831{ 832 if (!valid_elements_type(ctx, type, name)) 833 return GL_FALSE; 834 835 /* 836 * Unlike regular DrawElementsInstancedBaseVertex commands, the indices 837 * may not come from a client array and must come from an index buffer. 838 * If no element array buffer is bound, an INVALID_OPERATION error is 839 * generated. 840 */ 841 if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) { 842 _mesa_error(ctx, GL_INVALID_OPERATION, 843 "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name); 844 return GL_FALSE; 845 } 846 847 return valid_draw_indirect(ctx, mode, indirect, size, name); 848} 849 850static inline GLboolean 851valid_draw_indirect_multi(struct gl_context *ctx, 852 GLsizei primcount, GLsizei stride, 853 const char *name) 854{ 855 856 /* From the ARB_multi_draw_indirect specification: 857 * "INVALID_VALUE is generated by MultiDrawArraysIndirect or 858 * MultiDrawElementsIndirect if <primcount> is negative." 859 * 860 * "<primcount> must be positive, otherwise an INVALID_VALUE error will 861 * be generated." 862 */ 863 if (primcount < 0) { 864 _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name); 865 return GL_FALSE; 866 } 867 868 869 /* From the ARB_multi_draw_indirect specification: 870 * "<stride> must be a multiple of four, otherwise an INVALID_VALUE 871 * error is generated." 872 */ 873 if (stride % 4) { 874 _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name); 875 return GL_FALSE; 876 } 877 878 return GL_TRUE; 879} 880 881GLboolean 882_mesa_validate_DrawArraysIndirect(struct gl_context *ctx, 883 GLenum mode, 884 const GLvoid *indirect) 885{ 886 const unsigned drawArraysNumParams = 4; 887 888 FLUSH_CURRENT(ctx, 0); 889 890 return valid_draw_indirect(ctx, mode, 891 indirect, drawArraysNumParams * sizeof(GLuint), 892 "glDrawArraysIndirect"); 893} 894 895GLboolean 896_mesa_validate_DrawElementsIndirect(struct gl_context *ctx, 897 GLenum mode, GLenum type, 898 const GLvoid *indirect) 899{ 900 const unsigned drawElementsNumParams = 5; 901 902 FLUSH_CURRENT(ctx, 0); 903 904 return valid_draw_indirect_elements(ctx, mode, type, 905 indirect, drawElementsNumParams * sizeof(GLuint), 906 "glDrawElementsIndirect"); 907} 908 909GLboolean 910_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx, 911 GLenum mode, 912 const GLvoid *indirect, 913 GLsizei primcount, GLsizei stride) 914{ 915 GLsizeiptr size = 0; 916 const unsigned drawArraysNumParams = 4; 917 918 FLUSH_CURRENT(ctx, 0); 919 920 /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */ 921 assert(stride != 0); 922 923 if (!valid_draw_indirect_multi(ctx, primcount, stride, 924 "glMultiDrawArraysIndirect")) 925 return GL_FALSE; 926 927 /* number of bytes of the indirect buffer which will be read */ 928 size = primcount 929 ? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint) 930 : 0; 931 932 if (!valid_draw_indirect(ctx, mode, indirect, size, 933 "glMultiDrawArraysIndirect")) 934 return GL_FALSE; 935 936 return GL_TRUE; 937} 938 939GLboolean 940_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx, 941 GLenum mode, GLenum type, 942 const GLvoid *indirect, 943 GLsizei primcount, GLsizei stride) 944{ 945 GLsizeiptr size = 0; 946 const unsigned drawElementsNumParams = 5; 947 948 FLUSH_CURRENT(ctx, 0); 949 950 /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */ 951 assert(stride != 0); 952 953 if (!valid_draw_indirect_multi(ctx, primcount, stride, 954 "glMultiDrawElementsIndirect")) 955 return GL_FALSE; 956 957 /* number of bytes of the indirect buffer which will be read */ 958 size = primcount 959 ? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint) 960 : 0; 961 962 if (!valid_draw_indirect_elements(ctx, mode, type, 963 indirect, size, 964 "glMultiDrawElementsIndirect")) 965 return GL_FALSE; 966 967 return GL_TRUE; 968} 969