1 // 2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Texture.cpp: Implements the gl::Texture class and its derived classes 8 // Texture2D and TextureCubeMap. Implements GL texture objects and related 9 // functionality. [OpenGL ES 2.0.24] section 3.7 page 63. 10 11 #include "libGLESv2/Texture.h" 12 #include "libGLESv2/main.h" 13 #include "libGLESv2/Context.h" 14 #include "libGLESv2/formatutils.h" 15 #include "libGLESv2/ImageIndex.h" 16 #include "libGLESv2/Renderbuffer.h" 17 #include "libGLESv2/renderer/Image.h" 18 #include "libGLESv2/renderer/d3d/TextureStorage.h" 19 20 #include "libEGL/Surface.h" 21 22 #include "common/mathutil.h" 23 #include "common/utilities.h" 24 25 namespace gl 26 { 27 28 bool IsMipmapFiltered(const gl::SamplerState &samplerState) 29 { 30 switch (samplerState.minFilter) 31 { 32 case GL_NEAREST: 33 case GL_LINEAR: 34 return false; 35 case GL_NEAREST_MIPMAP_NEAREST: 36 case GL_LINEAR_MIPMAP_NEAREST: 37 case GL_NEAREST_MIPMAP_LINEAR: 38 case GL_LINEAR_MIPMAP_LINEAR: 39 return true; 40 default: UNREACHABLE(); 41 return false; 42 } 43 } 44 45 bool IsPointSampled(const gl::SamplerState &samplerState) 46 { 47 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); 48 } 49 50 Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) 51 : RefCountObject(id), 52 mTexture(impl), 53 mUsage(GL_NONE), 54 mImmutable(false), 55 mTarget(target) 56 { 57 } 58 59 Texture::~Texture() 60 { 61 SafeDelete(mTexture); 62 } 63 64 GLenum Texture::getTarget() const 65 { 66 return mTarget; 67 } 68 69 void Texture::setUsage(GLenum usage) 70 { 71 mUsage = usage; 72 getImplementation()->setUsage(usage); 73 } 74 75 void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler) 76 { 77 *sampler = mSamplerState; 78 79 // Offset the effective base level by the texture storage's top level 80 rx::TextureStorage *texture = getNativeTexture(); 81 int topLevel = texture ? texture->getTopLevel() : 0; 82 sampler->baseLevel = topLevel + mSamplerState.baseLevel; 83 } 84 85 GLenum Texture::getUsage() const 86 { 87 return mUsage; 88 } 89 90 GLint Texture::getBaseLevelWidth() const 91 { 92 const rx::Image *baseImage = getBaseLevelImage(); 93 return (baseImage ? baseImage->getWidth() : 0); 94 } 95 96 GLint Texture::getBaseLevelHeight() const 97 { 98 const rx::Image *baseImage = getBaseLevelImage(); 99 return (baseImage ? baseImage->getHeight() : 0); 100 } 101 102 GLint Texture::getBaseLevelDepth() const 103 { 104 const rx::Image *baseImage = getBaseLevelImage(); 105 return (baseImage ? baseImage->getDepth() : 0); 106 } 107 108 // Note: "base level image" is loosely defined to be any image from the base level, 109 // where in the base of 2D array textures and cube maps there are several. Don't use 110 // the base level image for anything except querying texture format and size. 111 GLenum Texture::getBaseLevelInternalFormat() const 112 { 113 const rx::Image *baseImage = getBaseLevelImage(); 114 return (baseImage ? baseImage->getInternalFormat() : GL_NONE); 115 } 116 117 GLsizei Texture::getWidth(const ImageIndex &index) const 118 { 119 rx::Image *image = mTexture->getImage(index); 120 return image->getWidth(); 121 } 122 123 GLsizei Texture::getHeight(const ImageIndex &index) const 124 { 125 rx::Image *image = mTexture->getImage(index); 126 return image->getHeight(); 127 } 128 129 GLenum Texture::getInternalFormat(const ImageIndex &index) const 130 { 131 rx::Image *image = mTexture->getImage(index); 132 return image->getInternalFormat(); 133 } 134 135 GLenum Texture::getActualFormat(const ImageIndex &index) const 136 { 137 rx::Image *image = mTexture->getImage(index); 138 return image->getActualFormat(); 139 } 140 141 rx::TextureStorage *Texture::getNativeTexture() 142 { 143 return getImplementation()->getNativeTexture(); 144 } 145 146 void Texture::generateMipmaps() 147 { 148 getImplementation()->generateMipmaps(); 149 } 150 151 void Texture::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 152 { 153 getImplementation()->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); 154 } 155 156 unsigned int Texture::getTextureSerial() 157 { 158 rx::TextureStorage *texture = getNativeTexture(); 159 return texture ? texture->getTextureSerial() : 0; 160 } 161 162 bool Texture::isImmutable() const 163 { 164 return mImmutable; 165 } 166 167 int Texture::immutableLevelCount() 168 { 169 return (mImmutable ? getNativeTexture()->getLevelCount() : 0); 170 } 171 172 int Texture::mipLevels() const 173 { 174 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; 175 } 176 177 const rx::Image *Texture::getBaseLevelImage() const 178 { 179 return (getImplementation()->getLayerCount(0) > 0 ? getImplementation()->getImage(0, 0) : NULL); 180 } 181 182 Texture2D::Texture2D(rx::TextureImpl *impl, GLuint id) 183 : Texture(impl, id, GL_TEXTURE_2D) 184 { 185 mSurface = NULL; 186 } 187 188 Texture2D::~Texture2D() 189 { 190 if (mSurface) 191 { 192 mSurface->setBoundTexture(NULL); 193 mSurface = NULL; 194 } 195 } 196 197 GLsizei Texture2D::getWidth(GLint level) const 198 { 199 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 200 return mTexture->getImage(level, 0)->getWidth(); 201 else 202 return 0; 203 } 204 205 GLsizei Texture2D::getHeight(GLint level) const 206 { 207 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 208 return mTexture->getImage(level, 0)->getHeight(); 209 else 210 return 0; 211 } 212 213 GLenum Texture2D::getInternalFormat(GLint level) const 214 { 215 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 216 return mTexture->getImage(level, 0)->getInternalFormat(); 217 else 218 return GL_NONE; 219 } 220 221 GLenum Texture2D::getActualFormat(GLint level) const 222 { 223 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 224 return mTexture->getImage(level, 0)->getActualFormat(); 225 else 226 return GL_NONE; 227 } 228 229 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 230 { 231 releaseTexImage(); 232 233 mTexture->setImage(GL_TEXTURE_2D, level, width, height, 1, internalFormat, format, type, unpack, pixels); 234 } 235 236 void Texture2D::bindTexImage(egl::Surface *surface) 237 { 238 releaseTexImage(); 239 240 mTexture->bindTexImage(surface); 241 242 mSurface = surface; 243 mSurface->setBoundTexture(this); 244 } 245 246 void Texture2D::releaseTexImage() 247 { 248 if (mSurface) 249 { 250 mSurface->setBoundTexture(NULL); 251 mSurface = NULL; 252 253 mTexture->releaseTexImage(); 254 } 255 } 256 257 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 258 { 259 releaseTexImage(); 260 261 mTexture->setCompressedImage(GL_TEXTURE_2D, level, format, width, height, 1, imageSize, pixels); 262 } 263 264 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 265 { 266 mTexture->subImage(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); 267 } 268 269 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 270 { 271 mTexture->subImageCompressed(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels); 272 } 273 274 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 275 { 276 releaseTexImage(); 277 278 mTexture->copyImage(GL_TEXTURE_2D, level, format, x, y, width, height, source); 279 } 280 281 void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) 282 { 283 mImmutable = true; 284 285 mTexture->storage(GL_TEXTURE_2D, levels, internalformat, width, height, 1); 286 } 287 288 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. 289 bool Texture2D::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const 290 { 291 GLsizei width = getBaseLevelWidth(); 292 GLsizei height = getBaseLevelHeight(); 293 294 if (width <= 0 || height <= 0) 295 { 296 return false; 297 } 298 299 if (!textureCaps.get(getInternalFormat(0)).filterable && !IsPointSampled(samplerState)) 300 { 301 return false; 302 } 303 304 bool npotSupport = extensions.textureNPOT; 305 306 if (!npotSupport) 307 { 308 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) || 309 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height))) 310 { 311 return false; 312 } 313 } 314 315 if (IsMipmapFiltered(samplerState)) 316 { 317 if (!npotSupport) 318 { 319 if (!gl::isPow2(width) || !gl::isPow2(height)) 320 { 321 return false; 322 } 323 } 324 325 if (!isMipmapComplete()) 326 { 327 return false; 328 } 329 } 330 331 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: 332 // The internalformat specified for the texture arrays is a sized internal depth or 333 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- 334 // MODE is NONE, and either the magnification filter is not NEAREST or the mini- 335 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. 336 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(0)); 337 if (formatInfo.depthBits > 0 && clientVersion > 2) 338 { 339 if (samplerState.compareMode == GL_NONE) 340 { 341 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || 342 samplerState.magFilter != GL_NEAREST) 343 { 344 return false; 345 } 346 } 347 } 348 349 return true; 350 } 351 352 bool Texture2D::isCompressed(GLint level) const 353 { 354 return GetInternalFormatInfo(getInternalFormat(level)).compressed; 355 } 356 357 bool Texture2D::isDepth(GLint level) const 358 { 359 return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 360 } 361 362 void Texture2D::generateMipmaps() 363 { 364 releaseTexImage(); 365 366 mTexture->generateMipmaps(); 367 } 368 369 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 370 bool Texture2D::isMipmapComplete() const 371 { 372 int levelCount = mipLevels(); 373 374 for (int level = 0; level < levelCount; level++) 375 { 376 if (!isLevelComplete(level)) 377 { 378 return false; 379 } 380 } 381 382 return true; 383 } 384 385 bool Texture2D::isLevelComplete(int level) const 386 { 387 if (isImmutable()) 388 { 389 return true; 390 } 391 392 const rx::Image *baseImage = getBaseLevelImage(); 393 394 GLsizei width = baseImage->getWidth(); 395 GLsizei height = baseImage->getHeight(); 396 397 if (width <= 0 || height <= 0) 398 { 399 return false; 400 } 401 402 // The base image level is complete if the width and height are positive 403 if (level == 0) 404 { 405 return true; 406 } 407 408 ASSERT(level >= 1 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getImage(level, 0) != NULL); 409 rx::Image *image = mTexture->getImage(level, 0); 410 411 if (image->getInternalFormat() != baseImage->getInternalFormat()) 412 { 413 return false; 414 } 415 416 if (image->getWidth() != std::max(1, width >> level)) 417 { 418 return false; 419 } 420 421 if (image->getHeight() != std::max(1, height >> level)) 422 { 423 return false; 424 } 425 426 return true; 427 } 428 429 TextureCubeMap::TextureCubeMap(rx::TextureImpl *impl, GLuint id) 430 : Texture(impl, id, GL_TEXTURE_CUBE_MAP) 431 { 432 } 433 434 TextureCubeMap::~TextureCubeMap() 435 { 436 } 437 438 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const 439 { 440 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 441 return mTexture->getImage(level, targetToLayerIndex(target))->getWidth(); 442 else 443 return 0; 444 } 445 446 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const 447 { 448 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 449 return mTexture->getImage(level, targetToLayerIndex(target))->getHeight(); 450 else 451 return 0; 452 } 453 454 GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const 455 { 456 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 457 return mTexture->getImage(level, targetToLayerIndex(target))->getInternalFormat(); 458 else 459 return GL_NONE; 460 } 461 462 GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const 463 { 464 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 465 return mTexture->getImage(level, targetToLayerIndex(target))->getActualFormat(); 466 else 467 return GL_NONE; 468 } 469 470 void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 471 { 472 mTexture->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, width, height, 1, internalFormat, format, type, unpack, pixels); 473 } 474 475 void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 476 { 477 mTexture->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, width, height, 1, internalFormat, format, type, unpack, pixels); 478 } 479 480 void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 481 { 482 mTexture->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, width, height, 1, internalFormat, format, type, unpack, pixels); 483 } 484 485 void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 486 { 487 mTexture->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, width, height, 1, internalFormat, format, type, unpack, pixels); 488 } 489 490 void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 491 { 492 mTexture->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, width, height, 1, internalFormat, format, type, unpack, pixels); 493 } 494 495 void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 496 { 497 mTexture->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, width, height, 1, internalFormat, format, type, unpack, pixels); 498 } 499 500 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 501 { 502 mTexture->setCompressedImage(target, level, format, width, height, 1, imageSize, pixels); 503 } 504 505 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 506 { 507 mTexture->subImage(target, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); 508 } 509 510 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 511 { 512 mTexture->subImageCompressed(target, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels); 513 } 514 515 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 516 bool TextureCubeMap::isCubeComplete() const 517 { 518 int baseWidth = getBaseLevelWidth(); 519 int baseHeight = getBaseLevelHeight(); 520 GLenum baseFormat = getBaseLevelInternalFormat(); 521 522 if (baseWidth <= 0 || baseWidth != baseHeight) 523 { 524 return false; 525 } 526 527 for (int faceIndex = 1; faceIndex < 6; faceIndex++) 528 { 529 const rx::Image *faceBaseImage = mTexture->getImage(0, faceIndex); 530 531 if (faceBaseImage->getWidth() != baseWidth || 532 faceBaseImage->getHeight() != baseHeight || 533 faceBaseImage->getInternalFormat() != baseFormat ) 534 { 535 return false; 536 } 537 } 538 539 return true; 540 } 541 542 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const 543 { 544 return GetInternalFormatInfo(getInternalFormat(target, level)).compressed; 545 } 546 547 bool TextureCubeMap::isDepth(GLenum target, GLint level) const 548 { 549 return GetInternalFormatInfo(getInternalFormat(target, level)).depthBits > 0; 550 } 551 552 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 553 { 554 mTexture->copyImage(target, level, format, x, y, width, height, source); 555 } 556 557 void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) 558 { 559 mImmutable = true; 560 561 mTexture->storage(GL_TEXTURE_CUBE_MAP, levels, internalformat, size, size, 1); 562 } 563 564 // Tests for texture sampling completeness 565 bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const 566 { 567 int size = getBaseLevelWidth(); 568 569 bool mipmapping = IsMipmapFiltered(samplerState); 570 571 if (!textureCaps.get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filterable && !IsPointSampled(samplerState)) 572 { 573 return false; 574 } 575 576 if (!gl::isPow2(size) && !extensions.textureNPOT) 577 { 578 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) 579 { 580 return false; 581 } 582 } 583 584 if (!mipmapping) 585 { 586 if (!isCubeComplete()) 587 { 588 return false; 589 } 590 } 591 else 592 { 593 if (!isMipmapComplete()) // Also tests for isCubeComplete() 594 { 595 return false; 596 } 597 } 598 599 return true; 600 } 601 602 int TextureCubeMap::targetToLayerIndex(GLenum target) 603 { 604 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); 605 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); 606 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); 607 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); 608 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); 609 610 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 611 } 612 613 GLenum TextureCubeMap::layerIndexToTarget(GLint layer) 614 { 615 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); 616 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); 617 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); 618 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); 619 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); 620 621 return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; 622 } 623 624 bool TextureCubeMap::isMipmapComplete() const 625 { 626 if (isImmutable()) 627 { 628 return true; 629 } 630 631 if (!isCubeComplete()) 632 { 633 return false; 634 } 635 636 int levelCount = mipLevels(); 637 638 for (int face = 0; face < 6; face++) 639 { 640 for (int level = 1; level < levelCount; level++) 641 { 642 if (!isFaceLevelComplete(face, level)) 643 { 644 return false; 645 } 646 } 647 } 648 649 return true; 650 } 651 652 bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const 653 { 654 ASSERT(level >= 0 && faceIndex < 6 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getImage(level, faceIndex) != NULL); 655 656 if (isImmutable()) 657 { 658 return true; 659 } 660 661 int baseSize = getBaseLevelWidth(); 662 663 if (baseSize <= 0) 664 { 665 return false; 666 } 667 668 // "isCubeComplete" checks for base level completeness and we must call that 669 // to determine if any face at level 0 is complete. We omit that check here 670 // to avoid re-checking cube-completeness for every face at level 0. 671 if (level == 0) 672 { 673 return true; 674 } 675 676 // Check that non-zero levels are consistent with the base level. 677 const rx::Image *faceLevelImage = mTexture->getImage(level, faceIndex); 678 679 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) 680 { 681 return false; 682 } 683 684 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) 685 { 686 return false; 687 } 688 689 return true; 690 } 691 692 693 Texture3D::Texture3D(rx::TextureImpl *impl, GLuint id) 694 : Texture(impl, id, GL_TEXTURE_3D) 695 { 696 } 697 698 Texture3D::~Texture3D() 699 { 700 } 701 702 GLsizei Texture3D::getWidth(GLint level) const 703 { 704 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getWidth() : 0; 705 } 706 707 GLsizei Texture3D::getHeight(GLint level) const 708 { 709 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getHeight() : 0; 710 } 711 712 GLsizei Texture3D::getDepth(GLint level) const 713 { 714 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getDepth() : 0; 715 } 716 717 GLenum Texture3D::getInternalFormat(GLint level) const 718 { 719 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getInternalFormat() : GL_NONE; 720 } 721 722 GLenum Texture3D::getActualFormat(GLint level) const 723 { 724 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getActualFormat() : GL_NONE; 725 } 726 727 bool Texture3D::isCompressed(GLint level) const 728 { 729 return GetInternalFormatInfo(getInternalFormat(level)).compressed; 730 } 731 732 bool Texture3D::isDepth(GLint level) const 733 { 734 return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 735 } 736 737 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 738 { 739 mTexture->setImage(GL_TEXTURE_3D, level, width, height, depth, internalFormat, format, type, unpack, pixels); 740 } 741 742 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 743 { 744 mTexture->setCompressedImage(GL_TEXTURE_3D, level, format, width, height, depth, imageSize, pixels); 745 } 746 747 void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 748 { 749 mTexture->subImage(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); 750 } 751 752 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 753 { 754 mTexture->subImageCompressed(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); 755 } 756 757 void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 758 { 759 mImmutable = true; 760 761 mTexture->storage(GL_TEXTURE_3D, levels, internalformat, width, height, depth); 762 } 763 764 bool Texture3D::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const 765 { 766 GLsizei width = getBaseLevelWidth(); 767 GLsizei height = getBaseLevelHeight(); 768 GLsizei depth = getBaseLevelDepth(); 769 770 if (width <= 0 || height <= 0 || depth <= 0) 771 { 772 return false; 773 } 774 775 if (!textureCaps.get(getInternalFormat(0)).filterable && !IsPointSampled(samplerState)) 776 { 777 return false; 778 } 779 780 if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) 781 { 782 return false; 783 } 784 785 return true; 786 } 787 788 bool Texture3D::isMipmapComplete() const 789 { 790 int levelCount = mipLevels(); 791 792 for (int level = 0; level < levelCount; level++) 793 { 794 if (!isLevelComplete(level)) 795 { 796 return false; 797 } 798 } 799 800 return true; 801 } 802 803 bool Texture3D::isLevelComplete(int level) const 804 { 805 ASSERT(level >= 0 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getImage(level, 0) != NULL); 806 807 if (isImmutable()) 808 { 809 return true; 810 } 811 812 GLsizei width = getBaseLevelWidth(); 813 GLsizei height = getBaseLevelHeight(); 814 GLsizei depth = getBaseLevelDepth(); 815 816 if (width <= 0 || height <= 0 || depth <= 0) 817 { 818 return false; 819 } 820 821 if (level == 0) 822 { 823 return true; 824 } 825 826 rx::Image *levelImage = mTexture->getImage(level, 0); 827 828 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) 829 { 830 return false; 831 } 832 833 if (levelImage->getWidth() != std::max(1, width >> level)) 834 { 835 return false; 836 } 837 838 if (levelImage->getHeight() != std::max(1, height >> level)) 839 { 840 return false; 841 } 842 843 if (levelImage->getDepth() != std::max(1, depth >> level)) 844 { 845 return false; 846 } 847 848 return true; 849 } 850 851 Texture2DArray::Texture2DArray(rx::TextureImpl *impl, GLuint id) 852 : Texture(impl, id, GL_TEXTURE_2D_ARRAY) 853 { 854 } 855 856 Texture2DArray::~Texture2DArray() 857 { 858 } 859 860 GLsizei Texture2DArray::getWidth(GLint level) const 861 { 862 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getWidth() : 0; 863 } 864 865 GLsizei Texture2DArray::getHeight(GLint level) const 866 { 867 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getHeight() : 0; 868 } 869 870 GLsizei Texture2DArray::getLayers(GLint level) const 871 { 872 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getLayerCount(level) : 0; 873 } 874 875 GLenum Texture2DArray::getInternalFormat(GLint level) const 876 { 877 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getInternalFormat() : GL_NONE; 878 } 879 880 GLenum Texture2DArray::getActualFormat(GLint level) const 881 { 882 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getActualFormat() : GL_NONE; 883 } 884 885 bool Texture2DArray::isCompressed(GLint level) const 886 { 887 return GetInternalFormatInfo(getInternalFormat(level)).compressed; 888 } 889 890 bool Texture2DArray::isDepth(GLint level) const 891 { 892 return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 893 } 894 895 void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 896 { 897 mTexture->setImage(GL_TEXTURE_2D_ARRAY, level, width, height, depth, internalFormat, format, type, unpack, pixels); 898 } 899 900 void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 901 { 902 mTexture->setCompressedImage(GL_TEXTURE_2D_ARRAY, level, format, width, height, depth, imageSize, pixels); 903 } 904 905 void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) 906 { 907 mTexture->subImage(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); 908 } 909 910 void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 911 { 912 mTexture->subImageCompressed(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); 913 } 914 915 void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 916 { 917 mImmutable = true; 918 919 mTexture->storage(GL_TEXTURE_2D_ARRAY, levels, internalformat, width, height, depth); 920 } 921 922 bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const 923 { 924 GLsizei width = getBaseLevelWidth(); 925 GLsizei height = getBaseLevelHeight(); 926 GLsizei depth = getLayers(0); 927 928 if (width <= 0 || height <= 0 || depth <= 0) 929 { 930 return false; 931 } 932 933 if (!textureCaps.get(getBaseLevelInternalFormat()).filterable && !IsPointSampled(samplerState)) 934 { 935 return false; 936 } 937 938 if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) 939 { 940 return false; 941 } 942 943 return true; 944 } 945 946 bool Texture2DArray::isMipmapComplete() const 947 { 948 int levelCount = mipLevels(); 949 950 for (int level = 1; level < levelCount; level++) 951 { 952 if (!isLevelComplete(level)) 953 { 954 return false; 955 } 956 } 957 958 return true; 959 } 960 961 bool Texture2DArray::isLevelComplete(int level) const 962 { 963 ASSERT(level >= 0 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 964 965 if (isImmutable()) 966 { 967 return true; 968 } 969 970 GLsizei width = getBaseLevelWidth(); 971 GLsizei height = getBaseLevelHeight(); 972 GLsizei layers = getLayers(0); 973 974 if (width <= 0 || height <= 0 || layers <= 0) 975 { 976 return false; 977 } 978 979 if (level == 0) 980 { 981 return true; 982 } 983 984 if (getInternalFormat(level) != getInternalFormat(0)) 985 { 986 return false; 987 } 988 989 if (getWidth(level) != std::max(1, width >> level)) 990 { 991 return false; 992 } 993 994 if (getHeight(level) != std::max(1, height >> level)) 995 { 996 return false; 997 } 998 999 if (getLayers(level) != layers) 1000 { 1001 return false; 1002 } 1003 1004 return true; 1005 } 1006 1007 } 1008