Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}