1 #include "precompiled.h" 2 // 3 // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 // 7 8 // validationES.h: Validation functions for generic OpenGL ES entry point parameters 9 10 #include "libGLESv2/validationES.h" 11 #include "libGLESv2/validationES2.h" 12 #include "libGLESv2/validationES3.h" 13 #include "libGLESv2/Context.h" 14 #include "libGLESv2/Texture.h" 15 #include "libGLESv2/Framebuffer.h" 16 #include "libGLESv2/Renderbuffer.h" 17 #include "libGLESv2/formatutils.h" 18 #include "libGLESv2/main.h" 19 #include "libGLESv2/Query.h" 20 #include "libGLESv2/ProgramBinary.h" 21 22 #include "common/mathutil.h" 23 #include "common/utilities.h" 24 25 namespace gl 26 { 27 28 bool ValidCap(const Context *context, GLenum cap) 29 { 30 switch (cap) 31 { 32 case GL_CULL_FACE: 33 case GL_POLYGON_OFFSET_FILL: 34 case GL_SAMPLE_ALPHA_TO_COVERAGE: 35 case GL_SAMPLE_COVERAGE: 36 case GL_SCISSOR_TEST: 37 case GL_STENCIL_TEST: 38 case GL_DEPTH_TEST: 39 case GL_BLEND: 40 case GL_DITHER: 41 return true; 42 case GL_PRIMITIVE_RESTART_FIXED_INDEX: 43 case GL_RASTERIZER_DISCARD: 44 return (context->getClientVersion() >= 3); 45 default: 46 return false; 47 } 48 } 49 50 bool ValidTextureTarget(const Context *context, GLenum target) 51 { 52 switch (target) 53 { 54 case GL_TEXTURE_2D: 55 case GL_TEXTURE_CUBE_MAP: 56 return true; 57 58 case GL_TEXTURE_3D: 59 case GL_TEXTURE_2D_ARRAY: 60 return (context->getClientVersion() >= 3); 61 62 default: 63 return false; 64 } 65 } 66 67 // This function differs from ValidTextureTarget in that the target must be 68 // usable as the destination of a 2D operation-- so a cube face is valid, but 69 // GL_TEXTURE_CUBE_MAP is not. 70 // Note: duplicate of IsInternalTextureTarget 71 bool ValidTexture2DDestinationTarget(const Context *context, GLenum target) 72 { 73 switch (target) 74 { 75 case GL_TEXTURE_2D: 76 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 77 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 78 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 80 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 82 return true; 83 case GL_TEXTURE_2D_ARRAY: 84 case GL_TEXTURE_3D: 85 return (context->getClientVersion() >= 3); 86 default: 87 return false; 88 } 89 } 90 91 bool ValidFramebufferTarget(GLenum target) 92 { 93 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER); 94 95 switch (target) 96 { 97 case GL_FRAMEBUFFER: return true; 98 case GL_READ_FRAMEBUFFER: return true; 99 case GL_DRAW_FRAMEBUFFER: return true; 100 default: return false; 101 } 102 } 103 104 bool ValidBufferTarget(const Context *context, GLenum target) 105 { 106 switch (target) 107 { 108 case GL_ARRAY_BUFFER: 109 case GL_ELEMENT_ARRAY_BUFFER: 110 return true; 111 112 case GL_PIXEL_PACK_BUFFER: 113 case GL_PIXEL_UNPACK_BUFFER: 114 return context->supportsPBOs(); 115 116 case GL_COPY_READ_BUFFER: 117 case GL_COPY_WRITE_BUFFER: 118 case GL_TRANSFORM_FEEDBACK_BUFFER: 119 case GL_UNIFORM_BUFFER: 120 return (context->getClientVersion() >= 3); 121 122 default: 123 return false; 124 } 125 } 126 127 bool ValidBufferParameter(const Context *context, GLenum pname) 128 { 129 switch (pname) 130 { 131 case GL_BUFFER_USAGE: 132 case GL_BUFFER_SIZE: 133 return true; 134 135 // GL_BUFFER_MAP_POINTER is a special case, and may only be 136 // queried with GetBufferPointerv 137 case GL_BUFFER_ACCESS_FLAGS: 138 case GL_BUFFER_MAPPED: 139 case GL_BUFFER_MAP_OFFSET: 140 case GL_BUFFER_MAP_LENGTH: 141 return (context->getClientVersion() >= 3); 142 143 default: 144 return false; 145 } 146 } 147 148 bool ValidMipLevel(const Context *context, GLenum target, GLint level) 149 { 150 int maxLevel = 0; 151 switch (target) 152 { 153 case GL_TEXTURE_2D: maxLevel = context->getMaximum2DTextureLevel(); break; 154 case GL_TEXTURE_CUBE_MAP: 155 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 156 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 157 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 159 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 160 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxLevel = context->getMaximumCubeTextureLevel(); break; 161 case GL_TEXTURE_3D: maxLevel = context->getMaximum3DTextureLevel(); break; 162 case GL_TEXTURE_2D_ARRAY: maxLevel = context->getMaximum2DArrayTextureLevel(); break; 163 default: UNREACHABLE(); 164 } 165 166 return level < maxLevel; 167 } 168 169 bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, 170 GLsizei width, GLsizei height, GLsizei depth) 171 { 172 if (level < 0 || width < 0 || height < 0 || depth < 0) 173 { 174 return false; 175 } 176 177 if (!context->supportsNonPower2Texture() && 178 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) 179 { 180 return false; 181 } 182 183 if (!ValidMipLevel(context, target, level)) 184 { 185 return false; 186 } 187 188 return true; 189 } 190 191 bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height) 192 { 193 GLuint clientVersion = context->getClientVersion(); 194 if (!IsFormatCompressed(internalFormat, clientVersion)) 195 { 196 return false; 197 } 198 199 GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion); 200 GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion); 201 if (width < 0 || (width > blockWidth && width % blockWidth != 0) || 202 height < 0 || (height > blockHeight && height % blockHeight != 0)) 203 { 204 return false; 205 } 206 207 return true; 208 } 209 210 bool ValidQueryType(const Context *context, GLenum queryType) 211 { 212 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT); 213 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); 214 215 switch (queryType) 216 { 217 case GL_ANY_SAMPLES_PASSED: 218 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 219 return true; 220 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 221 return (context->getClientVersion() >= 3); 222 default: 223 return false; 224 } 225 } 226 227 bool ValidProgram(const Context *context, GLuint id) 228 { 229 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the 230 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and 231 // INVALID_OPERATION if the provided name identifies an object that is not the expected type." 232 233 if (context->getProgram(id) != NULL) 234 { 235 return true; 236 } 237 else if (context->getShader(id) != NULL) 238 { 239 // ID is the wrong type 240 return gl::error(GL_INVALID_OPERATION, false); 241 } 242 else 243 { 244 // No shader/program object has this ID 245 return gl::error(GL_INVALID_VALUE, false); 246 } 247 } 248 249 bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples, 250 GLenum internalformat, GLsizei width, GLsizei height, 251 bool angleExtension) 252 { 253 switch (target) 254 { 255 case GL_RENDERBUFFER: 256 break; 257 default: 258 return gl::error(GL_INVALID_ENUM, false); 259 } 260 261 if (width < 0 || height < 0 || samples < 0) 262 { 263 return gl::error(GL_INVALID_VALUE, false); 264 } 265 266 if (!gl::IsValidInternalFormat(internalformat, context)) 267 { 268 return gl::error(GL_INVALID_ENUM, false); 269 } 270 271 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be 272 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains 273 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the 274 // internal format must be sized and not an integer format if samples is greater than zero. 275 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion())) 276 { 277 return gl::error(GL_INVALID_ENUM, false); 278 } 279 280 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion()); 281 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0) 282 { 283 return gl::error(GL_INVALID_OPERATION, false); 284 } 285 286 if (!gl::IsColorRenderingSupported(internalformat, context) && 287 !gl::IsDepthRenderingSupported(internalformat, context) && 288 !gl::IsStencilRenderingSupported(internalformat, context)) 289 { 290 return gl::error(GL_INVALID_ENUM, false); 291 } 292 293 if (std::max(width, height) > context->getMaximumRenderbufferDimension()) 294 { 295 return gl::error(GL_INVALID_VALUE, false); 296 } 297 298 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal 299 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2) 300 // states that samples must be less than or equal to the maximum samples for the specified 301 // internal format. 302 if (angleExtension) 303 { 304 if (samples > context->getMaxSupportedSamples()) 305 { 306 return gl::error(GL_INVALID_VALUE, false); 307 } 308 } 309 else 310 { 311 if (samples > context->getMaxSupportedFormatSamples(internalformat)) 312 { 313 return gl::error(GL_INVALID_VALUE, false); 314 } 315 } 316 317 GLuint handle = context->getRenderbufferHandle(); 318 if (handle == 0) 319 { 320 return gl::error(GL_INVALID_OPERATION, false); 321 } 322 323 return true; 324 } 325 326 bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, 327 GLenum renderbuffertarget, GLuint renderbuffer) 328 { 329 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target); 330 GLuint framebufferHandle = context->getTargetFramebufferHandle(target); 331 332 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) 333 { 334 return gl::error(GL_INVALID_OPERATION, false); 335 } 336 337 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) 338 { 339 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); 340 341 if (colorAttachment >= context->getMaximumRenderTargets()) 342 { 343 return gl::error(GL_INVALID_VALUE, false); 344 } 345 } 346 else 347 { 348 switch (attachment) 349 { 350 case GL_DEPTH_ATTACHMENT: 351 break; 352 case GL_STENCIL_ATTACHMENT: 353 break; 354 case GL_DEPTH_STENCIL_ATTACHMENT: 355 if (context->getClientVersion() < 3) 356 { 357 return gl::error(GL_INVALID_ENUM, false); 358 } 359 break; 360 default: 361 return gl::error(GL_INVALID_ENUM, false); 362 } 363 } 364 365 // [OpenGL ES 2.0.25] Section 4.4.3 page 112 366 // [OpenGL ES 3.0.2] Section 4.4.2 page 201 367 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of 368 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. 369 if (renderbuffer != 0) 370 { 371 if (!context->getRenderbuffer(renderbuffer)) 372 { 373 return gl::error(GL_INVALID_OPERATION, false); 374 } 375 } 376 377 return true; 378 } 379 380 static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer, 381 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 382 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) 383 { 384 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || 385 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() || 386 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight()) 387 { 388 return true; 389 } 390 else if (context->isScissorTestEnabled()) 391 { 392 int scissorX, scissorY, scissorWidth, scissorHeight; 393 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight); 394 395 return scissorX > 0 || scissorY > 0 || 396 scissorWidth < writeBuffer->getWidth() || 397 scissorHeight < writeBuffer->getHeight(); 398 } 399 else 400 { 401 return false; 402 } 403 } 404 405 bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 406 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, 407 GLenum filter, bool fromAngleExtension) 408 { 409 switch (filter) 410 { 411 case GL_NEAREST: 412 break; 413 case GL_LINEAR: 414 if (fromAngleExtension) 415 { 416 return gl::error(GL_INVALID_ENUM, false); 417 } 418 break; 419 default: 420 return gl::error(GL_INVALID_ENUM, false); 421 } 422 423 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) 424 { 425 return gl::error(GL_INVALID_VALUE, false); 426 } 427 428 if (mask == 0) 429 { 430 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no 431 // buffers are copied. 432 return false; 433 } 434 435 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)) 436 { 437 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."); 438 return gl::error(GL_INVALID_OPERATION, false); 439 } 440 441 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the 442 // color buffer, leaving only nearest being unfiltered from above 443 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST) 444 { 445 return gl::error(GL_INVALID_OPERATION, false); 446 } 447 448 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle()) 449 { 450 if (fromAngleExtension) 451 { 452 ERR("Blits with the same source and destination framebuffer are not supported by this " 453 "implementation."); 454 } 455 return gl::error(GL_INVALID_OPERATION, false); 456 } 457 458 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer(); 459 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer(); 460 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || 461 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) 462 { 463 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); 464 } 465 466 if (drawFramebuffer->getSamples() != 0) 467 { 468 return gl::error(GL_INVALID_OPERATION, false); 469 } 470 471 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; 472 473 GLuint clientVersion = context->getClientVersion(); 474 475 if (mask & GL_COLOR_BUFFER_BIT) 476 { 477 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); 478 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); 479 480 if (readColorBuffer && drawColorBuffer) 481 { 482 GLenum readInternalFormat = readColorBuffer->getActualFormat(); 483 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion); 484 485 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) 486 { 487 if (drawFramebuffer->isEnabledColorAttachment(i)) 488 { 489 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat(); 490 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion); 491 492 // The GL ES 3.0.2 spec (pg 193) states that: 493 // 1) If the read buffer is fixed point format, the draw buffer must be as well 494 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well 495 // 3) If the read buffer is a signed integer format, the draw buffer must be as well 496 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) && 497 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED)) 498 { 499 return gl::error(GL_INVALID_OPERATION, false); 500 } 501 502 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT) 503 { 504 return gl::error(GL_INVALID_OPERATION, false); 505 } 506 507 if (readComponentType == GL_INT && drawComponentType != GL_INT) 508 { 509 return gl::error(GL_INVALID_OPERATION, false); 510 } 511 512 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) 513 { 514 return gl::error(GL_INVALID_OPERATION, false); 515 } 516 } 517 } 518 519 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) 520 { 521 return gl::error(GL_INVALID_OPERATION, false); 522 } 523 524 if (fromAngleExtension) 525 { 526 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType(); 527 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER) 528 { 529 return gl::error(GL_INVALID_OPERATION, false); 530 } 531 532 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) 533 { 534 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) 535 { 536 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D && 537 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER) 538 { 539 return gl::error(GL_INVALID_OPERATION, false); 540 } 541 542 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat()) 543 { 544 return gl::error(GL_INVALID_OPERATION, false); 545 } 546 } 547 } 548 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, 549 srcX0, srcY0, srcX1, srcY1, 550 dstX0, dstY0, dstX1, dstY1)) 551 { 552 return gl::error(GL_INVALID_OPERATION, false); 553 } 554 } 555 } 556 } 557 558 if (mask & GL_DEPTH_BUFFER_BIT) 559 { 560 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer(); 561 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer(); 562 563 if (readDepthBuffer && drawDepthBuffer) 564 { 565 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat()) 566 { 567 return gl::error(GL_INVALID_OPERATION, false); 568 } 569 570 if (readDepthBuffer->getSamples() > 0 && !sameBounds) 571 { 572 return gl::error(GL_INVALID_OPERATION, false); 573 } 574 575 if (fromAngleExtension) 576 { 577 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer, 578 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) 579 { 580 ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); 581 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted 582 } 583 584 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0) 585 { 586 return gl::error(GL_INVALID_OPERATION, false); 587 } 588 } 589 } 590 } 591 592 if (mask & GL_STENCIL_BUFFER_BIT) 593 { 594 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer(); 595 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer(); 596 597 if (readStencilBuffer && drawStencilBuffer) 598 { 599 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat()) 600 { 601 return gl::error(GL_INVALID_OPERATION, false); 602 } 603 604 if (readStencilBuffer->getSamples() > 0 && !sameBounds) 605 { 606 return gl::error(GL_INVALID_OPERATION, false); 607 } 608 609 if (fromAngleExtension) 610 { 611 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer, 612 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) 613 { 614 ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); 615 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted 616 } 617 618 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0) 619 { 620 return gl::error(GL_INVALID_OPERATION, false); 621 } 622 } 623 } 624 } 625 626 return true; 627 } 628 629 bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion) 630 { 631 switch (pname) 632 { 633 case GL_VERTEX_ATTRIB_ARRAY_ENABLED: 634 case GL_VERTEX_ATTRIB_ARRAY_SIZE: 635 case GL_VERTEX_ATTRIB_ARRAY_STRIDE: 636 case GL_VERTEX_ATTRIB_ARRAY_TYPE: 637 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: 638 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 639 case GL_CURRENT_VERTEX_ATTRIB: 640 return true; 641 642 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: 643 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses 644 // the same constant. 645 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); 646 return true; 647 648 case GL_VERTEX_ATTRIB_ARRAY_INTEGER: 649 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false)); 650 651 default: 652 return gl::error(GL_INVALID_ENUM, false); 653 } 654 } 655 656 bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) 657 { 658 switch (pname) 659 { 660 case GL_TEXTURE_WRAP_R: 661 case GL_TEXTURE_SWIZZLE_R: 662 case GL_TEXTURE_SWIZZLE_G: 663 case GL_TEXTURE_SWIZZLE_B: 664 case GL_TEXTURE_SWIZZLE_A: 665 case GL_TEXTURE_BASE_LEVEL: 666 case GL_TEXTURE_MAX_LEVEL: 667 case GL_TEXTURE_COMPARE_MODE: 668 case GL_TEXTURE_COMPARE_FUNC: 669 case GL_TEXTURE_MIN_LOD: 670 case GL_TEXTURE_MAX_LOD: 671 if (context->getClientVersion() < 3) 672 { 673 return gl::error(GL_INVALID_ENUM, false); 674 } 675 break; 676 677 default: break; 678 } 679 680 switch (pname) 681 { 682 case GL_TEXTURE_WRAP_S: 683 case GL_TEXTURE_WRAP_T: 684 case GL_TEXTURE_WRAP_R: 685 switch (param) 686 { 687 case GL_REPEAT: 688 case GL_CLAMP_TO_EDGE: 689 case GL_MIRRORED_REPEAT: 690 return true; 691 default: 692 return gl::error(GL_INVALID_ENUM, false); 693 } 694 695 case GL_TEXTURE_MIN_FILTER: 696 switch (param) 697 { 698 case GL_NEAREST: 699 case GL_LINEAR: 700 case GL_NEAREST_MIPMAP_NEAREST: 701 case GL_LINEAR_MIPMAP_NEAREST: 702 case GL_NEAREST_MIPMAP_LINEAR: 703 case GL_LINEAR_MIPMAP_LINEAR: 704 return true; 705 default: 706 return gl::error(GL_INVALID_ENUM, false); 707 } 708 break; 709 710 case GL_TEXTURE_MAG_FILTER: 711 switch (param) 712 { 713 case GL_NEAREST: 714 case GL_LINEAR: 715 return true; 716 default: 717 return gl::error(GL_INVALID_ENUM, false); 718 } 719 break; 720 721 case GL_TEXTURE_USAGE_ANGLE: 722 switch (param) 723 { 724 case GL_NONE: 725 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: 726 return true; 727 default: 728 return gl::error(GL_INVALID_ENUM, false); 729 } 730 break; 731 732 case GL_TEXTURE_MAX_ANISOTROPY_EXT: 733 if (!context->supportsTextureFilterAnisotropy()) 734 { 735 return gl::error(GL_INVALID_ENUM, false); 736 } 737 738 // we assume the parameter passed to this validation method is truncated, not rounded 739 if (param < 1) 740 { 741 return gl::error(GL_INVALID_VALUE, false); 742 } 743 return true; 744 745 case GL_TEXTURE_MIN_LOD: 746 case GL_TEXTURE_MAX_LOD: 747 // any value is permissible 748 return true; 749 750 case GL_TEXTURE_COMPARE_MODE: 751 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 752 switch (param) 753 { 754 case GL_NONE: 755 case GL_COMPARE_REF_TO_TEXTURE: 756 return true; 757 default: 758 return gl::error(GL_INVALID_ENUM, false); 759 } 760 break; 761 762 case GL_TEXTURE_COMPARE_FUNC: 763 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 764 switch (param) 765 { 766 case GL_LEQUAL: 767 case GL_GEQUAL: 768 case GL_LESS: 769 case GL_GREATER: 770 case GL_EQUAL: 771 case GL_NOTEQUAL: 772 case GL_ALWAYS: 773 case GL_NEVER: 774 return true; 775 default: 776 return gl::error(GL_INVALID_ENUM, false); 777 } 778 break; 779 780 case GL_TEXTURE_SWIZZLE_R: 781 case GL_TEXTURE_SWIZZLE_G: 782 case GL_TEXTURE_SWIZZLE_B: 783 case GL_TEXTURE_SWIZZLE_A: 784 switch (param) 785 { 786 case GL_RED: 787 case GL_GREEN: 788 case GL_BLUE: 789 case GL_ALPHA: 790 case GL_ZERO: 791 case GL_ONE: 792 return true; 793 default: 794 return gl::error(GL_INVALID_ENUM, false); 795 } 796 break; 797 798 case GL_TEXTURE_BASE_LEVEL: 799 case GL_TEXTURE_MAX_LEVEL: 800 if (param < 0) 801 { 802 return gl::error(GL_INVALID_VALUE, false); 803 } 804 return true; 805 806 default: 807 return gl::error(GL_INVALID_ENUM, false); 808 } 809 } 810 811 bool ValidateSamplerObjectParameter(GLenum pname) 812 { 813 switch (pname) 814 { 815 case GL_TEXTURE_MIN_FILTER: 816 case GL_TEXTURE_MAG_FILTER: 817 case GL_TEXTURE_WRAP_S: 818 case GL_TEXTURE_WRAP_T: 819 case GL_TEXTURE_WRAP_R: 820 case GL_TEXTURE_MIN_LOD: 821 case GL_TEXTURE_MAX_LOD: 822 case GL_TEXTURE_COMPARE_MODE: 823 case GL_TEXTURE_COMPARE_FUNC: 824 return true; 825 826 default: 827 return gl::error(GL_INVALID_ENUM, false); 828 } 829 } 830 831 bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, 832 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels) 833 { 834 gl::Framebuffer *framebuffer = context->getReadFramebuffer(); 835 ASSERT(framebuffer); 836 837 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) 838 { 839 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); 840 } 841 842 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) 843 { 844 return gl::error(GL_INVALID_OPERATION, false); 845 } 846 847 if (!framebuffer->getReadColorbuffer()) 848 { 849 return gl::error(GL_INVALID_OPERATION, false); 850 } 851 852 GLenum currentInternalFormat, currentFormat, currentType; 853 int clientVersion = context->getClientVersion(); 854 855 context->getCurrentReadFormatType(¤tInternalFormat, ¤tFormat, ¤tType); 856 857 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : 858 ValidES3ReadFormatType(context, currentInternalFormat, format, type); 859 860 if (!(currentFormat == format && currentType == type) && !validReadFormat) 861 { 862 return gl::error(GL_INVALID_OPERATION, false); 863 } 864 865 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format : 866 GetSizedInternalFormat(format, type, clientVersion); 867 868 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment()); 869 // sized query sanity check 870 if (bufSize) 871 { 872 int requiredSize = outputPitch * height; 873 if (requiredSize > *bufSize) 874 { 875 return gl::error(GL_INVALID_OPERATION, false); 876 } 877 } 878 879 return true; 880 } 881 882 bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) 883 { 884 if (!ValidQueryType(context, target)) 885 { 886 return gl::error(GL_INVALID_ENUM, false); 887 } 888 889 if (id == 0) 890 { 891 return gl::error(GL_INVALID_OPERATION, false); 892 } 893 894 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id> 895 // of zero, if the active query object name for <target> is non-zero (for the 896 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if 897 // the active query for either target is non-zero), if <id> is the name of an 898 // existing query object whose type does not match <target>, or if <id> is the 899 // active query object name for any query type, the error INVALID_OPERATION is 900 // generated. 901 902 // Ensure no other queries are active 903 // NOTE: If other queries than occlusion are supported, we will need to check 904 // separately that: 905 // a) The query ID passed is not the current active query for any target/type 906 // b) There are no active queries for the requested target (and in the case 907 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, 908 // no query may be active for either if glBeginQuery targets either. 909 if (context->isQueryActive()) 910 { 911 return gl::error(GL_INVALID_OPERATION, false); 912 } 913 914 Query *queryObject = context->getQuery(id, true, target); 915 916 // check that name was obtained with glGenQueries 917 if (!queryObject) 918 { 919 return gl::error(GL_INVALID_OPERATION, false); 920 } 921 922 // check for type mismatch 923 if (queryObject->getType() != target) 924 { 925 return gl::error(GL_INVALID_OPERATION, false); 926 } 927 928 return true; 929 } 930 931 bool ValidateEndQuery(gl::Context *context, GLenum target) 932 { 933 if (!ValidQueryType(context, target)) 934 { 935 return gl::error(GL_INVALID_ENUM, false); 936 } 937 938 const Query *queryObject = context->getActiveQuery(target); 939 940 if (queryObject == NULL) 941 { 942 return gl::error(GL_INVALID_OPERATION, false); 943 } 944 945 if (!queryObject->isStarted()) 946 { 947 return gl::error(GL_INVALID_OPERATION, false); 948 } 949 950 return true; 951 } 952 953 static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType, 954 GLint location, GLsizei count, LinkedUniform **uniformOut) 955 { 956 if (count < 0) 957 { 958 return gl::error(GL_INVALID_VALUE, false); 959 } 960 961 gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); 962 if (!programBinary) 963 { 964 return gl::error(GL_INVALID_OPERATION, false); 965 } 966 967 if (location == -1) 968 { 969 // Silently ignore the uniform command 970 return false; 971 } 972 973 if (!programBinary->isValidUniformLocation(location)) 974 { 975 return gl::error(GL_INVALID_OPERATION, false); 976 } 977 978 LinkedUniform *uniform = programBinary->getUniformByLocation(location); 979 980 // attempting to write an array to a non-array uniform is an INVALID_OPERATION 981 if (uniform->elementCount() == 1 && count > 1) 982 { 983 return gl::error(GL_INVALID_OPERATION, false); 984 } 985 986 *uniformOut = uniform; 987 return true; 988 } 989 990 bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) 991 { 992 // Check for ES3 uniform entry points 993 if (UniformComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) 994 { 995 return gl::error(GL_INVALID_OPERATION, false); 996 } 997 998 LinkedUniform *uniform = NULL; 999 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) 1000 { 1001 return false; 1002 } 1003 1004 GLenum targetBoolType = UniformBoolVectorType(uniformType); 1005 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT); 1006 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) 1007 { 1008 return gl::error(GL_INVALID_OPERATION, false); 1009 } 1010 1011 return true; 1012 } 1013 1014 bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, 1015 GLboolean transpose) 1016 { 1017 // Check for ES3 uniform entry points 1018 int rows = VariableRowCount(matrixType); 1019 int cols = VariableColumnCount(matrixType); 1020 if (rows != cols && context->getClientVersion() < 3) 1021 { 1022 return gl::error(GL_INVALID_OPERATION, false); 1023 } 1024 1025 if (transpose != GL_FALSE && context->getClientVersion() < 3) 1026 { 1027 return gl::error(GL_INVALID_VALUE, false); 1028 } 1029 1030 LinkedUniform *uniform = NULL; 1031 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) 1032 { 1033 return false; 1034 } 1035 1036 if (uniform->type != matrixType) 1037 { 1038 return gl::error(GL_INVALID_OPERATION, false); 1039 } 1040 1041 return true; 1042 } 1043 1044 bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) 1045 { 1046 if (!context->getQueryParameterInfo(pname, nativeType, numParams)) 1047 { 1048 return gl::error(GL_INVALID_ENUM, false); 1049 } 1050 1051 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) 1052 { 1053 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); 1054 1055 if (colorAttachment >= context->getMaximumRenderTargets()) 1056 { 1057 return gl::error(GL_INVALID_OPERATION, false); 1058 } 1059 } 1060 1061 switch (pname) 1062 { 1063 case GL_TEXTURE_BINDING_2D: 1064 case GL_TEXTURE_BINDING_CUBE_MAP: 1065 case GL_TEXTURE_BINDING_3D: 1066 case GL_TEXTURE_BINDING_2D_ARRAY: 1067 if (context->getActiveSampler() >= context->getMaximumCombinedTextureImageUnits()) 1068 { 1069 return gl::error(GL_INVALID_OPERATION, false); 1070 } 1071 break; 1072 1073 case GL_IMPLEMENTATION_COLOR_READ_TYPE: 1074 case GL_IMPLEMENTATION_COLOR_READ_FORMAT: 1075 { 1076 Framebuffer *framebuffer = context->getReadFramebuffer(); 1077 ASSERT(framebuffer); 1078 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) 1079 { 1080 return gl::error(GL_INVALID_OPERATION, false); 1081 } 1082 1083 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); 1084 if (!attachment) 1085 { 1086 return gl::error(GL_INVALID_OPERATION, false); 1087 } 1088 } 1089 break; 1090 1091 default: 1092 break; 1093 } 1094 1095 // pname is valid, but there are no parameters to return 1096 if (numParams == 0) 1097 { 1098 return false; 1099 } 1100 1101 return true; 1102 } 1103 1104 bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, 1105 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, 1106 GLint border, GLenum *textureFormatOut) 1107 { 1108 1109 if (!ValidTexture2DDestinationTarget(context, target)) 1110 { 1111 return gl::error(GL_INVALID_ENUM, false); 1112 } 1113 1114 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) 1115 { 1116 return gl::error(GL_INVALID_VALUE, false); 1117 } 1118 1119 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height) 1120 { 1121 return gl::error(GL_INVALID_VALUE, false); 1122 } 1123 1124 if (border != 0) 1125 { 1126 return gl::error(GL_INVALID_VALUE, false); 1127 } 1128 1129 if (!ValidMipLevel(context, target, level)) 1130 { 1131 return gl::error(GL_INVALID_VALUE, false); 1132 } 1133 1134 gl::Framebuffer *framebuffer = context->getReadFramebuffer(); 1135 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) 1136 { 1137 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); 1138 } 1139 1140 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) 1141 { 1142 return gl::error(GL_INVALID_OPERATION, false); 1143 } 1144 1145 gl::Texture *texture = NULL; 1146 GLenum textureInternalFormat = GL_NONE; 1147 bool textureCompressed = false; 1148 bool textureIsDepth = false; 1149 GLint textureLevelWidth = 0; 1150 GLint textureLevelHeight = 0; 1151 GLint textureLevelDepth = 0; 1152 int maxDimension = 0; 1153 1154 switch (target) 1155 { 1156 case GL_TEXTURE_2D: 1157 { 1158 gl::Texture2D *texture2d = context->getTexture2D(); 1159 if (texture2d) 1160 { 1161 textureInternalFormat = texture2d->getInternalFormat(level); 1162 textureCompressed = texture2d->isCompressed(level); 1163 textureIsDepth = texture2d->isDepth(level); 1164 textureLevelWidth = texture2d->getWidth(level); 1165 textureLevelHeight = texture2d->getHeight(level); 1166 textureLevelDepth = 1; 1167 texture = texture2d; 1168 maxDimension = context->getMaximum2DTextureDimension(); 1169 } 1170 } 1171 break; 1172 1173 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 1174 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1175 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 1176 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 1177 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 1178 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 1179 { 1180 gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); 1181 if (textureCube) 1182 { 1183 textureInternalFormat = textureCube->getInternalFormat(target, level); 1184 textureCompressed = textureCube->isCompressed(target, level); 1185 textureIsDepth = false; 1186 textureLevelWidth = textureCube->getWidth(target, level); 1187 textureLevelHeight = textureCube->getHeight(target, level); 1188 textureLevelDepth = 1; 1189 texture = textureCube; 1190 maxDimension = context->getMaximumCubeTextureDimension(); 1191 } 1192 } 1193 break; 1194 1195 case GL_TEXTURE_2D_ARRAY: 1196 { 1197 gl::Texture2DArray *texture2dArray = context->getTexture2DArray(); 1198 if (texture2dArray) 1199 { 1200 textureInternalFormat = texture2dArray->getInternalFormat(level); 1201 textureCompressed = texture2dArray->isCompressed(level); 1202 textureIsDepth = texture2dArray->isDepth(level); 1203 textureLevelWidth = texture2dArray->getWidth(level); 1204 textureLevelHeight = texture2dArray->getHeight(level); 1205 textureLevelDepth = texture2dArray->getLayers(level); 1206 texture = texture2dArray; 1207 maxDimension = context->getMaximum2DTextureDimension(); 1208 } 1209 } 1210 break; 1211 1212 case GL_TEXTURE_3D: 1213 { 1214 gl::Texture3D *texture3d = context->getTexture3D(); 1215 if (texture3d) 1216 { 1217 textureInternalFormat = texture3d->getInternalFormat(level); 1218 textureCompressed = texture3d->isCompressed(level); 1219 textureIsDepth = texture3d->isDepth(level); 1220 textureLevelWidth = texture3d->getWidth(level); 1221 textureLevelHeight = texture3d->getHeight(level); 1222 textureLevelDepth = texture3d->getDepth(level); 1223 texture = texture3d; 1224 maxDimension = context->getMaximum3DTextureDimension(); 1225 } 1226 } 1227 break; 1228 1229 default: 1230 return gl::error(GL_INVALID_ENUM, false); 1231 } 1232 1233 if (!texture) 1234 { 1235 return gl::error(GL_INVALID_OPERATION, false); 1236 } 1237 1238 if (texture->isImmutable() && !isSubImage) 1239 { 1240 return gl::error(GL_INVALID_OPERATION, false); 1241 } 1242 1243 if (textureIsDepth) 1244 { 1245 return gl::error(GL_INVALID_OPERATION, false); 1246 } 1247 1248 if (textureCompressed) 1249 { 1250 int clientVersion = context->getClientVersion(); 1251 GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat, clientVersion); 1252 GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat, clientVersion); 1253 1254 if (((width % blockWidth) != 0 && width != textureLevelWidth) || 1255 ((height % blockHeight) != 0 && height != textureLevelHeight)) 1256 { 1257 return gl::error(GL_INVALID_OPERATION, false); 1258 } 1259 } 1260 1261 if (isSubImage) 1262 { 1263 if (xoffset + width > textureLevelWidth || 1264 yoffset + height > textureLevelHeight || 1265 zoffset >= textureLevelDepth) 1266 { 1267 return gl::error(GL_INVALID_VALUE, false); 1268 } 1269 } 1270 else 1271 { 1272 if (IsCubemapTextureTarget(target) && width != height) 1273 { 1274 return gl::error(GL_INVALID_VALUE, false); 1275 } 1276 1277 if (!IsValidInternalFormat(internalformat, context)) 1278 { 1279 return gl::error(GL_INVALID_ENUM, false); 1280 } 1281 1282 int maxLevelDimension = (maxDimension >> level); 1283 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension) 1284 { 1285 return gl::error(GL_INVALID_VALUE, false); 1286 } 1287 } 1288 1289 *textureFormatOut = textureInternalFormat; 1290 return true; 1291 } 1292 1293 } 1294