Bug 1230089 - If sampler is bound, use parameter of sampler. r=jgilbert
authorMorris Tseng <mtseng@mozilla.com>
Thu, 21 Jan 2016 14:49:41 +0800
changeset 306213 56626252ef750211cfa5f92a93d64555dd01958e
parent 306212 235d8796a27947c371643340162d9dc081cb2cce
child 306214 2cd90b7d3dbd3cbc4759a493da12cfbbb1364c92
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs1230089
milestone46.0a1
Bug 1230089 - If sampler is bound, use parameter of sampler. r=jgilbert
dom/canvas/WebGL2ContextSamplers.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextTextures.cpp
dom/canvas/WebGLSampler.cpp
dom/canvas/WebGLSampler.h
dom/canvas/WebGLStrongTypes.h
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTexture.h
--- a/dom/canvas/WebGL2ContextSamplers.cpp
+++ b/dom/canvas/WebGL2ContextSamplers.cpp
@@ -42,16 +42,18 @@ WebGL2Context::DeleteSampler(WebGLSample
         return;
 
     if (!sampler || sampler->IsDeleted())
         return;
 
     for (int n = 0; n < mGLMaxTextureUnits; n++) {
         if (mBoundSamplers[n] == sampler) {
             mBoundSamplers[n] = nullptr;
+
+            InvalidateResolveCacheForTextureWithTexUnit(n);
         }
     }
 
     sampler->RequestDelete();
 }
 
 bool
 WebGL2Context::IsSampler(WebGLSampler* sampler)
@@ -83,32 +85,34 @@ WebGL2Context::BindSampler(GLuint unit, 
 
     if (GLint(unit) >= mGLMaxTextureUnits)
         return ErrorInvalidValue("bindSampler: unit must be < %d", mGLMaxTextureUnits);
 
     if (sampler && sampler->IsDeleted())
         return ErrorInvalidOperation("bindSampler: binding deleted sampler");
 
     WebGLContextUnchecked::BindSampler(unit, sampler);
+    InvalidateResolveCacheForTextureWithTexUnit(unit);
 
     mBoundSamplers[unit] = sampler;
 }
 
 void
 WebGL2Context::SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param)
 {
     if (IsContextLost())
         return;
 
     if (!sampler || sampler->IsDeleted())
         return ErrorInvalidOperation("samplerParameteri: invalid sampler");
 
     if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameteri"))
         return;
 
+    sampler->SamplerParameter1i(pname, param);
     WebGLContextUnchecked::SamplerParameteri(sampler, pname, param);
 }
 
 void
 WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Int32Array& param)
 {
     if (IsContextLost())
         return;
@@ -119,16 +123,17 @@ WebGL2Context::SamplerParameteriv(WebGLS
     param.ComputeLengthAndData();
     if (param.Length() < 1)
         return /* TODO(djg): Error message */;
 
     /* TODO(djg): All of these calls in ES3 only take 1 param */
     if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameteriv"))
         return;
 
+    sampler->SamplerParameter1i(pname, param.Data()[0]);
     WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Data());
 }
 
 void
 WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLint>& param)
 {
     if (IsContextLost())
         return;
@@ -138,31 +143,33 @@ WebGL2Context::SamplerParameteriv(WebGLS
 
     if (param.Length() < 1)
         return /* TODO(djg): Error message */;
 
     /* TODO(djg): All of these calls in ES3 only take 1 param */
     if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameteriv"))
         return;
 
+    sampler->SamplerParameter1i(pname, param[0]);
     WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Elements());
 }
 
 void
 WebGL2Context::SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param)
 {
     if (IsContextLost())
         return;
 
     if (!sampler || sampler->IsDeleted())
         return ErrorInvalidOperation("samplerParameterf: invalid sampler");
 
     if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameterf"))
         return;
 
+    sampler->SamplerParameter1f(pname, param);
     WebGLContextUnchecked::SamplerParameterf(sampler, pname, param);
 }
 
 void
 WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Float32Array& param)
 {
     if (IsContextLost())
         return;
@@ -173,16 +180,17 @@ WebGL2Context::SamplerParameterfv(WebGLS
     param.ComputeLengthAndData();
     if (param.Length() < 1)
         return /* TODO(djg): Error message */;
 
     /* TODO(djg): All of these calls in ES3 only take 1 param */
     if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameterfv"))
         return;
 
+    sampler->SamplerParameter1f(pname, param.Data()[0]);
     WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Data());
 }
 
 void
 WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLfloat>& param)
 {
     if (IsContextLost())
         return;
@@ -192,16 +200,17 @@ WebGL2Context::SamplerParameterfv(WebGLS
 
     if (param.Length() < 1)
         return /* TODO(djg): Error message */;
 
     /* TODO(djg): All of these calls in ES3 only take 1 param */
     if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameterfv"))
         return;
 
+    sampler->SamplerParameter1f(pname, param[0]);
     WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Elements());
 }
 
 void
 WebGL2Context::GetSamplerParameter(JSContext*, WebGLSampler* sampler, GLenum pname, JS::MutableHandleValue retval)
 {
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -327,16 +327,18 @@ public:
      */
     WebGLTexture*
     ActiveBoundTextureForTexImageTarget(const TexImageTarget texImgTarget) const
     {
         const TexTarget texTarget = TexImageTargetToTexTarget(texImgTarget);
         return ActiveBoundTextureForTarget(texTarget);
     }
 
+    void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
+
     already_AddRefed<Layer>
     GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
                    LayerManager* manager) override;
 
     // Note that 'clean' here refers to its invalidation state, not the
     // contents of the buffer.
     void MarkContextClean() override { mInvalidated = false; }
 
--- a/dom/canvas/WebGLContextTextures.cpp
+++ b/dom/canvas/WebGLContextTextures.cpp
@@ -182,16 +182,29 @@ WebGLContext::IsTexParamValid(GLenum pna
     case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
         return IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic);
 
     default:
         return false;
     }
 }
 
+void
+WebGLContext::InvalidateResolveCacheForTextureWithTexUnit(const GLuint texUnit)
+{
+    if (mBound2DTextures[texUnit])
+        mBound2DTextures[texUnit]->InvalidateResolveCache();
+    if (mBoundCubeMapTextures[texUnit])
+        mBoundCubeMapTextures[texUnit]->InvalidateResolveCache();
+    if (mBound3DTextures[texUnit])
+        mBound3DTextures[texUnit]->InvalidateResolveCache();
+    if (mBound2DArrayTextures[texUnit])
+        mBound2DArrayTextures[texUnit]->InvalidateResolveCache();
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 // GL calls
 
 void
 WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
 {
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGLSampler.cpp
+++ b/dom/canvas/WebGLSampler.cpp
@@ -9,16 +9,25 @@
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 WebGLSampler::WebGLSampler(WebGLContext* webgl, GLuint sampler)
     : WebGLContextBoundObject(webgl)
     , mGLName(sampler)
+    , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
+    , mMagFilter(LOCAL_GL_LINEAR)
+    , mWrapS(LOCAL_GL_REPEAT)
+    , mWrapT(LOCAL_GL_REPEAT)
+    , mWrapR(LOCAL_GL_REPEAT)
+    , mMinLod(-1000)
+    , mMaxLod(1000)
+    , mCompareMode(LOCAL_GL_NONE)
+    , mCompareFunc(LOCAL_GL_LEQUAL)
 {
     mContext->mSamplers.insertBack(this);
 }
 
 WebGLSampler::~WebGLSampler()
 {
     DeleteOnce();
 }
@@ -39,14 +48,80 @@ WebGLSampler::GetParentObject() const
 }
 
 JSObject*
 WebGLSampler::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGLSamplerBinding::Wrap(cx, this, givenProto);
 }
 
+void
+WebGLSampler::SamplerParameter1i(GLenum pname, GLint param)
+{
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+        mMinFilter = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+        mMagFilter = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_WRAP_S:
+        mWrapS = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_WRAP_T:
+        mWrapT = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_WRAP_R:
+        mWrapR = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+        mCompareMode = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        mCompareFunc = param;
+        break;
+
+    default:
+        MOZ_CRASH("Unhandled pname");
+        break;
+    }
+
+    for (uint32_t i = 0; i < mContext->mBoundSamplers.Length(); ++i) {
+        if (this == mContext->mBoundSamplers[i])
+            mContext->InvalidateResolveCacheForTextureWithTexUnit(i);
+    }
+}
+
+void
+WebGLSampler::SamplerParameter1f(GLenum pname, GLfloat param)
+{
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+        mMinLod = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+        mMaxLod = param;
+        break;
+
+    default:
+        MOZ_CRASH("Unhandled pname");
+        break;
+    }
+
+    for (uint32_t i = 0; i < mContext->mBoundSamplers.Length(); ++i) {
+        if (this == mContext->mBoundSamplers[i])
+            mContext->InvalidateResolveCacheForTextureWithTexUnit(i);
+    }
+}
+
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLSampler)
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLSampler, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLSampler, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLSampler.h
+++ b/dom/canvas/WebGLSampler.h
@@ -14,31 +14,45 @@ namespace mozilla {
 
 class WebGLSampler final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLSampler>
     , public LinkedListElement<WebGLSampler>
     , public WebGLContextBoundObject
 {
     friend class WebGLContext2;
+    friend class WebGLTexture;
 
 public:
     explicit WebGLSampler(WebGLContext* webgl, GLuint sampler);
 
     const GLuint mGLName;
 
     void Delete();
     WebGLContext* GetParentObject() const;
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
+    void SamplerParameter1i(GLenum pname, GLint param);
+    void SamplerParameter1f(GLenum pname, GLfloat param);
+
 private:
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLSampler)
 
+    TexMinFilter mMinFilter;
+    TexMagFilter mMagFilter;
+    TexWrap mWrapS;
+    TexWrap mWrapT;
+    TexWrap mWrapR;
+    GLint mMinLod;
+    GLint mMaxLod;
+    TexCompareMode mCompareMode;
+    TexCompareFunc mCompareFunc;
+
 private:
     ~WebGLSampler();
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_SAMPLER_H_
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -264,16 +264,32 @@ STRONG_GLENUM_BEGIN(TexMagFilter)
 STRONG_GLENUM_END(TexMagFilter)
 
 STRONG_GLENUM_BEGIN(TexWrap)
     STRONG_GLENUM_VALUE(REPEAT),
     STRONG_GLENUM_VALUE(CLAMP_TO_EDGE),
     STRONG_GLENUM_VALUE(MIRRORED_REPEAT),
 STRONG_GLENUM_END(TexWrap)
 
+STRONG_GLENUM_BEGIN(TexCompareMode)
+    STRONG_GLENUM_VALUE(NONE),
+    STRONG_GLENUM_VALUE(COMPARE_REF_TO_TEXTURE),
+STRONG_GLENUM_END(TexCompareMode)
+
+STRONG_GLENUM_BEGIN(TexCompareFunc)
+    STRONG_GLENUM_VALUE(LEQUAL),
+    STRONG_GLENUM_VALUE(GEQUAL),
+    STRONG_GLENUM_VALUE(LESS),
+    STRONG_GLENUM_VALUE(GREATER),
+    STRONG_GLENUM_VALUE(EQUAL),
+    STRONG_GLENUM_VALUE(NOTEQUAL),
+    STRONG_GLENUM_VALUE(ALWAYS),
+    STRONG_GLENUM_VALUE(NEVER),
+STRONG_GLENUM_END(TexCompareFunc)
+
 STRONG_GLENUM_BEGIN(TexFormat)
     STRONG_GLENUM_VALUE(NONE),            // 0x0000
     STRONG_GLENUM_VALUE(DEPTH_COMPONENT), // 0x1902
     STRONG_GLENUM_VALUE(RED),             // 0x1903
     STRONG_GLENUM_VALUE(ALPHA),           // 0x1906
     STRONG_GLENUM_VALUE(RGB),             // 0x1907
     STRONG_GLENUM_VALUE(RGBA),            // 0x1908
     STRONG_GLENUM_VALUE(LUMINANCE),       // 0x1909
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -185,22 +185,22 @@ WebGLTexture::SetImageInfosAtLevel(uint3
     for (uint8_t i = 0; i < mFaceCount; i++) {
         ImageInfoAtFace(i, level) = newInfo;
     }
 
     InvalidateResolveCache();
 }
 
 bool
-WebGLTexture::IsMipmapComplete() const
+WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
 {
     MOZ_ASSERT(DoesMinFilterRequireMipmap());
     // GLES 3.0.4, p161
 
-    const uint32_t maxLevel = MaxEffectiveMipmapLevel();
+    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())
@@ -285,17 +285,17 @@ WebGLTexture::IsCubeComplete() const
             return false;
         }
     }
 
     return true;
 }
 
 bool
-WebGLTexture::IsComplete(const char** const out_reason) const
+WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
 {
     // Texture completeness is established at GLES 3.0.4, p160-161.
     // "[A] texture is complete unless any of the following conditions hold true:"
 
     // "* Any dimension of the `level_base` array is not positive."
     const ImageInfo& baseImageInfo = BaseImageInfo();
     if (!baseImageInfo.IsDefined()) {
         // In case of undefined texture image, we don't print any message because this is
@@ -310,29 +310,33 @@ WebGLTexture::IsComplete(const char** co
     }
 
     // "* The texture is a cube map texture, and is not cube complete."
     if (IsCubeMap() && !IsCubeComplete()) {
         *out_reason = "Cubemaps must be \"cube complete\".";
         return false;
     }
 
+    WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
+    TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
+    TexMagFilter magFilter = sampler ? sampler->mMagFilter : mMagFilter;
+
     // "* The minification filter requires a mipmap (is neither NEAREST nor LINEAR) and
     //    the texture is not mipmap complete."
-    const bool requiresMipmap = (mMinFilter != LOCAL_GL_NEAREST &&
-                                 mMinFilter != LOCAL_GL_LINEAR);
-    if (requiresMipmap && !IsMipmapComplete()) {
+    const bool requiresMipmap = (minFilter != LOCAL_GL_NEAREST &&
+                                 minFilter != LOCAL_GL_LINEAR);
+    if (requiresMipmap && !IsMipmapComplete(texUnit)) {
         *out_reason = "Because the minification filter requires mipmapping, the texture"
                       " must be \"mipmap complete\".";
         return false;
     }
 
-    const bool isMinFilteringNearest = (mMinFilter == LOCAL_GL_NEAREST ||
-                                        mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
-    const bool isMagFilteringNearest = (mMagFilter == LOCAL_GL_NEAREST);
+    const bool isMinFilteringNearest = (minFilter == LOCAL_GL_NEAREST ||
+                                        minFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
+    const bool isMagFilteringNearest = (magFilter == LOCAL_GL_NEAREST);
     const bool isFilteringNearestOnly = (isMinFilteringNearest && isMagFilteringNearest);
     if (!isFilteringNearestOnly) {
         auto formatUsage = baseImageInfo.mFormat;
         auto format = formatUsage->format;
 
         // "* The effective internal format specified for the texture arrays is a sized
         //    internal color format that is not texture-filterable, and either the
         //    magnification filter is not NEAREST or the minification filter is neither
@@ -389,19 +393,21 @@ WebGLTexture::IsComplete(const char** co
         // "* A two-dimensional sampler is called, the corresponding texture image is a
         //    non-power-of-two image[...], and either the texture wrap mode is not
         //    CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
 
         // "* A cube map sampler is called, any of the corresponding texture images are
         //    non-power-of-two images, and either the texture wrap mode is not
         //    CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
         if (!baseImageInfo.IsPowerOfTwo()) {
+            TexWrap wrapS = sampler ? sampler->mWrapS : mWrapS;
+            TexWrap wrapT = sampler ? sampler->mWrapT : mWrapT;
             // "either the texture wrap mode is not CLAMP_TO_EDGE"
-            if (mWrapS != LOCAL_GL_CLAMP_TO_EDGE ||
-                mWrapT != LOCAL_GL_CLAMP_TO_EDGE)
+            if (wrapS != LOCAL_GL_CLAMP_TO_EDGE ||
+                wrapT != LOCAL_GL_CLAMP_TO_EDGE)
             {
                 *out_reason = "Non-power-of-two textures must have a wrap mode of"
                               " CLAMP_TO_EDGE.";
                 return false;
             }
 
             // "or the minification filter is neither NEAREST nor LINEAR"
             if (requiresMipmap) {
@@ -416,20 +422,22 @@ WebGLTexture::IsComplete(const char** co
         // (already covered)
     }
 
     return true;
 }
 
 
 uint32_t
-WebGLTexture::MaxEffectiveMipmapLevel() const
+WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit) const
 {
-    if (mMinFilter == LOCAL_GL_NEAREST ||
-        mMinFilter == LOCAL_GL_LINEAR)
+    WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
+    TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
+    if (minFilter == LOCAL_GL_NEAREST ||
+        minFilter == LOCAL_GL_LINEAR)
     {
         // No mips used.
         return mBaseMipmapLevel;
     }
 
     const auto& imageInfo = BaseImageInfo();
     MOZ_ASSERT(imageInfo.IsDefined());
 
@@ -437,33 +445,33 @@ WebGLTexture::MaxEffectiveMipmapLevel() 
     return std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
 }
 
 bool
 WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
                                FakeBlackType* const out_fakeBlack)
 {
     const char* incompleteReason;
-    if (!IsComplete(&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();
+    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;
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -279,17 +279,17 @@ public:
 
     ////////////////////////////////////
 
 protected:
     void ClampLevelBaseAndMax();
 
     void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
 
-    uint32_t MaxEffectiveMipmapLevel() const;
+    uint32_t MaxEffectiveMipmapLevel(uint32_t texUnit) const;
 
     static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
         GLenum rawTexImageTarget = texImageTarget.get();
         switch (rawTexImageTarget) {
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
@@ -364,21 +364,21 @@ public:
     }
 
     void SetGeneratedMipmap();
 
     void SetCustomMipmap();
 
     bool AreAllLevel0ImageInfosEqual() const;
 
-    bool IsMipmapComplete() const;
+    bool IsMipmapComplete(uint32_t texUnit) const;
 
     bool IsCubeComplete() const;
 
-    bool IsComplete(const char** const out_reason) const;
+    bool IsComplete(uint32_t texUnit, const char** const out_reason) const;
 
     bool IsMipmapCubeComplete() const;
 
     bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
 
     // Resolve cache optimizations
 protected:
     bool GetFakeBlackType(const char* funcName, uint32_t texUnit,