bool WebGLTexture::IsMipmapComplete(uint32_t texUnit) const { MOZ_ASSERT(DoesMinFilterRequireMipmap()); // GLES 3.0.4, p161 const uint32_t maxLevel = MaxEffectiveMipmapLevel(texUnit); // "* `level_base <= level_max`" if (mBaseMipmapLevel > maxLevel) return false; // Make a copy so we can modify it. const ImageInfo& baseImageInfo = BaseImageInfo(); if (!baseImageInfo.IsDefined()) return false; // Reference dimensions based on the current level. uint32_t refWidth = baseImageInfo.mWidth; uint32_t refHeight = baseImageInfo.mHeight; uint32_t refDepth = baseImageInfo.mDepth; MOZ_ASSERT(refWidth && refHeight && refDepth); for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) { // "A cube map texture is mipmap complete if each of the six texture images, // considered individually, is mipmap complete." for (uint8_t face = 0; face < mFaceCount; face++) { const ImageInfo& cur = ImageInfoAtFace(face, level); // "* The set of mipmap arrays `level_base` through `q` (where `q` is defined // the "Mipmapping" discussion of section 3.8.10) were each specified with // the same effective internal format." // "* The dimensions of the arrays follow the sequence described in the // "Mipmapping" discussion of section 3.8.10." if (cur.mWidth != refWidth || cur.mHeight != refHeight || cur.mDepth != refDepth || cur.mFormat != baseImageInfo.mFormat) { return false; } } // GLES 3.0.4, p158: // "[...] until the last array is reached with dimension 1 x 1 x 1." if (refWidth == 1 && refHeight == 1 && refDepth == 1) { break; } refWidth = std::max(uint32_t(1), refWidth / 2); refHeight = std::max(uint32_t(1), refHeight / 2); refDepth = std::max(uint32_t(1), refDepth / 2); } return true; }
bool WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit, FakeBlackType* const out_fakeBlack) { const char* incompleteReason; if (!IsComplete(texUnit, &incompleteReason)) { if (incompleteReason) { mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is" " 'incomplete', and will be rendered as" " RGBA(0,0,0,1), as per the GLES 2.0.24 $3.8.2: %s", funcName, texUnit, mTarget.get(), incompleteReason); } *out_fakeBlack = FakeBlackType::RGBA0001; return true; } // We may still want FakeBlack as an optimization for uninitialized image data. bool hasUninitializedData = false; bool hasInitializedData = false; const auto maxLevel = MaxEffectiveMipmapLevel(texUnit); MOZ_ASSERT(mBaseMipmapLevel <= maxLevel); for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) { for (uint8_t face = 0; face < mFaceCount; face++) { const auto& cur = ImageInfoAtFace(face, level); if (cur.IsDataInitialized()) hasInitializedData = true; else hasUninitializedData = true; } } MOZ_ASSERT(hasUninitializedData || hasInitializedData); if (!hasUninitializedData) { *out_fakeBlack = FakeBlackType::None; return true; } if (!hasInitializedData) { const auto format = ImageInfoAtFace(0, mBaseMipmapLevel).mFormat->format; if (format->isColorFormat) { *out_fakeBlack = (format->hasAlpha ? FakeBlackType::RGBA0000 : FakeBlackType::RGBA0001); return true; } mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is" " uninitialized, and will be (perhaps slowly) cleared" " by the implementation.", funcName, texUnit, mTarget.get()); } else { mContext->GenerateWarning("%s: Active texture %u for target 0x%04x contains" " TexImages with uninitialized data along with" " TexImages with initialized data, forcing the" " implementation to (slowly) initialize the" " uninitialized TexImages.", funcName, texUnit, mTarget.get()); } GLenum baseImageTarget = mTarget.get(); if (baseImageTarget == LOCAL_GL_TEXTURE_CUBE_MAP) baseImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) { for (uint8_t face = 0; face < mFaceCount; face++) { TexImageTarget imageTarget = baseImageTarget + face; if (!EnsureImageDataInitialized(funcName, imageTarget, level)) return false; // The world just exploded. } } *out_fakeBlack = FakeBlackType::None; return true; }
bool WebGLTexture::IsMipmapComplete(const char* funcName, uint32_t texUnit, bool* const out_initFailed) { *out_initFailed = false; MOZ_ASSERT(DoesMinFilterRequireMipmap()); // GLES 3.0.4, p161 uint32_t maxLevel; if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel)) return false; // "* `level_base <= level_max`" if (mBaseMipmapLevel > maxLevel) return false; // Make a copy so we can modify it. const ImageInfo& baseImageInfo = BaseImageInfo(); // Reference dimensions based on the current level. uint32_t refWidth = baseImageInfo.mWidth; uint32_t refHeight = baseImageInfo.mHeight; uint32_t refDepth = baseImageInfo.mDepth; MOZ_ASSERT(refWidth && refHeight && refDepth); for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) { if (!EnsureLevelInitialized(funcName, level)) { *out_initFailed = true; return false; } // "A cube map texture is mipmap complete if each of the six texture images, // considered individually, is mipmap complete." for (uint8_t face = 0; face < mFaceCount; face++) { const ImageInfo& cur = ImageInfoAtFace(face, level); // "* The set of mipmap arrays `level_base` through `q` (where `q` is defined // the "Mipmapping" discussion of section 3.8.10) were each specified with // the same effective internal format." // "* The dimensions of the arrays follow the sequence described in the // "Mipmapping" discussion of section 3.8.10." if (cur.mWidth != refWidth || cur.mHeight != refHeight || cur.mDepth != refDepth || cur.mFormat != baseImageInfo.mFormat) { return false; } } // GLES 3.0.4, p158: // "[...] until the last array is reached with dimension 1 x 1 x 1." if (mTarget == LOCAL_GL_TEXTURE_3D) { if (refWidth == 1 && refHeight == 1 && refDepth == 1) { break; } refDepth = std::max(uint32_t(1), refDepth / 2); } else { // TEXTURE_2D_ARRAY may have depth != 1, but that's normal. if (refWidth == 1 && refHeight == 1) { break; } } refWidth = std::max(uint32_t(1), refWidth / 2); refHeight = std::max(uint32_t(1), refHeight / 2); } return true; }