Texture.cpp (85913B)
1 // 2 // Copyright 2002 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. [OpenGL ES 2.0.24] section 3.7 page 63. 8 9 #include "libANGLE/Texture.h" 10 11 #include "common/mathutil.h" 12 #include "common/utilities.h" 13 #include "libANGLE/Config.h" 14 #include "libANGLE/Context.h" 15 #include "libANGLE/Image.h" 16 #include "libANGLE/State.h" 17 #include "libANGLE/Surface.h" 18 #include "libANGLE/formatutils.h" 19 #include "libANGLE/renderer/GLImplFactory.h" 20 #include "libANGLE/renderer/TextureImpl.h" 21 22 namespace gl 23 { 24 25 namespace 26 { 27 constexpr angle::SubjectIndex kBufferSubjectIndex = 2; 28 static_assert(kBufferSubjectIndex != rx::kTextureImageImplObserverMessageIndex, "Index collision"); 29 static_assert(kBufferSubjectIndex != rx::kTextureImageSiblingMessageIndex, "Index collision"); 30 31 bool IsPointSampled(const SamplerState &samplerState) 32 { 33 return (samplerState.getMagFilter() == GL_NEAREST && 34 (samplerState.getMinFilter() == GL_NEAREST || 35 samplerState.getMinFilter() == GL_NEAREST_MIPMAP_NEAREST)); 36 } 37 38 size_t GetImageDescIndex(TextureTarget target, size_t level) 39 { 40 return IsCubeMapFaceTarget(target) ? (level * 6 + CubeMapTextureTargetToFaceIndex(target)) 41 : level; 42 } 43 44 InitState DetermineInitState(const Context *context, Buffer *unpackBuffer, const uint8_t *pixels) 45 { 46 // Can happen in tests. 47 if (!context || !context->isRobustResourceInitEnabled()) 48 { 49 return InitState::Initialized; 50 } 51 52 return (!pixels && !unpackBuffer) ? InitState::MayNeedInit : InitState::Initialized; 53 } 54 } // namespace 55 56 GLenum ConvertToNearestFilterMode(GLenum filterMode) 57 { 58 switch (filterMode) 59 { 60 case GL_LINEAR: 61 return GL_NEAREST; 62 case GL_LINEAR_MIPMAP_NEAREST: 63 return GL_NEAREST_MIPMAP_NEAREST; 64 case GL_LINEAR_MIPMAP_LINEAR: 65 return GL_NEAREST_MIPMAP_LINEAR; 66 default: 67 return filterMode; 68 } 69 } 70 71 GLenum ConvertToNearestMipFilterMode(GLenum filterMode) 72 { 73 switch (filterMode) 74 { 75 case GL_LINEAR_MIPMAP_LINEAR: 76 return GL_LINEAR_MIPMAP_NEAREST; 77 case GL_NEAREST_MIPMAP_LINEAR: 78 return GL_NEAREST_MIPMAP_NEAREST; 79 default: 80 return filterMode; 81 } 82 } 83 84 bool IsMipmapSupported(const TextureType &type) 85 { 86 if (type == TextureType::_2DMultisample || type == TextureType::Buffer) 87 { 88 return false; 89 } 90 return true; 91 } 92 93 SwizzleState::SwizzleState() 94 : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA) 95 {} 96 97 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha) 98 : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) 99 {} 100 101 bool SwizzleState::swizzleRequired() const 102 { 103 return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE || 104 swizzleAlpha != GL_ALPHA; 105 } 106 107 bool SwizzleState::operator==(const SwizzleState &other) const 108 { 109 return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen && 110 swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha; 111 } 112 113 bool SwizzleState::operator!=(const SwizzleState &other) const 114 { 115 return !(*this == other); 116 } 117 118 TextureState::TextureState(TextureType type) 119 : mType(type), 120 mSamplerState(SamplerState::CreateDefaultForTarget(type)), 121 mSrgbOverride(SrgbOverride::Default), 122 mBaseLevel(0), 123 mMaxLevel(kInitialMaxLevel), 124 mDepthStencilTextureMode(GL_DEPTH_COMPONENT), 125 mHasBeenBoundAsImage(false), 126 mIs3DAndHasBeenBoundAs2DImage(false), 127 mHasBeenBoundAsAttachment(false), 128 mImmutableFormat(false), 129 mImmutableLevels(0), 130 mUsage(GL_NONE), 131 mHasProtectedContent(false), 132 mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)), 133 mCropRect(0, 0, 0, 0), 134 mGenerateMipmapHint(GL_FALSE), 135 mInitState(InitState::Initialized), 136 mCachedSamplerFormat(SamplerFormat::InvalidEnum), 137 mCachedSamplerCompareMode(GL_NONE), 138 mCachedSamplerFormatValid(false) 139 {} 140 141 TextureState::~TextureState() {} 142 143 bool TextureState::swizzleRequired() const 144 { 145 return mSwizzleState.swizzleRequired(); 146 } 147 148 GLuint TextureState::getEffectiveBaseLevel() const 149 { 150 if (mImmutableFormat) 151 { 152 // GLES 3.0.4 section 3.8.10 153 return std::min(mBaseLevel, mImmutableLevels - 1); 154 } 155 // Some classes use the effective base level to index arrays with level data. By clamping the 156 // effective base level to max levels these arrays need just one extra item to store properties 157 // that should be returned for all out-of-range base level values, instead of needing special 158 // handling for out-of-range base levels. 159 return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS)); 160 } 161 162 GLuint TextureState::getEffectiveMaxLevel() const 163 { 164 if (mImmutableFormat) 165 { 166 // GLES 3.0.4 section 3.8.10 167 GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel()); 168 clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1); 169 return clampedMaxLevel; 170 } 171 return mMaxLevel; 172 } 173 174 GLuint TextureState::getMipmapMaxLevel() const 175 { 176 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); 177 GLuint expectedMipLevels = 0; 178 if (mType == TextureType::_3D) 179 { 180 const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), 181 baseImageDesc.size.depth); 182 expectedMipLevels = static_cast<GLuint>(log2(maxDim)); 183 } 184 else 185 { 186 expectedMipLevels = static_cast<GLuint>( 187 log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height))); 188 } 189 190 return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel()); 191 } 192 193 bool TextureState::setBaseLevel(GLuint baseLevel) 194 { 195 if (mBaseLevel != baseLevel) 196 { 197 mBaseLevel = baseLevel; 198 return true; 199 } 200 return false; 201 } 202 203 bool TextureState::setMaxLevel(GLuint maxLevel) 204 { 205 if (mMaxLevel != maxLevel) 206 { 207 mMaxLevel = maxLevel; 208 return true; 209 } 210 211 return false; 212 } 213 214 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 215 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any 216 // per-level checks begin at the base-level. 217 // For OpenGL ES2 the base level is always zero. 218 bool TextureState::isCubeComplete() const 219 { 220 ASSERT(mType == TextureType::CubeMap); 221 222 angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin; 223 const ImageDesc &baseImageDesc = getImageDesc(*face, getEffectiveBaseLevel()); 224 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height) 225 { 226 return false; 227 } 228 229 ++face; 230 231 for (; face != kAfterCubeMapTextureTargetMax; ++face) 232 { 233 const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel()); 234 if (faceImageDesc.size.width != baseImageDesc.size.width || 235 faceImageDesc.size.height != baseImageDesc.size.height || 236 !Format::SameSized(faceImageDesc.format, baseImageDesc.format)) 237 { 238 return false; 239 } 240 } 241 242 return true; 243 } 244 245 const ImageDesc &TextureState::getBaseLevelDesc() const 246 { 247 ASSERT(mType != TextureType::CubeMap || isCubeComplete()); 248 return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); 249 } 250 251 const ImageDesc &TextureState::getLevelZeroDesc() const 252 { 253 ASSERT(mType != TextureType::CubeMap || isCubeComplete()); 254 return getImageDesc(getBaseImageTarget(), 0); 255 } 256 257 void TextureState::setCrop(const Rectangle &rect) 258 { 259 mCropRect = rect; 260 } 261 262 const Rectangle &TextureState::getCrop() const 263 { 264 return mCropRect; 265 } 266 267 void TextureState::setGenerateMipmapHint(GLenum hint) 268 { 269 mGenerateMipmapHint = hint; 270 } 271 272 GLenum TextureState::getGenerateMipmapHint() const 273 { 274 return mGenerateMipmapHint; 275 } 276 277 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const 278 { 279 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); 280 if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT || 281 baseImageDesc.format.info->format == GL_DEPTH_STENCIL) && 282 samplerState.getCompareMode() != GL_NONE) 283 { 284 return SamplerFormat::Shadow; 285 } 286 else 287 { 288 switch (baseImageDesc.format.info->componentType) 289 { 290 case GL_UNSIGNED_NORMALIZED: 291 case GL_SIGNED_NORMALIZED: 292 case GL_FLOAT: 293 return SamplerFormat::Float; 294 case GL_INT: 295 return SamplerFormat::Signed; 296 case GL_UNSIGNED_INT: 297 return SamplerFormat::Unsigned; 298 default: 299 return SamplerFormat::InvalidEnum; 300 } 301 } 302 } 303 304 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState, 305 const State &state) const 306 { 307 // Buffer textures cannot be incomplete. 308 if (mType == TextureType::Buffer) 309 { 310 return true; 311 } 312 313 // Check for all non-format-based completeness rules 314 if (!computeSamplerCompletenessForCopyImage(samplerState, state)) 315 { 316 return false; 317 } 318 319 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); 320 321 // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is 322 // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter 323 // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture, 324 // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as 325 // incomplete texture. So, we ignore filtering for multisample texture completeness here. 326 if (!IsMultisampled(mType) && 327 !baseImageDesc.format.info->filterSupport(state.getClientVersion(), 328 state.getExtensions()) && 329 !IsPointSampled(samplerState)) 330 { 331 return false; 332 } 333 334 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: 335 // The internalformat specified for the texture arrays is a sized internal depth or 336 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- 337 // MODE is NONE, and either the magnification filter is not NEAREST or the mini- 338 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. 339 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 && 340 state.getClientMajorVersion() >= 3) 341 { 342 // Note: we restrict this validation to sized types. For the OES_depth_textures 343 // extension, due to some underspecification problems, we must allow linear filtering 344 // for legacy compatibility with WebGL 1. 345 // See http://crbug.com/649200 346 if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized) 347 { 348 if ((samplerState.getMinFilter() != GL_NEAREST && 349 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) || 350 samplerState.getMagFilter() != GL_NEAREST) 351 { 352 return false; 353 } 354 } 355 } 356 357 // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if: 358 // The internalformat specified for the texture is DEPTH_STENCIL format, the value of 359 // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is 360 // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. 361 // However, the ES 3.1 spec differs from the statement above, because it is incorrect. 362 // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33. 363 // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3). 364 // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample 365 // texture completeness here. 366 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 && 367 mDepthStencilTextureMode == GL_STENCIL_INDEX) 368 { 369 if ((samplerState.getMinFilter() != GL_NEAREST && 370 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) || 371 samplerState.getMagFilter() != GL_NEAREST) 372 { 373 return false; 374 } 375 } 376 377 return true; 378 } 379 380 // CopyImageSubData has more lax rules for texture completeness: format-based completeness rules are 381 // ignored, so a texture can still be considered complete even if it violates format-specific 382 // conditions 383 bool TextureState::computeSamplerCompletenessForCopyImage(const SamplerState &samplerState, 384 const State &state) const 385 { 386 // Buffer textures cannot be incomplete. 387 if (mType == TextureType::Buffer) 388 { 389 return true; 390 } 391 392 if (!mImmutableFormat && mBaseLevel > mMaxLevel) 393 { 394 return false; 395 } 396 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); 397 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || 398 baseImageDesc.size.depth == 0) 399 { 400 return false; 401 } 402 // The cases where the texture is incomplete because base level is out of range should be 403 // handled by the above condition. 404 ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat); 405 406 if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height) 407 { 408 return false; 409 } 410 411 bool npotSupport = state.getExtensions().textureNpotOES || state.getClientMajorVersion() >= 3; 412 if (!npotSupport) 413 { 414 if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE && 415 samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) || 416 (samplerState.getWrapT() != GL_CLAMP_TO_EDGE && 417 samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height))) 418 { 419 return false; 420 } 421 } 422 423 if (IsMipmapSupported(mType) && IsMipmapFiltered(samplerState.getMinFilter())) 424 { 425 if (!npotSupport) 426 { 427 if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height)) 428 { 429 return false; 430 } 431 } 432 433 if (!computeMipmapCompleteness()) 434 { 435 return false; 436 } 437 } 438 else 439 { 440 if (mType == TextureType::CubeMap && !isCubeComplete()) 441 { 442 return false; 443 } 444 } 445 446 // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a 447 // texture unit that would have been rejected by a call to TexParameter* for the texture bound 448 // to that unit, the behavior of the implementation is as if the texture were incomplete. For 449 // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the 450 // sampler object bound to a texture unit and the texture bound to that unit is an external 451 // texture and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered 452 // incomplete. 453 // Sampler object state which does not affect sampling for the type of texture bound 454 // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect 455 // completeness. 456 if (mType == TextureType::External) 457 { 458 if (!state.getExtensions().EGLImageExternalWrapModesEXT) 459 { 460 if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE || 461 samplerState.getWrapT() != GL_CLAMP_TO_EDGE) 462 { 463 return false; 464 } 465 } 466 467 if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST) 468 { 469 return false; 470 } 471 } 472 473 return true; 474 } 475 476 bool TextureState::computeMipmapCompleteness() const 477 { 478 const GLuint maxLevel = getMipmapMaxLevel(); 479 480 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++) 481 { 482 if (mType == TextureType::CubeMap) 483 { 484 for (TextureTarget face : AllCubeFaceTextureTargets()) 485 { 486 if (!computeLevelCompleteness(face, level)) 487 { 488 return false; 489 } 490 } 491 } 492 else 493 { 494 if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level)) 495 { 496 return false; 497 } 498 } 499 } 500 501 return true; 502 } 503 504 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const 505 { 506 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); 507 508 if (mImmutableFormat) 509 { 510 return true; 511 } 512 513 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); 514 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || 515 baseImageDesc.size.depth == 0) 516 { 517 return false; 518 } 519 520 const ImageDesc &levelImageDesc = getImageDesc(target, level); 521 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 || 522 levelImageDesc.size.depth == 0) 523 { 524 return false; 525 } 526 527 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format)) 528 { 529 return false; 530 } 531 532 ASSERT(level >= getEffectiveBaseLevel()); 533 const size_t relativeLevel = level - getEffectiveBaseLevel(); 534 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel)) 535 { 536 return false; 537 } 538 539 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel)) 540 { 541 return false; 542 } 543 544 if (mType == TextureType::_3D) 545 { 546 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel)) 547 { 548 return false; 549 } 550 } 551 else if (IsArrayTextureType(mType)) 552 { 553 if (levelImageDesc.size.depth != baseImageDesc.size.depth) 554 { 555 return false; 556 } 557 } 558 559 return true; 560 } 561 562 TextureTarget TextureState::getBaseImageTarget() const 563 { 564 return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin 565 : NonCubeTextureTypeToTarget(mType); 566 } 567 568 GLuint TextureState::getEnabledLevelCount() const 569 { 570 GLuint levelCount = 0; 571 const GLuint baseLevel = getEffectiveBaseLevel(); 572 const GLuint maxLevel = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel()); 573 574 // The mip chain will have either one or more sequential levels, or max levels, 575 // but not a sparse one. 576 Optional<Extents> expectedSize; 577 for (size_t enabledLevel = baseLevel; enabledLevel <= maxLevel; ++enabledLevel, ++levelCount) 578 { 579 // Note: for cube textures, we only check the first face. 580 TextureTarget target = TextureTypeToTarget(mType, 0); 581 size_t descIndex = GetImageDescIndex(target, enabledLevel); 582 const Extents &levelSize = mImageDescs[descIndex].size; 583 584 if (levelSize.empty()) 585 { 586 break; 587 } 588 if (expectedSize.valid()) 589 { 590 Extents newSize = expectedSize.value(); 591 newSize.width = std::max(1, newSize.width >> 1); 592 newSize.height = std::max(1, newSize.height >> 1); 593 594 if (!IsArrayTextureType(mType)) 595 { 596 newSize.depth = std::max(1, newSize.depth >> 1); 597 } 598 599 if (newSize != levelSize) 600 { 601 break; 602 } 603 } 604 expectedSize = levelSize; 605 } 606 607 return levelCount; 608 } 609 610 ImageDesc::ImageDesc() 611 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized) 612 {} 613 614 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState) 615 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState) 616 {} 617 618 ImageDesc::ImageDesc(const Extents &size, 619 const Format &format, 620 const GLsizei samples, 621 const bool fixedSampleLocations, 622 const InitState initState) 623 : size(size), 624 format(format), 625 samples(samples), 626 fixedSampleLocations(fixedSampleLocations), 627 initState(initState) 628 {} 629 630 GLint ImageDesc::getMemorySize() const 631 { 632 // Assume allocated size is around width * height * depth * samples * pixelBytes 633 angle::CheckedNumeric<GLint> levelSize = 1; 634 levelSize *= format.info->pixelBytes; 635 levelSize *= size.width; 636 levelSize *= size.height; 637 levelSize *= size.depth; 638 levelSize *= std::max(samples, 1); 639 return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max()); 640 } 641 642 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const 643 { 644 size_t descIndex = GetImageDescIndex(target, level); 645 ASSERT(descIndex < mImageDescs.size()); 646 return mImageDescs[descIndex]; 647 } 648 649 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc) 650 { 651 size_t descIndex = GetImageDescIndex(target, level); 652 ASSERT(descIndex < mImageDescs.size()); 653 mImageDescs[descIndex] = desc; 654 if (desc.initState == InitState::MayNeedInit) 655 { 656 mInitState = InitState::MayNeedInit; 657 } 658 else 659 { 660 // Scan for any uninitialized images. If there are none, set the init state of the entire 661 // texture to initialized. The cost of the scan is only paid after doing image 662 // initialization which is already very expensive. 663 bool allImagesInitialized = true; 664 665 for (const ImageDesc &initDesc : mImageDescs) 666 { 667 if (initDesc.initState == InitState::MayNeedInit) 668 { 669 allImagesInitialized = false; 670 break; 671 } 672 } 673 674 if (allImagesInitialized) 675 { 676 mInitState = InitState::Initialized; 677 } 678 } 679 } 680 681 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6 682 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube 683 // face, and we don't allow using this function when the cube map is not cube complete. 684 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const 685 { 686 if (imageIndex.isEntireLevelCubeMap()) 687 { 688 ASSERT(isCubeComplete()); 689 const GLint levelIndex = imageIndex.getLevelIndex(); 690 return getImageDesc(kCubeMapTextureTargetMin, levelIndex); 691 } 692 693 return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex()); 694 } 695 696 void TextureState::setImageDescChain(GLuint baseLevel, 697 GLuint maxLevel, 698 Extents baseSize, 699 const Format &format, 700 InitState initState) 701 { 702 for (GLuint level = baseLevel; level <= maxLevel; level++) 703 { 704 int relativeLevel = (level - baseLevel); 705 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1), 706 std::max<int>(baseSize.height >> relativeLevel, 1), 707 (IsArrayTextureType(mType)) 708 ? baseSize.depth 709 : std::max<int>(baseSize.depth >> relativeLevel, 1)); 710 ImageDesc levelInfo(levelSize, format, initState); 711 712 if (mType == TextureType::CubeMap) 713 { 714 for (TextureTarget face : AllCubeFaceTextureTargets()) 715 { 716 setImageDesc(face, level, levelInfo); 717 } 718 } 719 else 720 { 721 setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo); 722 } 723 } 724 } 725 726 void TextureState::setImageDescChainMultisample(Extents baseSize, 727 const Format &format, 728 GLsizei samples, 729 bool fixedSampleLocations, 730 InitState initState) 731 { 732 ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray); 733 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState); 734 setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo); 735 } 736 737 void TextureState::clearImageDesc(TextureTarget target, size_t level) 738 { 739 setImageDesc(target, level, ImageDesc()); 740 } 741 742 void TextureState::clearImageDescs() 743 { 744 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) 745 { 746 mImageDescs[descIndex] = ImageDesc(); 747 } 748 } 749 750 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type) 751 : RefCountObject(factory->generateSerial(), id), 752 mState(type), 753 mTexture(factory->createTexture(mState)), 754 mImplObserver(this, rx::kTextureImageImplObserverMessageIndex), 755 mBufferObserver(this, kBufferSubjectIndex), 756 mBoundSurface(nullptr), 757 mBoundStream(nullptr) 758 { 759 mImplObserver.bind(mTexture); 760 761 // Initially assume the implementation is dirty. 762 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION); 763 } 764 765 void Texture::onDestroy(const Context *context) 766 { 767 if (mBoundSurface) 768 { 769 ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER)); 770 mBoundSurface = nullptr; 771 } 772 if (mBoundStream) 773 { 774 mBoundStream->releaseTextures(); 775 mBoundStream = nullptr; 776 } 777 778 egl::RefCountObjectReleaser<egl::Image> releaseImage; 779 (void)orphanImages(context, &releaseImage); 780 781 mState.mBuffer.set(context, nullptr, 0, 0); 782 783 if (mTexture) 784 { 785 mTexture->onDestroy(context); 786 } 787 } 788 789 Texture::~Texture() 790 { 791 SafeDelete(mTexture); 792 } 793 794 angle::Result Texture::setLabel(const Context *context, const std::string &label) 795 { 796 mState.mLabel = label; 797 return mTexture->onLabelUpdate(context); 798 } 799 800 const std::string &Texture::getLabel() const 801 { 802 return mState.mLabel; 803 } 804 805 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed) 806 { 807 if (mState.mSwizzleState.swizzleRed != swizzleRed) 808 { 809 mState.mSwizzleState.swizzleRed = swizzleRed; 810 signalDirtyState(DIRTY_BIT_SWIZZLE_RED); 811 } 812 } 813 814 GLenum Texture::getSwizzleRed() const 815 { 816 return mState.mSwizzleState.swizzleRed; 817 } 818 819 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen) 820 { 821 if (mState.mSwizzleState.swizzleGreen != swizzleGreen) 822 { 823 mState.mSwizzleState.swizzleGreen = swizzleGreen; 824 signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN); 825 } 826 } 827 828 GLenum Texture::getSwizzleGreen() const 829 { 830 return mState.mSwizzleState.swizzleGreen; 831 } 832 833 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue) 834 { 835 if (mState.mSwizzleState.swizzleBlue != swizzleBlue) 836 { 837 mState.mSwizzleState.swizzleBlue = swizzleBlue; 838 signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE); 839 } 840 } 841 842 GLenum Texture::getSwizzleBlue() const 843 { 844 return mState.mSwizzleState.swizzleBlue; 845 } 846 847 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha) 848 { 849 if (mState.mSwizzleState.swizzleAlpha != swizzleAlpha) 850 { 851 mState.mSwizzleState.swizzleAlpha = swizzleAlpha; 852 signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA); 853 } 854 } 855 856 GLenum Texture::getSwizzleAlpha() const 857 { 858 return mState.mSwizzleState.swizzleAlpha; 859 } 860 861 void Texture::setMinFilter(const Context *context, GLenum minFilter) 862 { 863 if (mState.mSamplerState.setMinFilter(minFilter)) 864 { 865 signalDirtyState(DIRTY_BIT_MIN_FILTER); 866 } 867 } 868 869 GLenum Texture::getMinFilter() const 870 { 871 return mState.mSamplerState.getMinFilter(); 872 } 873 874 void Texture::setMagFilter(const Context *context, GLenum magFilter) 875 { 876 if (mState.mSamplerState.setMagFilter(magFilter)) 877 { 878 signalDirtyState(DIRTY_BIT_MAG_FILTER); 879 } 880 } 881 882 GLenum Texture::getMagFilter() const 883 { 884 return mState.mSamplerState.getMagFilter(); 885 } 886 887 void Texture::setWrapS(const Context *context, GLenum wrapS) 888 { 889 if (mState.mSamplerState.setWrapS(wrapS)) 890 { 891 signalDirtyState(DIRTY_BIT_WRAP_S); 892 } 893 } 894 895 GLenum Texture::getWrapS() const 896 { 897 return mState.mSamplerState.getWrapS(); 898 } 899 900 void Texture::setWrapT(const Context *context, GLenum wrapT) 901 { 902 if (mState.mSamplerState.getWrapT() == wrapT) 903 return; 904 if (mState.mSamplerState.setWrapT(wrapT)) 905 { 906 signalDirtyState(DIRTY_BIT_WRAP_T); 907 } 908 } 909 910 GLenum Texture::getWrapT() const 911 { 912 return mState.mSamplerState.getWrapT(); 913 } 914 915 void Texture::setWrapR(const Context *context, GLenum wrapR) 916 { 917 if (mState.mSamplerState.setWrapR(wrapR)) 918 { 919 signalDirtyState(DIRTY_BIT_WRAP_R); 920 } 921 } 922 923 GLenum Texture::getWrapR() const 924 { 925 return mState.mSamplerState.getWrapR(); 926 } 927 928 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy) 929 { 930 if (mState.mSamplerState.setMaxAnisotropy(maxAnisotropy)) 931 { 932 signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY); 933 } 934 } 935 936 float Texture::getMaxAnisotropy() const 937 { 938 return mState.mSamplerState.getMaxAnisotropy(); 939 } 940 941 void Texture::setMinLod(const Context *context, GLfloat minLod) 942 { 943 if (mState.mSamplerState.setMinLod(minLod)) 944 { 945 signalDirtyState(DIRTY_BIT_MIN_LOD); 946 } 947 } 948 949 GLfloat Texture::getMinLod() const 950 { 951 return mState.mSamplerState.getMinLod(); 952 } 953 954 void Texture::setMaxLod(const Context *context, GLfloat maxLod) 955 { 956 if (mState.mSamplerState.setMaxLod(maxLod)) 957 { 958 signalDirtyState(DIRTY_BIT_MAX_LOD); 959 } 960 } 961 962 GLfloat Texture::getMaxLod() const 963 { 964 return mState.mSamplerState.getMaxLod(); 965 } 966 967 void Texture::setCompareMode(const Context *context, GLenum compareMode) 968 { 969 if (mState.mSamplerState.setCompareMode(compareMode)) 970 { 971 signalDirtyState(DIRTY_BIT_COMPARE_MODE); 972 } 973 } 974 975 GLenum Texture::getCompareMode() const 976 { 977 return mState.mSamplerState.getCompareMode(); 978 } 979 980 void Texture::setCompareFunc(const Context *context, GLenum compareFunc) 981 { 982 if (mState.mSamplerState.setCompareFunc(compareFunc)) 983 { 984 signalDirtyState(DIRTY_BIT_COMPARE_FUNC); 985 } 986 } 987 988 GLenum Texture::getCompareFunc() const 989 { 990 return mState.mSamplerState.getCompareFunc(); 991 } 992 993 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode) 994 { 995 if (mState.mSamplerState.setSRGBDecode(sRGBDecode)) 996 { 997 signalDirtyState(DIRTY_BIT_SRGB_DECODE); 998 } 999 } 1000 1001 GLenum Texture::getSRGBDecode() const 1002 { 1003 return mState.mSamplerState.getSRGBDecode(); 1004 } 1005 1006 void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride) 1007 { 1008 SrgbOverride oldOverride = mState.mSrgbOverride; 1009 mState.mSrgbOverride = (sRGBOverride == GL_SRGB) ? SrgbOverride::SRGB : SrgbOverride::Default; 1010 if (mState.mSrgbOverride != oldOverride) 1011 { 1012 signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE); 1013 } 1014 } 1015 1016 GLenum Texture::getSRGBOverride() const 1017 { 1018 return (mState.mSrgbOverride == SrgbOverride::SRGB) ? GL_SRGB : GL_NONE; 1019 } 1020 1021 const SamplerState &Texture::getSamplerState() const 1022 { 1023 return mState.mSamplerState; 1024 } 1025 1026 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel) 1027 { 1028 if (mState.setBaseLevel(baseLevel)) 1029 { 1030 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel())); 1031 signalDirtyState(DIRTY_BIT_BASE_LEVEL); 1032 } 1033 1034 return angle::Result::Continue; 1035 } 1036 1037 GLuint Texture::getBaseLevel() const 1038 { 1039 return mState.mBaseLevel; 1040 } 1041 1042 void Texture::setMaxLevel(const Context *context, GLuint maxLevel) 1043 { 1044 if (mState.setMaxLevel(maxLevel)) 1045 { 1046 signalDirtyState(DIRTY_BIT_MAX_LEVEL); 1047 } 1048 } 1049 1050 GLuint Texture::getMaxLevel() const 1051 { 1052 return mState.mMaxLevel; 1053 } 1054 1055 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode) 1056 { 1057 if (mState.mDepthStencilTextureMode != mode) 1058 { 1059 mState.mDepthStencilTextureMode = mode; 1060 signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE); 1061 } 1062 } 1063 1064 GLenum Texture::getDepthStencilTextureMode() const 1065 { 1066 return mState.mDepthStencilTextureMode; 1067 } 1068 1069 bool Texture::getImmutableFormat() const 1070 { 1071 return mState.mImmutableFormat; 1072 } 1073 1074 GLuint Texture::getImmutableLevels() const 1075 { 1076 return mState.mImmutableLevels; 1077 } 1078 1079 void Texture::setUsage(const Context *context, GLenum usage) 1080 { 1081 mState.mUsage = usage; 1082 signalDirtyState(DIRTY_BIT_USAGE); 1083 } 1084 1085 GLenum Texture::getUsage() const 1086 { 1087 return mState.mUsage; 1088 } 1089 1090 void Texture::setProtectedContent(Context *context, bool hasProtectedContent) 1091 { 1092 mState.mHasProtectedContent = hasProtectedContent; 1093 } 1094 1095 bool Texture::hasProtectedContent() const 1096 { 1097 return mState.mHasProtectedContent; 1098 } 1099 1100 const TextureState &Texture::getTextureState() const 1101 { 1102 return mState; 1103 } 1104 1105 const Extents &Texture::getExtents(TextureTarget target, size_t level) const 1106 { 1107 ASSERT(TextureTargetToType(target) == mState.mType); 1108 return mState.getImageDesc(target, level).size; 1109 } 1110 1111 size_t Texture::getWidth(TextureTarget target, size_t level) const 1112 { 1113 ASSERT(TextureTargetToType(target) == mState.mType); 1114 return mState.getImageDesc(target, level).size.width; 1115 } 1116 1117 size_t Texture::getHeight(TextureTarget target, size_t level) const 1118 { 1119 ASSERT(TextureTargetToType(target) == mState.mType); 1120 return mState.getImageDesc(target, level).size.height; 1121 } 1122 1123 size_t Texture::getDepth(TextureTarget target, size_t level) const 1124 { 1125 ASSERT(TextureTargetToType(target) == mState.mType); 1126 return mState.getImageDesc(target, level).size.depth; 1127 } 1128 1129 const Format &Texture::getFormat(TextureTarget target, size_t level) const 1130 { 1131 ASSERT(TextureTargetToType(target) == mState.mType); 1132 return mState.getImageDesc(target, level).format; 1133 } 1134 1135 GLsizei Texture::getSamples(TextureTarget target, size_t level) const 1136 { 1137 ASSERT(TextureTargetToType(target) == mState.mType); 1138 return mState.getImageDesc(target, level).samples; 1139 } 1140 1141 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const 1142 { 1143 ASSERT(TextureTargetToType(target) == mState.mType); 1144 return mState.getImageDesc(target, level).fixedSampleLocations; 1145 } 1146 1147 GLuint Texture::getMipmapMaxLevel() const 1148 { 1149 return mState.getMipmapMaxLevel(); 1150 } 1151 1152 bool Texture::isMipmapComplete() const 1153 { 1154 return mState.computeMipmapCompleteness(); 1155 } 1156 1157 egl::Surface *Texture::getBoundSurface() const 1158 { 1159 return mBoundSurface; 1160 } 1161 1162 egl::Stream *Texture::getBoundStream() const 1163 { 1164 return mBoundStream; 1165 } 1166 1167 GLint Texture::getMemorySize() const 1168 { 1169 GLint implSize = mTexture->getMemorySize(); 1170 if (implSize > 0) 1171 { 1172 return implSize; 1173 } 1174 1175 angle::CheckedNumeric<GLint> size = 0; 1176 for (const ImageDesc &imageDesc : mState.mImageDescs) 1177 { 1178 size += imageDesc.getMemorySize(); 1179 } 1180 return size.ValueOrDefault(std::numeric_limits<GLint>::max()); 1181 } 1182 1183 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const 1184 { 1185 GLint implSize = mTexture->getLevelMemorySize(target, level); 1186 if (implSize > 0) 1187 { 1188 return implSize; 1189 } 1190 1191 return mState.getImageDesc(target, level).getMemorySize(); 1192 } 1193 1194 void Texture::signalDirtyStorage(InitState initState) 1195 { 1196 mState.mInitState = initState; 1197 invalidateCompletenessCache(); 1198 mState.mCachedSamplerFormatValid = false; 1199 onStateChange(angle::SubjectMessage::SubjectChanged); 1200 } 1201 1202 void Texture::signalDirtyState(size_t dirtyBit) 1203 { 1204 mDirtyBits.set(dirtyBit); 1205 invalidateCompletenessCache(); 1206 mState.mCachedSamplerFormatValid = false; 1207 1208 if (dirtyBit == DIRTY_BIT_BASE_LEVEL || dirtyBit == DIRTY_BIT_MAX_LEVEL) 1209 { 1210 onStateChange(angle::SubjectMessage::SubjectChanged); 1211 } 1212 else 1213 { 1214 onStateChange(angle::SubjectMessage::DirtyBitsFlagged); 1215 } 1216 } 1217 1218 angle::Result Texture::setImage(Context *context, 1219 const PixelUnpackState &unpackState, 1220 Buffer *unpackBuffer, 1221 TextureTarget target, 1222 GLint level, 1223 GLenum internalFormat, 1224 const Extents &size, 1225 GLenum format, 1226 GLenum type, 1227 const uint8_t *pixels) 1228 { 1229 ASSERT(TextureTargetToType(target) == mState.mType); 1230 1231 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1232 ANGLE_TRY(releaseTexImageInternal(context)); 1233 1234 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1235 ANGLE_TRY(orphanImages(context, &releaseImage)); 1236 1237 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth); 1238 1239 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState, 1240 unpackBuffer, pixels)); 1241 1242 InitState initState = DetermineInitState(context, unpackBuffer, pixels); 1243 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState)); 1244 1245 ANGLE_TRY(handleMipmapGenerationHint(context, level)); 1246 1247 signalDirtyStorage(initState); 1248 1249 return angle::Result::Continue; 1250 } 1251 1252 angle::Result Texture::setSubImage(Context *context, 1253 const PixelUnpackState &unpackState, 1254 Buffer *unpackBuffer, 1255 TextureTarget target, 1256 GLint level, 1257 const Box &area, 1258 GLenum format, 1259 GLenum type, 1260 const uint8_t *pixels) 1261 { 1262 ASSERT(TextureTargetToType(target) == mState.mType); 1263 1264 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth); 1265 ANGLE_TRY(ensureSubImageInitialized(context, index, area)); 1266 1267 ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer, 1268 pixels)); 1269 1270 ANGLE_TRY(handleMipmapGenerationHint(context, level)); 1271 1272 onStateChange(angle::SubjectMessage::ContentsChanged); 1273 1274 return angle::Result::Continue; 1275 } 1276 1277 angle::Result Texture::setCompressedImage(Context *context, 1278 const PixelUnpackState &unpackState, 1279 TextureTarget target, 1280 GLint level, 1281 GLenum internalFormat, 1282 const Extents &size, 1283 size_t imageSize, 1284 const uint8_t *pixels) 1285 { 1286 ASSERT(TextureTargetToType(target) == mState.mType); 1287 1288 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1289 ANGLE_TRY(releaseTexImageInternal(context)); 1290 1291 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1292 ANGLE_TRY(orphanImages(context, &releaseImage)); 1293 1294 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth); 1295 1296 ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState, 1297 imageSize, pixels)); 1298 1299 Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack); 1300 1301 InitState initState = DetermineInitState(context, unpackBuffer, pixels); 1302 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState)); 1303 signalDirtyStorage(initState); 1304 1305 return angle::Result::Continue; 1306 } 1307 1308 angle::Result Texture::setCompressedSubImage(const Context *context, 1309 const PixelUnpackState &unpackState, 1310 TextureTarget target, 1311 GLint level, 1312 const Box &area, 1313 GLenum format, 1314 size_t imageSize, 1315 const uint8_t *pixels) 1316 { 1317 ASSERT(TextureTargetToType(target) == mState.mType); 1318 1319 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth); 1320 ANGLE_TRY(ensureSubImageInitialized(context, index, area)); 1321 1322 ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize, 1323 pixels)); 1324 1325 onStateChange(angle::SubjectMessage::ContentsChanged); 1326 1327 return angle::Result::Continue; 1328 } 1329 1330 angle::Result Texture::copyImage(Context *context, 1331 TextureTarget target, 1332 GLint level, 1333 const Rectangle &sourceArea, 1334 GLenum internalFormat, 1335 Framebuffer *source) 1336 { 1337 ASSERT(TextureTargetToType(target) == mState.mType); 1338 1339 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1340 ANGLE_TRY(releaseTexImageInternal(context)); 1341 1342 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1343 ANGLE_TRY(orphanImages(context, &releaseImage)); 1344 1345 ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1); 1346 1347 const InternalFormat &internalFormatInfo = 1348 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); 1349 1350 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving 1351 // other pixels untouched. For safety in robust resource initialization, assume that that 1352 // clipping is going to occur when computing the region for which to ensure initialization. If 1353 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is 1354 // going to be set during the copy operation. 1355 Box destBox; 1356 bool forceCopySubImage = false; 1357 if (context->isRobustResourceInitEnabled()) 1358 { 1359 const FramebufferAttachment *sourceReadAttachment = source->getReadColorAttachment(); 1360 Extents fbSize = sourceReadAttachment->getSize(); 1361 // Force using copySubImage when the source area is out of bounds AND 1362 // we're not copying to and from the same texture 1363 forceCopySubImage = ((sourceArea.x < 0) || (sourceArea.y < 0) || 1364 ((sourceArea.x + sourceArea.width) > fbSize.width) || 1365 ((sourceArea.y + sourceArea.height) > fbSize.height)) && 1366 (sourceReadAttachment->getResource() != this); 1367 Rectangle clippedArea; 1368 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) 1369 { 1370 const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 1371 0); 1372 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width, 1373 clippedArea.height, 1); 1374 } 1375 } 1376 1377 InitState initState = DetermineInitState(context, nullptr, nullptr); 1378 1379 // If we need to initialize the destination texture we split the call into a create call, 1380 // an initializeContents call, and then a copySubImage call. This ensures the destination 1381 // texture exists before we try to clear it. 1382 Extents size(sourceArea.width, sourceArea.height, 1); 1383 if (forceCopySubImage || doesSubImageNeedInit(context, index, destBox)) 1384 { 1385 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, 1386 internalFormatInfo.format, internalFormatInfo.type, 1387 PixelUnpackState(), nullptr, nullptr)); 1388 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormatInfo), initState)); 1389 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox)); 1390 ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source)); 1391 } 1392 else 1393 { 1394 ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source)); 1395 } 1396 1397 mState.setImageDesc(target, level, 1398 ImageDesc(size, Format(internalFormatInfo), InitState::Initialized)); 1399 1400 ANGLE_TRY(handleMipmapGenerationHint(context, level)); 1401 1402 // Because this could affect the texture storage we might need to init other layers/levels. 1403 signalDirtyStorage(initState); 1404 1405 return angle::Result::Continue; 1406 } 1407 1408 angle::Result Texture::copySubImage(Context *context, 1409 const ImageIndex &index, 1410 const Offset &destOffset, 1411 const Rectangle &sourceArea, 1412 Framebuffer *source) 1413 { 1414 ASSERT(TextureTargetToType(index.getTarget()) == mState.mType); 1415 1416 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving 1417 // other pixels untouched. For safety in robust resource initialization, assume that that 1418 // clipping is going to occur when computing the region for which to ensure initialization. If 1419 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is 1420 // going to be set during the copy operation. Note that this assumes that 1421 // ensureSubImageInitialized ensures initialization of the entire destination texture, and not 1422 // just a sub-region. 1423 Box destBox; 1424 if (context->isRobustResourceInitEnabled()) 1425 { 1426 Extents fbSize = source->getReadColorAttachment()->getSize(); 1427 Rectangle clippedArea; 1428 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) 1429 { 1430 const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x, 1431 destOffset.y + clippedArea.y - sourceArea.y, 0); 1432 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width, 1433 clippedArea.height, 1); 1434 } 1435 } 1436 1437 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox)); 1438 1439 ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source)); 1440 ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex())); 1441 1442 onStateChange(angle::SubjectMessage::ContentsChanged); 1443 1444 return angle::Result::Continue; 1445 } 1446 1447 angle::Result Texture::copyRenderbufferSubData(Context *context, 1448 const gl::Renderbuffer *srcBuffer, 1449 GLint srcLevel, 1450 GLint srcX, 1451 GLint srcY, 1452 GLint srcZ, 1453 GLint dstLevel, 1454 GLint dstX, 1455 GLint dstY, 1456 GLint dstZ, 1457 GLsizei srcWidth, 1458 GLsizei srcHeight, 1459 GLsizei srcDepth) 1460 { 1461 ANGLE_TRY(mTexture->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY, srcZ, 1462 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, 1463 srcDepth)); 1464 1465 signalDirtyStorage(InitState::Initialized); 1466 1467 return angle::Result::Continue; 1468 } 1469 1470 angle::Result Texture::copyTextureSubData(Context *context, 1471 const gl::Texture *srcTexture, 1472 GLint srcLevel, 1473 GLint srcX, 1474 GLint srcY, 1475 GLint srcZ, 1476 GLint dstLevel, 1477 GLint dstX, 1478 GLint dstY, 1479 GLint dstZ, 1480 GLsizei srcWidth, 1481 GLsizei srcHeight, 1482 GLsizei srcDepth) 1483 { 1484 ANGLE_TRY(mTexture->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ, 1485 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, 1486 srcDepth)); 1487 1488 signalDirtyStorage(InitState::Initialized); 1489 1490 return angle::Result::Continue; 1491 } 1492 1493 angle::Result Texture::copyTexture(Context *context, 1494 TextureTarget target, 1495 GLint level, 1496 GLenum internalFormat, 1497 GLenum type, 1498 GLint sourceLevel, 1499 bool unpackFlipY, 1500 bool unpackPremultiplyAlpha, 1501 bool unpackUnmultiplyAlpha, 1502 Texture *source) 1503 { 1504 ASSERT(TextureTargetToType(target) == mState.mType); 1505 ASSERT(source->getType() != TextureType::CubeMap); 1506 1507 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1508 ANGLE_TRY(releaseTexImageInternal(context)); 1509 1510 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1511 ANGLE_TRY(orphanImages(context, &releaseImage)); 1512 1513 // Initialize source texture. 1514 // Note: we don't have a way to notify which portions of the image changed currently. 1515 ANGLE_TRY(source->ensureInitialized(context)); 1516 1517 ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel); 1518 1519 ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY, 1520 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source)); 1521 1522 const auto &sourceDesc = 1523 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel); 1524 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type); 1525 mState.setImageDesc( 1526 target, level, 1527 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized)); 1528 1529 signalDirtyStorage(InitState::Initialized); 1530 1531 return angle::Result::Continue; 1532 } 1533 1534 angle::Result Texture::copySubTexture(const Context *context, 1535 TextureTarget target, 1536 GLint level, 1537 const Offset &destOffset, 1538 GLint sourceLevel, 1539 const Box &sourceBox, 1540 bool unpackFlipY, 1541 bool unpackPremultiplyAlpha, 1542 bool unpackUnmultiplyAlpha, 1543 Texture *source) 1544 { 1545 ASSERT(TextureTargetToType(target) == mState.mType); 1546 1547 // Ensure source is initialized. 1548 ANGLE_TRY(source->ensureInitialized(context)); 1549 1550 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height, 1551 sourceBox.depth); 1552 ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth); 1553 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox)); 1554 1555 ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox, 1556 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, 1557 source)); 1558 1559 onStateChange(angle::SubjectMessage::ContentsChanged); 1560 1561 return angle::Result::Continue; 1562 } 1563 1564 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source) 1565 { 1566 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1567 ANGLE_TRY(releaseTexImageInternal(context)); 1568 1569 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1570 ANGLE_TRY(orphanImages(context, &releaseImage)); 1571 1572 ANGLE_TRY(mTexture->copyCompressedTexture(context, source)); 1573 1574 ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap); 1575 const auto &sourceDesc = 1576 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0); 1577 mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc); 1578 1579 return angle::Result::Continue; 1580 } 1581 1582 angle::Result Texture::setStorage(Context *context, 1583 TextureType type, 1584 GLsizei levels, 1585 GLenum internalFormat, 1586 const Extents &size) 1587 { 1588 ASSERT(type == mState.mType); 1589 1590 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1591 ANGLE_TRY(releaseTexImageInternal(context)); 1592 1593 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1594 ANGLE_TRY(orphanImages(context, &releaseImage)); 1595 1596 mState.mImmutableFormat = true; 1597 mState.mImmutableLevels = static_cast<GLuint>(levels); 1598 mState.clearImageDescs(); 1599 InitState initState = DetermineInitState(context, nullptr, nullptr); 1600 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat), 1601 initState); 1602 1603 ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size)); 1604 1605 // Changing the texture to immutable can trigger a change in the base and max levels: 1606 // GLES 3.0.4 section 3.8.10 pg 158: 1607 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then 1608 // clamped to the range[levelbase;levels]. 1609 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); 1610 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); 1611 1612 signalDirtyStorage(initState); 1613 1614 return angle::Result::Continue; 1615 } 1616 1617 angle::Result Texture::setImageExternal(Context *context, 1618 TextureTarget target, 1619 GLint level, 1620 GLenum internalFormat, 1621 const Extents &size, 1622 GLenum format, 1623 GLenum type) 1624 { 1625 ASSERT(TextureTargetToType(target) == mState.mType); 1626 1627 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1628 ANGLE_TRY(releaseTexImageInternal(context)); 1629 1630 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1631 ANGLE_TRY(orphanImages(context, &releaseImage)); 1632 1633 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth); 1634 1635 ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type)); 1636 1637 InitState initState = InitState::Initialized; 1638 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState)); 1639 1640 ANGLE_TRY(handleMipmapGenerationHint(context, level)); 1641 1642 signalDirtyStorage(initState); 1643 1644 return angle::Result::Continue; 1645 } 1646 1647 angle::Result Texture::setStorageMultisample(Context *context, 1648 TextureType type, 1649 GLsizei samplesIn, 1650 GLint internalFormat, 1651 const Extents &size, 1652 bool fixedSampleLocations) 1653 { 1654 ASSERT(type == mState.mType); 1655 1656 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1657 ANGLE_TRY(releaseTexImageInternal(context)); 1658 1659 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1660 ANGLE_TRY(orphanImages(context, &releaseImage)); 1661 1662 // Potentially adjust "samples" to a supported value 1663 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); 1664 GLsizei samples = formatCaps.getNearestSamples(samplesIn); 1665 1666 mState.mImmutableFormat = true; 1667 mState.mImmutableLevels = static_cast<GLuint>(1); 1668 mState.clearImageDescs(); 1669 InitState initState = DetermineInitState(context, nullptr, nullptr); 1670 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations, 1671 initState); 1672 1673 ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size, 1674 fixedSampleLocations)); 1675 signalDirtyStorage(initState); 1676 1677 return angle::Result::Continue; 1678 } 1679 1680 angle::Result Texture::setStorageExternalMemory(Context *context, 1681 TextureType type, 1682 GLsizei levels, 1683 GLenum internalFormat, 1684 const Extents &size, 1685 MemoryObject *memoryObject, 1686 GLuint64 offset, 1687 GLbitfield createFlags, 1688 GLbitfield usageFlags, 1689 const void *imageCreateInfoPNext) 1690 { 1691 ASSERT(type == mState.mType); 1692 1693 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1694 ANGLE_TRY(releaseTexImageInternal(context)); 1695 1696 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1697 ANGLE_TRY(orphanImages(context, &releaseImage)); 1698 1699 ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size, 1700 memoryObject, offset, createFlags, usageFlags, 1701 imageCreateInfoPNext)); 1702 1703 mState.mImmutableFormat = true; 1704 mState.mImmutableLevels = static_cast<GLuint>(levels); 1705 mState.clearImageDescs(); 1706 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat), 1707 InitState::Initialized); 1708 1709 // Changing the texture to immutable can trigger a change in the base and max levels: 1710 // GLES 3.0.4 section 3.8.10 pg 158: 1711 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then 1712 // clamped to the range[levelbase;levels]. 1713 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); 1714 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); 1715 1716 signalDirtyStorage(InitState::Initialized); 1717 1718 return angle::Result::Continue; 1719 } 1720 1721 angle::Result Texture::generateMipmap(Context *context) 1722 { 1723 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1724 ANGLE_TRY(releaseTexImageInternal(context)); 1725 1726 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture 1727 // is not mip complete. 1728 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1729 if (!isMipmapComplete()) 1730 { 1731 ANGLE_TRY(orphanImages(context, &releaseImage)); 1732 } 1733 1734 const GLuint baseLevel = mState.getEffectiveBaseLevel(); 1735 const GLuint maxLevel = mState.getMipmapMaxLevel(); 1736 1737 if (maxLevel <= baseLevel) 1738 { 1739 return angle::Result::Continue; 1740 } 1741 1742 // If any dimension is zero, this is a no-op: 1743 // 1744 // > Otherwise, if level_base is not defined, or if any dimension is zero, all mipmap levels are 1745 // > left unchanged. This is not an error. 1746 const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel); 1747 if (baseImageInfo.size.empty()) 1748 { 1749 return angle::Result::Continue; 1750 } 1751 1752 // Clear the base image(s) immediately if needed 1753 if (context->isRobustResourceInitEnabled()) 1754 { 1755 ImageIndexIterator it = 1756 ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1, 1757 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel); 1758 while (it.hasNext()) 1759 { 1760 const ImageIndex index = it.next(); 1761 const ImageDesc &desc = mState.getImageDesc(index.getTarget(), index.getLevelIndex()); 1762 1763 if (desc.initState == InitState::MayNeedInit) 1764 { 1765 ANGLE_TRY(initializeContents(context, GL_NONE, index)); 1766 } 1767 } 1768 } 1769 1770 ANGLE_TRY(syncState(context, Command::GenerateMipmap)); 1771 ANGLE_TRY(mTexture->generateMipmap(context)); 1772 1773 // Propagate the format and size of the base mip to the smaller ones. Cube maps are guaranteed 1774 // to have faces of the same size and format so any faces can be picked. 1775 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format, 1776 InitState::Initialized); 1777 1778 signalDirtyStorage(InitState::Initialized); 1779 1780 return angle::Result::Continue; 1781 } 1782 1783 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface) 1784 { 1785 ASSERT(surface); 1786 1787 if (mBoundSurface) 1788 { 1789 ANGLE_TRY(releaseTexImageFromSurface(context)); 1790 } 1791 1792 mBoundSurface = surface; 1793 1794 // Set the image info to the size and format of the surface 1795 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle); 1796 Extents size(surface->getWidth(), surface->getHeight(), 1); 1797 ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized); 1798 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc); 1799 mState.mHasProtectedContent = surface->hasProtectedContent(); 1800 1801 ANGLE_TRY(mTexture->bindTexImage(context, surface)); 1802 1803 signalDirtyStorage(InitState::Initialized); 1804 return angle::Result::Continue; 1805 } 1806 1807 angle::Result Texture::releaseTexImageFromSurface(const Context *context) 1808 { 1809 ASSERT(mBoundSurface); 1810 mBoundSurface = nullptr; 1811 ANGLE_TRY(mTexture->releaseTexImage(context)); 1812 1813 // Erase the image info for level 0 1814 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle); 1815 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0); 1816 mState.mHasProtectedContent = false; 1817 signalDirtyStorage(InitState::Initialized); 1818 return angle::Result::Continue; 1819 } 1820 1821 void Texture::bindStream(egl::Stream *stream) 1822 { 1823 ASSERT(stream); 1824 1825 // It should not be possible to bind a texture already bound to another stream 1826 ASSERT(mBoundStream == nullptr); 1827 1828 mBoundStream = stream; 1829 1830 ASSERT(mState.mType == TextureType::External); 1831 } 1832 1833 void Texture::releaseStream() 1834 { 1835 ASSERT(mBoundStream); 1836 mBoundStream = nullptr; 1837 } 1838 1839 angle::Result Texture::acquireImageFromStream(const Context *context, 1840 const egl::Stream::GLTextureDescription &desc) 1841 { 1842 ASSERT(mBoundStream != nullptr); 1843 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc)); 1844 1845 Extents size(desc.width, desc.height, 1); 1846 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, 1847 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized)); 1848 signalDirtyStorage(InitState::Initialized); 1849 return angle::Result::Continue; 1850 } 1851 1852 angle::Result Texture::releaseImageFromStream(const Context *context) 1853 { 1854 ASSERT(mBoundStream != nullptr); 1855 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr, 1856 egl::Stream::GLTextureDescription())); 1857 1858 // Set to incomplete 1859 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0); 1860 signalDirtyStorage(InitState::Initialized); 1861 return angle::Result::Continue; 1862 } 1863 1864 angle::Result Texture::releaseTexImageInternal(Context *context) 1865 { 1866 if (mBoundSurface) 1867 { 1868 // Notify the surface 1869 egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context); 1870 // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041 1871 if (eglErr.isError()) 1872 { 1873 context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture", 1874 __FILE__, ANGLE_FUNCTION, __LINE__); 1875 } 1876 1877 // Then, call the same method as from the surface 1878 ANGLE_TRY(releaseTexImageFromSurface(context)); 1879 } 1880 return angle::Result::Continue; 1881 } 1882 1883 angle::Result Texture::setEGLImageTargetImpl(Context *context, 1884 TextureType type, 1885 GLuint levels, 1886 egl::Image *imageTarget) 1887 { 1888 ASSERT(type == mState.mType); 1889 1890 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after 1891 ANGLE_TRY(releaseTexImageInternal(context)); 1892 1893 egl::RefCountObjectReleaser<egl::Image> releaseImage; 1894 ANGLE_TRY(orphanImages(context, &releaseImage)); 1895 1896 setTargetImage(context, imageTarget); 1897 1898 auto initState = imageTarget->sourceInitState(); 1899 1900 mState.clearImageDescs(); 1901 mState.setImageDescChain(0, levels - 1, imageTarget->getExtents(), imageTarget->getFormat(), 1902 initState); 1903 mState.mHasProtectedContent = imageTarget->hasProtectedContent(); 1904 1905 ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget)); 1906 1907 signalDirtyStorage(initState); 1908 1909 return angle::Result::Continue; 1910 } 1911 1912 angle::Result Texture::setEGLImageTarget(Context *context, 1913 TextureType type, 1914 egl::Image *imageTarget) 1915 { 1916 ASSERT(type == TextureType::_2D || type == TextureType::External || 1917 type == TextureType::_2DArray); 1918 1919 return setEGLImageTargetImpl(context, type, 1u, imageTarget); 1920 } 1921 1922 angle::Result Texture::setStorageEGLImageTarget(Context *context, 1923 TextureType type, 1924 egl::Image *imageTarget, 1925 const GLint *attrib_list) 1926 { 1927 ASSERT(type == TextureType::External || type == TextureType::_3D || type == TextureType::_2D || 1928 type == TextureType::_2DArray || type == TextureType::CubeMap || 1929 type == TextureType::CubeMapArray); 1930 1931 ANGLE_TRY(setEGLImageTargetImpl(context, type, imageTarget->getLevelCount(), imageTarget)); 1932 1933 mState.mImmutableLevels = imageTarget->getLevelCount(); 1934 mState.mImmutableFormat = true; 1935 1936 // Changing the texture to immutable can trigger a change in the base and max levels: 1937 // GLES 3.0.4 section 3.8.10 pg 158: 1938 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then 1939 // clamped to the range[levelbase;levels]. 1940 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); 1941 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); 1942 1943 return angle::Result::Continue; 1944 } 1945 1946 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const 1947 { 1948 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs, 1949 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the 1950 // one that belongs to the first face of the cube map. 1951 if (imageIndex.isEntireLevelCubeMap()) 1952 { 1953 // A cube map texture is cube complete if the following conditions all hold true: 1954 // - The levelbase arrays of each of the six texture images making up the cube map have 1955 // identical, positive, and square dimensions. 1956 if (!mState.isCubeComplete()) 1957 { 1958 return Extents(); 1959 } 1960 } 1961 1962 return mState.getImageDesc(imageIndex).size; 1963 } 1964 1965 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const 1966 { 1967 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs, 1968 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the 1969 // one that belongs to the first face of the cube map. 1970 if (imageIndex.isEntireLevelCubeMap()) 1971 { 1972 // A cube map texture is cube complete if the following conditions all hold true: 1973 // - The levelbase arrays were each specified with the same effective internal format. 1974 if (!mState.isCubeComplete()) 1975 { 1976 return Format::Invalid(); 1977 } 1978 } 1979 return mState.getImageDesc(imageIndex).format; 1980 } 1981 1982 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const 1983 { 1984 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a 1985 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp). 1986 if (imageIndex.isEntireLevelCubeMap()) 1987 { 1988 return 0; 1989 } 1990 1991 return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex()); 1992 } 1993 1994 bool Texture::isRenderable(const Context *context, 1995 GLenum binding, 1996 const ImageIndex &imageIndex) const 1997 { 1998 if (isEGLImageTarget()) 1999 { 2000 return ImageSibling::isRenderable(context, binding, imageIndex); 2001 } 2002 2003 // Surfaces bound to textures are always renderable. This avoids issues with surfaces with ES3+ 2004 // formats not being renderable when bound to textures in ES2 contexts. 2005 if (mBoundSurface) 2006 { 2007 return true; 2008 } 2009 2010 return getAttachmentFormat(binding, imageIndex) 2011 .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions()); 2012 } 2013 2014 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const 2015 { 2016 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a 2017 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp). 2018 if (imageIndex.isEntireLevelCubeMap()) 2019 { 2020 return true; 2021 } 2022 2023 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be 2024 // the same for all attached textures. 2025 return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex()); 2026 } 2027 2028 void Texture::setBorderColor(const Context *context, const ColorGeneric &color) 2029 { 2030 mState.mSamplerState.setBorderColor(color); 2031 signalDirtyState(DIRTY_BIT_BORDER_COLOR); 2032 } 2033 2034 const ColorGeneric &Texture::getBorderColor() const 2035 { 2036 return mState.mSamplerState.getBorderColor(); 2037 } 2038 2039 GLint Texture::getRequiredTextureImageUnits(const Context *context) const 2040 { 2041 // Only external texture types can return non-1. 2042 if (mState.mType != TextureType::External) 2043 { 2044 return 1; 2045 } 2046 2047 return mTexture->getRequiredExternalTextureImageUnits(context); 2048 } 2049 2050 void Texture::setCrop(const Rectangle &rect) 2051 { 2052 mState.setCrop(rect); 2053 } 2054 2055 const Rectangle &Texture::getCrop() const 2056 { 2057 return mState.getCrop(); 2058 } 2059 2060 void Texture::setGenerateMipmapHint(GLenum hint) 2061 { 2062 mState.setGenerateMipmapHint(hint); 2063 } 2064 2065 GLenum Texture::getGenerateMipmapHint() const 2066 { 2067 return mState.getGenerateMipmapHint(); 2068 } 2069 2070 angle::Result Texture::setBuffer(const gl::Context *context, 2071 gl::Buffer *buffer, 2072 GLenum internalFormat) 2073 { 2074 // Use 0 to indicate that the size is taken from whatever size the buffer has when the texture 2075 // buffer is used. 2076 return setBufferRange(context, buffer, internalFormat, 0, 0); 2077 } 2078 2079 angle::Result Texture::setBufferRange(const gl::Context *context, 2080 gl::Buffer *buffer, 2081 GLenum internalFormat, 2082 GLintptr offset, 2083 GLsizeiptr size) 2084 { 2085 mState.mImmutableFormat = true; 2086 mState.mBuffer.set(context, buffer, offset, size); 2087 ANGLE_TRY(mTexture->setBuffer(context, internalFormat)); 2088 2089 mState.clearImageDescs(); 2090 if (buffer == nullptr) 2091 { 2092 mBufferObserver.reset(); 2093 InitState initState = DetermineInitState(context, nullptr, nullptr); 2094 signalDirtyStorage(initState); 2095 return angle::Result::Continue; 2096 } 2097 2098 size = GetBoundBufferAvailableSize(mState.mBuffer); 2099 2100 mState.mImmutableLevels = static_cast<GLuint>(1); 2101 InternalFormat internalFormatInfo = GetSizedInternalFormatInfo(internalFormat); 2102 Format format(internalFormat); 2103 Extents extents(static_cast<GLuint>(size / internalFormatInfo.pixelBytes), 1, 1); 2104 InitState initState = buffer->initState(); 2105 mState.setImageDesc(TextureTarget::Buffer, 0, ImageDesc(extents, format, initState)); 2106 2107 signalDirtyStorage(initState); 2108 2109 // Observe modifications to the buffer, so that extents can be updated. 2110 mBufferObserver.bind(buffer); 2111 2112 return angle::Result::Continue; 2113 } 2114 2115 const OffsetBindingPointer<Buffer> &Texture::getBuffer() const 2116 { 2117 return mState.mBuffer; 2118 } 2119 2120 void Texture::onAttach(const Context *context, rx::Serial framebufferSerial) 2121 { 2122 addRef(); 2123 2124 // Duplicates allowed for multiple attachment points. See the comment in the header. 2125 mBoundFramebufferSerials.push_back(framebufferSerial); 2126 2127 if (!mState.mHasBeenBoundAsAttachment) 2128 { 2129 mDirtyBits.set(DIRTY_BIT_BOUND_AS_ATTACHMENT); 2130 mState.mHasBeenBoundAsAttachment = true; 2131 } 2132 } 2133 2134 void Texture::onDetach(const Context *context, rx::Serial framebufferSerial) 2135 { 2136 // Erase first instance. If there are multiple bindings, leave the others. 2137 ASSERT(isBoundToFramebuffer(framebufferSerial)); 2138 mBoundFramebufferSerials.remove_and_permute(framebufferSerial); 2139 2140 release(context); 2141 } 2142 2143 GLuint Texture::getId() const 2144 { 2145 return id().value; 2146 } 2147 2148 GLuint Texture::getNativeID() const 2149 { 2150 return mTexture->getNativeID(); 2151 } 2152 2153 angle::Result Texture::syncState(const Context *context, Command source) 2154 { 2155 ASSERT(hasAnyDirtyBit() || source == Command::GenerateMipmap); 2156 ANGLE_TRY(mTexture->syncState(context, mDirtyBits, source)); 2157 mDirtyBits.reset(); 2158 mState.mInitState = InitState::Initialized; 2159 return angle::Result::Continue; 2160 } 2161 2162 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const 2163 { 2164 return mTexture; 2165 } 2166 2167 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler) 2168 { 2169 const auto &samplerState = 2170 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState; 2171 const auto &contextState = context->getState(); 2172 2173 if (contextState.getContextID() != mCompletenessCache.context || 2174 !mCompletenessCache.samplerState.sameCompleteness(samplerState)) 2175 { 2176 mCompletenessCache.context = context->getState().getContextID(); 2177 mCompletenessCache.samplerState = samplerState; 2178 mCompletenessCache.samplerComplete = 2179 mState.computeSamplerCompleteness(samplerState, contextState); 2180 } 2181 2182 return mCompletenessCache.samplerComplete; 2183 } 2184 2185 // CopyImageSubData requires that we ignore format-based completeness rules 2186 bool Texture::isSamplerCompleteForCopyImage(const Context *context, 2187 const Sampler *optionalSampler) const 2188 { 2189 const gl::SamplerState &samplerState = 2190 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState; 2191 const gl::State &contextState = context->getState(); 2192 return mState.computeSamplerCompletenessForCopyImage(samplerState, contextState); 2193 } 2194 2195 Texture::SamplerCompletenessCache::SamplerCompletenessCache() 2196 : context({0}), samplerState(), samplerComplete(false) 2197 {} 2198 2199 void Texture::invalidateCompletenessCache() const 2200 { 2201 mCompletenessCache.context = {0}; 2202 } 2203 2204 angle::Result Texture::ensureInitialized(const Context *context) 2205 { 2206 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) 2207 { 2208 return angle::Result::Continue; 2209 } 2210 2211 bool anyDirty = false; 2212 2213 ImageIndexIterator it = 2214 ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1, 2215 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel); 2216 while (it.hasNext()) 2217 { 2218 const ImageIndex index = it.next(); 2219 ImageDesc &desc = 2220 mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())]; 2221 if (desc.initState == InitState::MayNeedInit && !desc.size.empty()) 2222 { 2223 ASSERT(mState.mInitState == InitState::MayNeedInit); 2224 ANGLE_TRY(initializeContents(context, GL_NONE, index)); 2225 desc.initState = InitState::Initialized; 2226 anyDirty = true; 2227 } 2228 } 2229 if (anyDirty) 2230 { 2231 signalDirtyStorage(InitState::Initialized); 2232 } 2233 mState.mInitState = InitState::Initialized; 2234 2235 return angle::Result::Continue; 2236 } 2237 2238 InitState Texture::initState(GLenum /*binding*/, const ImageIndex &imageIndex) const 2239 { 2240 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs, 2241 // we need to check all the related ImageDescs. 2242 if (imageIndex.isEntireLevelCubeMap()) 2243 { 2244 const GLint levelIndex = imageIndex.getLevelIndex(); 2245 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets()) 2246 { 2247 if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit) 2248 { 2249 return InitState::MayNeedInit; 2250 } 2251 } 2252 return InitState::Initialized; 2253 } 2254 2255 return mState.getImageDesc(imageIndex).initState; 2256 } 2257 2258 void Texture::setInitState(GLenum binding, const ImageIndex &imageIndex, InitState initState) 2259 { 2260 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs, 2261 // we need to update all the related ImageDescs. 2262 if (imageIndex.isEntireLevelCubeMap()) 2263 { 2264 const GLint levelIndex = imageIndex.getLevelIndex(); 2265 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets()) 2266 { 2267 setInitState(binding, ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), 2268 initState); 2269 } 2270 } 2271 else 2272 { 2273 ImageDesc newDesc = mState.getImageDesc(imageIndex); 2274 newDesc.initState = initState; 2275 mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc); 2276 } 2277 } 2278 2279 void Texture::setInitState(InitState initState) 2280 { 2281 for (ImageDesc &imageDesc : mState.mImageDescs) 2282 { 2283 // Only modify defined images, undefined images will remain in the initialized state 2284 if (!imageDesc.size.empty()) 2285 { 2286 imageDesc.initState = initState; 2287 } 2288 } 2289 mState.mInitState = initState; 2290 } 2291 2292 bool Texture::doesSubImageNeedInit(const Context *context, 2293 const ImageIndex &imageIndex, 2294 const Box &area) const 2295 { 2296 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) 2297 { 2298 return false; 2299 } 2300 2301 // Pre-initialize the texture contents if necessary. 2302 const ImageDesc &desc = mState.getImageDesc(imageIndex); 2303 if (desc.initState != InitState::MayNeedInit) 2304 { 2305 return false; 2306 } 2307 2308 ASSERT(mState.mInitState == InitState::MayNeedInit); 2309 return !area.coversSameExtent(desc.size); 2310 } 2311 2312 angle::Result Texture::ensureSubImageInitialized(const Context *context, 2313 const ImageIndex &imageIndex, 2314 const Box &area) 2315 { 2316 if (doesSubImageNeedInit(context, imageIndex, area)) 2317 { 2318 // NOTE: do not optimize this to only initialize the passed area of the texture, or the 2319 // initialization logic in copySubImage will be incorrect. 2320 ANGLE_TRY(initializeContents(context, GL_NONE, imageIndex)); 2321 } 2322 // Note: binding is ignored for textures. 2323 setInitState(GL_NONE, imageIndex, InitState::Initialized); 2324 return angle::Result::Continue; 2325 } 2326 2327 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level) 2328 { 2329 if (getGenerateMipmapHint() == GL_TRUE && level == 0) 2330 { 2331 ANGLE_TRY(generateMipmap(context)); 2332 } 2333 2334 return angle::Result::Continue; 2335 } 2336 2337 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) 2338 { 2339 switch (message) 2340 { 2341 case angle::SubjectMessage::ContentsChanged: 2342 if (index != kBufferSubjectIndex) 2343 { 2344 // ContentsChange originates from TextureStorage11::resolveAndReleaseTexture 2345 // which resolves the underlying multisampled texture if it exists and so 2346 // Texture will signal dirty storage to invalidate its own cache and the 2347 // attached framebuffer's cache. 2348 signalDirtyStorage(InitState::Initialized); 2349 } 2350 break; 2351 case angle::SubjectMessage::DirtyBitsFlagged: 2352 signalDirtyState(DIRTY_BIT_IMPLEMENTATION); 2353 2354 // Notify siblings that we are dirty. 2355 if (index == rx::kTextureImageImplObserverMessageIndex) 2356 { 2357 notifySiblings(message); 2358 } 2359 break; 2360 case angle::SubjectMessage::SubjectChanged: 2361 mState.mInitState = InitState::MayNeedInit; 2362 signalDirtyState(DIRTY_BIT_IMPLEMENTATION); 2363 onStateChange(angle::SubjectMessage::ContentsChanged); 2364 2365 // Notify siblings that we are dirty. 2366 if (index == rx::kTextureImageImplObserverMessageIndex) 2367 { 2368 notifySiblings(message); 2369 } 2370 else if (index == kBufferSubjectIndex) 2371 { 2372 const gl::Buffer *buffer = mState.mBuffer.get(); 2373 ASSERT(buffer != nullptr); 2374 2375 // Update cached image desc based on buffer size. 2376 GLsizeiptr size = GetBoundBufferAvailableSize(mState.mBuffer); 2377 2378 ImageDesc desc = mState.getImageDesc(TextureTarget::Buffer, 0); 2379 const GLuint pixelBytes = desc.format.info->pixelBytes; 2380 desc.size.width = static_cast<GLuint>(size / pixelBytes); 2381 2382 mState.setImageDesc(TextureTarget::Buffer, 0, desc); 2383 } 2384 break; 2385 case angle::SubjectMessage::StorageReleased: 2386 // When the TextureStorage is released, it needs to update the 2387 // RenderTargetCache of the Framebuffer attaching this Texture. 2388 // This is currently only for D3D back-end. See http://crbug.com/1234829 2389 if (index == rx::kTextureImageImplObserverMessageIndex) 2390 { 2391 onStateChange(angle::SubjectMessage::StorageReleased); 2392 } 2393 break; 2394 case angle::SubjectMessage::SubjectMapped: 2395 case angle::SubjectMessage::SubjectUnmapped: 2396 case angle::SubjectMessage::BindingChanged: 2397 ASSERT(index == kBufferSubjectIndex); 2398 break; 2399 case angle::SubjectMessage::InitializationComplete: 2400 ASSERT(index == rx::kTextureImageImplObserverMessageIndex); 2401 setInitState(InitState::Initialized); 2402 break; 2403 case angle::SubjectMessage::InternalMemoryAllocationChanged: 2404 // Need to mark the texture dirty to give the back end a chance to handle the new 2405 // buffer. For example, the Vulkan back end needs to create a new buffer view that 2406 // points to the newly allocated buffer and update the texture descriptor set. 2407 signalDirtyState(DIRTY_BIT_IMPLEMENTATION); 2408 break; 2409 default: 2410 UNREACHABLE(); 2411 break; 2412 } 2413 } 2414 2415 GLenum Texture::getImplementationColorReadFormat(const Context *context) const 2416 { 2417 return mTexture->getColorReadFormat(context); 2418 } 2419 2420 GLenum Texture::getImplementationColorReadType(const Context *context) const 2421 { 2422 return mTexture->getColorReadType(context); 2423 } 2424 2425 bool Texture::isCompressedFormatEmulated(const Context *context, 2426 TextureTarget target, 2427 GLint level) const 2428 { 2429 if (!getFormat(target, level).info->compressed) 2430 { 2431 // If it isn't compressed, the remaining logic won't work 2432 return false; 2433 } 2434 2435 GLenum implFormat = getImplementationColorReadFormat(context); 2436 2437 // Check against the list of formats used to emulate compressed textures 2438 return IsEmulatedCompressedFormat(implFormat); 2439 } 2440 2441 angle::Result Texture::getTexImage(const Context *context, 2442 const PixelPackState &packState, 2443 Buffer *packBuffer, 2444 TextureTarget target, 2445 GLint level, 2446 GLenum format, 2447 GLenum type, 2448 void *pixels) 2449 { 2450 // No-op if the image level is empty. 2451 if (getExtents(target, level).empty()) 2452 { 2453 return angle::Result::Continue; 2454 } 2455 2456 return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type, 2457 pixels); 2458 } 2459 2460 angle::Result Texture::getCompressedTexImage(const Context *context, 2461 const PixelPackState &packState, 2462 Buffer *packBuffer, 2463 TextureTarget target, 2464 GLint level, 2465 void *pixels) 2466 { 2467 // No-op if the image level is empty. 2468 if (getExtents(target, level).empty()) 2469 { 2470 return angle::Result::Continue; 2471 } 2472 2473 return mTexture->getCompressedTexImage(context, packState, packBuffer, target, level, pixels); 2474 } 2475 2476 void Texture::onBindAsImageTexture() 2477 { 2478 if (!mState.mHasBeenBoundAsImage) 2479 { 2480 mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE); 2481 mState.mHasBeenBoundAsImage = true; 2482 } 2483 } 2484 2485 void Texture::onBind3DTextureAs2DImage() 2486 { 2487 if (!mState.mIs3DAndHasBeenBoundAs2DImage) 2488 { 2489 mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE); 2490 mState.mIs3DAndHasBeenBoundAs2DImage = true; 2491 } 2492 } 2493 2494 } // namespace gl