Use enum to track MipMapsStatus throughout Texture creation

Bug: skia:
Change-Id: I1de1105d74b45f7b02ff52e6b8333801d98ef1ce
Reviewed-on: https://skia-review.googlesource.com/58501
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 31939bc..758d017 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -427,7 +427,7 @@
         }
         GrTexture* texture = surface->asTexture();
         if (texture && 1 == mipLevels) {
-            texture->texturePriv().dirtyMipMaps(true);
+            texture->texturePriv().markMipMapsDirty();
         }
     }
 }
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index c134c64..250b6dd 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -17,20 +17,20 @@
 #include "SkMipMap.h"
 #include "SkTypes.h"
 
-void GrTexture::dirtyMipMaps(bool mipMapsDirty) {
-    if (mipMapsDirty) {
-        if (kInvalid_MipMapsStatus == fMipMapsStatus || kClean_MipMapsStatus == fMipMapsStatus) {
-            fMipMapsStatus = kDirty_MipMapsStatus;
-        }
-    } else {
-        const bool sizeChanged = kNotAllocated_MipMapsStatus == fMipMapsStatus;
-        fMipMapsStatus = kClean_MipMapsStatus;
-        if (sizeChanged) {
-            // This must not be called until after changing fMipMapsStatus.
-            this->didChangeGpuMemorySize();
-            // TODO(http://skbug.com/4548) - The desc and scratch key should be
-            // updated to reflect the newly-allocated mipmaps.
-        }
+void GrTexture::markMipMapsDirty() {
+    if (GrMipMapsStatus::kValid == fMipMapsStatus) {
+        fMipMapsStatus = GrMipMapsStatus::kDirty;
+    }
+}
+
+void GrTexture::markMipMapsClean() {
+    const bool sizeChanged = GrMipMapsStatus::kNotAllocated == fMipMapsStatus;
+    fMipMapsStatus = GrMipMapsStatus::kValid;
+    if (sizeChanged) {
+        // This must not be called until after changing fMipMapsStatus.
+        this->didChangeGpuMemorySize();
+        // TODO(http://skbug.com/4548) - The desc and scratch key should be
+        // updated to reflect the newly-allocated mipmaps.
     }
 }
 
@@ -42,24 +42,17 @@
 /////////////////////////////////////////////////////////////////////////////
 GrTexture::GrTexture(GrGpu* gpu, const GrSurfaceDesc& desc, GrSLType samplerType,
                      GrSamplerState::Filter highestFilterMode,
-                     bool mipsAllocated, bool wasFullMipMapDataProvided)
+                     GrMipMapsStatus mipMapsStatus)
         : INHERITED(gpu, desc)
         , fSamplerType(samplerType)
         , fHighestFilterMode(highestFilterMode)
+        , fMipMapsStatus(mipMapsStatus)
         // Mip color mode is explicitly set after creation via GrTexturePriv
         , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) {
-    if (mipsAllocated) {
-        if (wasFullMipMapDataProvided) {
-            fMipMapsStatus = kClean_MipMapsStatus;
-        } else {
-            // Currently we should only hit this case when none of the mips were uploaded including
-            // the base. Thus we set this to invalid.
-            fMipMapsStatus = kInvalid_MipMapsStatus;
-        }
-        fMaxMipMapLevel = SkMipMap::ComputeLevelCount(this->width(), this->height());
-    } else {
-        fMipMapsStatus = kNotAllocated_MipMapsStatus;
+    if (GrMipMapsStatus::kNotAllocated == fMipMapsStatus) {
         fMaxMipMapLevel = 0;
+    } else {
+        fMaxMipMapLevel = SkMipMap::ComputeLevelCount(this->width(), this->height());
     }
 }
 
diff --git a/src/gpu/GrTexturePriv.h b/src/gpu/GrTexturePriv.h
index 3986c96..31d097ed 100644
--- a/src/gpu/GrTexturePriv.h
+++ b/src/gpu/GrTexturePriv.h
@@ -17,22 +17,20 @@
     implemented privately in GrTexture with a inline public method here). */
 class GrTexturePriv {
 public:
-    void dirtyMipMaps(bool mipMapsDirty) {
-        fTexture->dirtyMipMaps(mipMapsDirty);
+    void markMipMapsDirty() {
+        fTexture->markMipMapsDirty();
+    }
+
+    void markMipMapsClean() {
+        fTexture->markMipMapsClean();
     }
 
     bool mipMapsAreDirty() const {
-        return GrTexture::kClean_MipMapsStatus != fTexture->fMipMapsStatus;
+        return GrMipMapsStatus::kValid != fTexture->fMipMapsStatus;
     }
 
     bool hasMipMaps() const {
-        return GrTexture::kNotAllocated_MipMapsStatus != fTexture->fMipMapsStatus;
-    }
-
-    // Once we no longer support allocating mip levels after creation, we can also require that mips
-    // have been allocated to the valid check.
-    bool mipMapsAreValid() const {
-        return GrTexture::kInvalid_MipMapsStatus != fTexture->fMipMapsStatus;
+        return GrMipMapsStatus::kNotAllocated != fTexture->fMipMapsStatus;
     }
 
     void setMaxMipMapLevel(int maxMipMapLevel) const {
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index bef1f19..86aa76f 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1010,7 +1010,7 @@
                             GrSurfaceOrigin texOrigin, GrGLenum target, UploadType uploadType,
                             int left, int top, int width, int height, GrPixelConfig dataConfig,
                             const GrMipLevel texels[], int mipLevelCount,
-                            bool* wasFullMipMapDataProvided) {
+                            GrMipMapsStatus* mipMapsStatus) {
     SkASSERT(this->caps()->isConfigTexturable(texConfig));
     SkDEBUGCODE(
         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
@@ -1076,9 +1076,8 @@
     // in case we need a temporary, trimmed copy of the src pixels
     SkAutoSMalloc<128 * 128> tempStorage;
 
-    if (wasFullMipMapDataProvided) {
-        // Make sure this is initialized to true
-        *wasFullMipMapDataProvided = true;
+    if (mipMapsStatus) {
+        *mipMapsStatus = GrMipMapsStatus::kValid;
     }
 
     // find the combined size of all the mip levels and the relative offset of
@@ -1094,12 +1093,14 @@
             individualMipOffsets.push_back(combinedBufferSize);
             combinedBufferSize += trimmedSize;
         } else {
-            if (wasFullMipMapDataProvided) {
-                *wasFullMipMapDataProvided = false;
+            if (mipMapsStatus) {
+                *mipMapsStatus = GrMipMapsStatus::kDirty;
             }
             individualMipOffsets.push_back(0);
         }
-
+    }
+    if (mipMapsStatus && mipLevelCount <= 1) {
+        *mipMapsStatus = GrMipMapsStatus::kNotAllocated;
     }
     char* buffer = (char*)tempStorage.reset(combinedBufferSize);
 
@@ -1416,18 +1417,13 @@
 
     GrGLTexture::IDDesc idDesc;
     idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
-    bool wasFullMipMapDataProvided = true;
+    GrMipMapsStatus mipMapsStatus;
     GrGLTexture::TexParams initialTexParams;
     if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams,
-                                 texels, mipLevelCount, &wasFullMipMapDataProvided)) {
+                                 texels, mipLevelCount, &mipMapsStatus)) {
         return return_null_texture();
     }
 
-    bool mipsAllocated = false;
-    if (mipLevelCount > 1) {
-        mipsAllocated = true;
-    }
-
     sk_sp<GrGLTexture> tex;
     if (isRenderTarget) {
         // unbind the texture from the texture unit before binding it to the frame buffer
@@ -1439,11 +1435,10 @@
             return return_null_texture();
         }
         tex = sk_make_sp<GrGLTextureRenderTarget>(this, budgeted, desc, idDesc, rtIDDesc,
-                                                  mipsAllocated, wasFullMipMapDataProvided);
+                                                  mipMapsStatus);
         tex->baseLevelWasBoundToFBO();
     } else {
-        tex = sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc,
-                                      mipsAllocated, wasFullMipMapDataProvided);
+        tex = sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc, mipMapsStatus);
     }
     tex->setCachedTexParams(initialTexParams, this->getResetTimestamp());
 #ifdef TRACE_TEXTURE_CREATION
@@ -1615,7 +1610,7 @@
 bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info,
                                 bool renderTarget, GrGLTexture::TexParams* initialTexParams,
                                 const GrMipLevel texels[], int mipLevelCount,
-                                bool* wasFullMipMapDataProvided) {
+                                GrMipMapsStatus* mipMapsStatus) {
     info->fID = 0;
     info->fTarget = GR_GL_TEXTURE_2D;
     GL_CALL(GenTextures(1, &(info->fID)));
@@ -1639,7 +1634,7 @@
     }
     if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, desc.fOrigin, info->fTarget,
                              kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
-                             texels, mipLevelCount)) {
+                             texels, mipLevelCount, mipMapsStatus)) {
         GL_CALL(DeleteTextures(1, &(info->fID)));
         return false;
     }
@@ -3169,7 +3164,7 @@
         : SkDestinationSurfaceColorMode::kLegacy;
     if (GrPixelConfigIsSRGB(texture->config()) &&
         colorMode != texture->texturePriv().mipColorMode()) {
-        texture->texturePriv().dirtyMipMaps(true);
+        texture->texturePriv().markMipMapsDirty();
     }
 
     // If the mips aren't dirty, we're done:
@@ -3177,9 +3172,6 @@
         return;
     }
 
-    // Make sure we at least have some base layer to make mips from
-    SkASSERT(texture->texturePriv().mipMapsAreValid());
-
     // If we created a rt/tex and rendered to it without using a texture and now we're texturing
     // from the rt it will still be the last bound texture, but it needs resolving.
     GrGLRenderTarget* texRT = static_cast<GrGLRenderTarget*>(texture->asRenderTarget());
@@ -3211,7 +3203,7 @@
         GL_CALL(GenerateMipmap(target));
     }
 
-    texture->texturePriv().dirtyMipMaps(false);
+    texture->texturePriv().markMipMapsClean();
     texture->texturePriv().setMaxMipMapLevel(SkMipMap::ComputeLevelCount(
         texture->width(), texture->height()));
     texture->texturePriv().setMipColorMode(colorMode);
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 20758c3..a3af0ae 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -225,7 +225,7 @@
     bool createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info,
                            bool renderTarget, GrGLTexture::TexParams* initialTexParams,
                            const GrMipLevel texels[], int mipLevelCount,
-                           bool* wasFullMipMapDataProvided);
+                           GrMipMapsStatus* mipMapsStatus);
 
     bool onIsACopyNeededForTextureParams(GrTextureProxy*, const GrSamplerState&,
                                          GrTextureProducer::CopyParams*,
@@ -393,7 +393,7 @@
                        GrSurfaceOrigin texOrigin, GrGLenum target, UploadType uploadType, int left,
                        int top, int width, int height, GrPixelConfig dataConfig,
                        const GrMipLevel texels[], int mipLevelCount,
-                       bool* wasFullMipMapDataProvided = nullptr);
+                       GrMipMapsStatus* mipMapsStatus = nullptr);
 
     bool createRenderTargetObjects(const GrSurfaceDesc&, const GrGLTextureInfo& texInfo,
                                    GrGLRenderTarget::IDDesc*);
diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp
index 789c0b7..aa918d5 100644
--- a/src/gpu/gl/GrGLTexture.cpp
+++ b/src/gpu/gl/GrGLTexture.cpp
@@ -49,22 +49,10 @@
 
 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
 GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
-                         const IDDesc& idDesc)
+                         const IDDesc& idDesc, GrMipMapsStatus mipMapsStatus)
     : GrSurface(gpu, desc)
     , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
-                highest_filter_mode(idDesc, desc.fConfig), false, false) {
-    this->init(desc, idDesc);
-    this->registerWithCache(budgeted);
-}
-
-GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
-                         const IDDesc& idDesc,
-                         bool mipsAllocated,
-                         bool wasFullMipMapDataProvided)
-    : GrSurface(gpu, desc)
-    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
-                highest_filter_mode(idDesc, desc.fConfig),
-                mipsAllocated, wasFullMipMapDataProvided) {
+                highest_filter_mode(idDesc, desc.fConfig), mipMapsStatus) {
     this->init(desc, idDesc);
     this->registerWithCache(budgeted);
 }
@@ -72,17 +60,16 @@
 GrGLTexture::GrGLTexture(GrGLGpu* gpu, Wrapped, const GrSurfaceDesc& desc, const IDDesc& idDesc)
     : GrSurface(gpu, desc)
     , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
-                highest_filter_mode(idDesc, desc.fConfig), false, false) {
+                highest_filter_mode(idDesc, desc.fConfig), GrMipMapsStatus::kNotAllocated) {
     this->init(desc, idDesc);
     this->registerWithCacheWrapped();
 }
 
 GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc,
-                         bool mipsAllocated, bool wasFullMipMapDataProvided)
+                         GrMipMapsStatus mipMapsStatus)
     : GrSurface(gpu, desc)
     , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
-                highest_filter_mode(idDesc, desc.fConfig),
-                mipsAllocated, wasFullMipMapDataProvided) {
+                highest_filter_mode(idDesc, desc.fConfig), mipMapsStatus) {
     this->init(desc, idDesc);
 }
 
diff --git a/src/gpu/gl/GrGLTexture.h b/src/gpu/gl/GrGLTexture.h
index f2dc739..8ab6805 100644
--- a/src/gpu/gl/GrGLTexture.h
+++ b/src/gpu/gl/GrGLTexture.h
@@ -32,9 +32,7 @@
         GrGLTextureInfo             fInfo;
         GrBackendObjectOwnership    fOwnership;
     };
-    GrGLTexture(GrGLGpu*, SkBudgeted, const GrSurfaceDesc&, const IDDesc&);
-    GrGLTexture(GrGLGpu*, SkBudgeted, const GrSurfaceDesc&, const IDDesc&,
-                bool mipsAllocated, bool wasFullMipMapDataProvided);
+    GrGLTexture(GrGLGpu*, SkBudgeted, const GrSurfaceDesc&, const IDDesc&, GrMipMapsStatus);
 
     ~GrGLTexture() override {
         // check that invokeReleaseProc has been called (if needed)
@@ -73,8 +71,7 @@
 
 protected:
     // Constructor for subclasses.
-    GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&,
-                bool mipsAllocated, bool wasMipMapDataProvided);
+    GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&, GrMipMapsStatus);
 
     enum Wrapped { kWrapped };
     // Constructor for instances wrapping backend objects.
diff --git a/src/gpu/gl/GrGLTextureRenderTarget.cpp b/src/gpu/gl/GrGLTextureRenderTarget.cpp
index b60d3c9..c5a75be 100644
--- a/src/gpu/gl/GrGLTextureRenderTarget.cpp
+++ b/src/gpu/gl/GrGLTextureRenderTarget.cpp
@@ -17,10 +17,9 @@
                                                  const GrSurfaceDesc& desc,
                                                  const GrGLTexture::IDDesc& texIDDesc,
                                                  const GrGLRenderTarget::IDDesc& rtIDDesc,
-                                                 bool mipsAllocated,
-                                                 bool wasFullMipMapDataProvided)
+                                                 GrMipMapsStatus mipMapsStatus)
         : GrSurface(gpu, desc)
-        , GrGLTexture(gpu, desc, texIDDesc, mipsAllocated, wasFullMipMapDataProvided)
+        , GrGLTexture(gpu, desc, texIDDesc, mipMapsStatus)
         , GrGLRenderTarget(gpu, desc, rtIDDesc) {
     this->registerWithCache(budgeted);
 }
@@ -30,7 +29,7 @@
                                                  const GrGLTexture::IDDesc& texIDDesc,
                                                  const GrGLRenderTarget::IDDesc& rtIDDesc)
         : GrSurface(gpu, desc)
-        , GrGLTexture(gpu, desc, texIDDesc, false, false)
+        , GrGLTexture(gpu, desc, texIDDesc, GrMipMapsStatus::kNotAllocated)
         , GrGLRenderTarget(gpu, desc, rtIDDesc) {
     this->registerWithCacheWrapped();
 }
diff --git a/src/gpu/gl/GrGLTextureRenderTarget.h b/src/gpu/gl/GrGLTextureRenderTarget.h
index 2242933..6621f9c 100644
--- a/src/gpu/gl/GrGLTextureRenderTarget.h
+++ b/src/gpu/gl/GrGLTextureRenderTarget.h
@@ -29,8 +29,7 @@
                             const GrSurfaceDesc& desc,
                             const GrGLTexture::IDDesc& texIDDesc,
                             const GrGLRenderTarget::IDDesc& rtIDDesc,
-                            bool mipsAllocated,
-                            bool wasFullMipMapDataProvided);
+                            GrMipMapsStatus);
 
     bool canAttemptStencilAttachment() const override;
 
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index 470f306..9730dda 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -66,14 +66,15 @@
 
 sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                             const GrMipLevel texels[], int mipLevelCount) {
-    bool hasMipLevels = mipLevelCount > 1;
+    GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid
+                                                      : GrMipMapsStatus::kNotAllocated;
     GrMockTextureInfo info;
     info.fID = NextInternalTextureID();
     if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
         return sk_sp<GrTexture>(
-                new GrMockTextureRenderTarget(this, budgeted, desc, hasMipLevels, info));
+                new GrMockTextureRenderTarget(this, budgeted, desc, mipMapsStatus, info));
     }
-    return sk_sp<GrTexture>(new GrMockTexture(this, budgeted, desc, hasMipLevels, info));
+    return sk_sp<GrTexture>(new GrMockTexture(this, budgeted, desc, mipMapsStatus, info));
 }
 
 GrBuffer* GrMockGpu::onCreateBuffer(size_t sizeInBytes, GrBufferType type,
diff --git a/src/gpu/mock/GrMockTexture.h b/src/gpu/mock/GrMockTexture.h
index 21f0eec..0db583f 100644
--- a/src/gpu/mock/GrMockTexture.h
+++ b/src/gpu/mock/GrMockTexture.h
@@ -15,9 +15,9 @@
 
 class GrMockTexture : public GrTexture {
 public:
-    GrMockTexture(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, bool hasMipLevels,
-                  const GrMockTextureInfo& info)
-            : GrMockTexture(gpu, desc, hasMipLevels, info) {
+    GrMockTexture(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
+                  GrMipMapsStatus mipMapsStatus, const GrMockTextureInfo& info)
+            : GrMockTexture(gpu, desc, mipMapsStatus, info) {
         this->registerWithCache(budgeted);
     }
     ~GrMockTexture() override {
@@ -36,11 +36,11 @@
 
 protected:
     // constructor for subclasses
-    GrMockTexture(GrMockGpu* gpu, const GrSurfaceDesc& desc, bool hasMipLevels,
+    GrMockTexture(GrMockGpu* gpu, const GrSurfaceDesc& desc, GrMipMapsStatus mipMapsStatus,
                   const GrMockTextureInfo& info)
             : GrSurface(gpu, desc)
             , INHERITED(gpu, desc, kITexture2DSampler_GrSLType, GrSamplerState::Filter::kMipMap,
-                        hasMipLevels, hasMipLevels)
+                        mipMapsStatus)
             , fInfo(info)
             , fReleaseProc(nullptr)
             , fReleaseCtx(nullptr) {}
@@ -56,9 +56,9 @@
 class GrMockTextureRenderTarget : public GrMockTexture, public GrRenderTarget {
 public:
     GrMockTextureRenderTarget(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
-                              bool hasMipLevels, const GrMockTextureInfo& texInfo)
+                              GrMipMapsStatus mipMapsStatus, const GrMockTextureInfo& texInfo)
             : GrSurface(gpu, desc)
-            , GrMockTexture(gpu, desc, hasMipLevels, texInfo)
+            , GrMockTexture(gpu, desc, mipMapsStatus, texInfo)
             , GrRenderTarget(gpu, desc) {
         this->registerWithCache(budgeted);
     }
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 47035f9..a830959 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -128,7 +128,7 @@
                                                                     desc, mipLevels);
 #endif
     } else {
-        tex = GrMtlTexture::CreateNewTexture(this, budgeted, desc, mipLevels, false);
+        tex = GrMtlTexture::CreateNewTexture(this, budgeted, desc, mipLevels);
     }
 
     if (!tex) {
diff --git a/src/gpu/mtl/GrMtlTexture.h b/src/gpu/mtl/GrMtlTexture.h
index 0e5e30c..39194ec 100644
--- a/src/gpu/mtl/GrMtlTexture.h
+++ b/src/gpu/mtl/GrMtlTexture.h
@@ -17,8 +17,7 @@
 class GrMtlTexture : public GrTexture {
 public:
     static sk_sp<GrMtlTexture> CreateNewTexture(GrMtlGpu*, SkBudgeted budgeted,
-                                                const GrSurfaceDesc&, int mipLevels,
-                                                bool wasFullMipMapDataProvided);
+                                                const GrSurfaceDesc&, int mipLevels);
 
     static sk_sp<GrMtlTexture> MakeWrappedTexture(GrMtlGpu*, const GrSurfaceDesc&,
                                                   GrWrapOwnership);
@@ -55,8 +54,7 @@
 
 private:
     enum Wrapped { kWrapped };
-    GrMtlTexture(GrMtlGpu*, SkBudgeted, const GrSurfaceDesc&, id<MTLTexture>, bool isMipMapped,
-                 bool wasFullMipMapDataProvided);
+    GrMtlTexture(GrMtlGpu*, SkBudgeted, const GrSurfaceDesc&, id<MTLTexture>, GrMipMapsStatus);
    // GrMtlTexture(GrMtlGpu*, Wrapped, const GrSurfaceDesc&, GrMtlImage::Wrapped wrapped);
 
     id<MTLTexture> fTexture;
diff --git a/src/gpu/mtl/GrMtlTexture.mm b/src/gpu/mtl/GrMtlTexture.mm
index d66f2ba..e8d060b 100644
--- a/src/gpu/mtl/GrMtlTexture.mm
+++ b/src/gpu/mtl/GrMtlTexture.mm
@@ -12,8 +12,7 @@
 #include "GrTexturePriv.h"
 
 sk_sp<GrMtlTexture> GrMtlTexture::CreateNewTexture(GrMtlGpu* gpu, SkBudgeted budgeted,
-                                                   const GrSurfaceDesc& desc, int mipLevels,
-                                                   bool wasFullMipMapDataProvided) {
+                                                   const GrSurfaceDesc& desc, int mipLevels) {
     MTLPixelFormat format;
     if (!GrPixelConfigToMTLFormat(desc.fConfig, &format)) {
         return nullptr;
@@ -41,8 +40,10 @@
 
     id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:descriptor];
 
-    return sk_sp<GrMtlTexture>(new GrMtlTexture(gpu, budgeted, desc, texture, mipLevels > 1,
-                                                wasFullMipMapDataProvided));
+    GrMipMapsStatus mipMapsStatus = mipLevels > 1 ? GrMipMapsStatus::kValid
+                                                  : GrMipMapsStatus::kNotAllocated;
+
+    return sk_sp<GrMtlTexture>(new GrMtlTexture(gpu, budgeted, desc, texture, mipMapsStatus));
 }
 
 // This method parallels GrTextureProxy::highestFilterMode
@@ -58,11 +59,10 @@
                            SkBudgeted budgeted,
                            const GrSurfaceDesc& desc,
                            id<MTLTexture> texture,
-                           bool isMipMapped,
-                           bool wasFullMipMapDataProvided)
+                           GrMipMapsStatus)
         : GrSurface(gpu, desc)
         , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
-                    isMipMapped, wasFullMipMapDataProvided)
+                    mipMapsStatus)
         , fTexture(texture) {
 }
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index b756bd5..2119199 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -489,7 +489,7 @@
                                          1,
                                          &region);
 
-    vkTex->texturePriv().dirtyMipMaps(true);
+    vkTex->texturePriv().markMipMapsDirty();
     return true;
 }
 
@@ -766,7 +766,7 @@
                                          regions.begin());
     transferBuffer->unref();
     if (1 == mipLevelCount) {
-       tex->texturePriv().dirtyMipMaps(true);
+        tex->texturePriv().markMipMapsDirty();
     }
 
     return true;
@@ -818,11 +818,14 @@
     imageDesc.fUsageFlags = usageFlags;
     imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
 
-    bool fullMipMapDataProvided = true;
-    for (int i = 0; i < mipLevelCount; ++i) {
-        if (!texels[i].fPixels) {
-            fullMipMapDataProvided = false;
-            break;
+    GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated;
+    if (mipLevels > 1) {
+        mipMapsStatus = GrMipMapsStatus::kValid;
+        for (int i = 0; i < mipLevels; ++i) {
+            if (!texels[i].fPixels) {
+                mipMapsStatus = GrMipMapsStatus::kDirty;
+                break;
+            }
         }
     }
 
@@ -830,10 +833,10 @@
     if (renderTarget) {
         tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted, desc,
                                                                     imageDesc,
-                                                                    fullMipMapDataProvided);
+                                                                    mipMapsStatus);
     } else {
         tex = GrVkTexture::CreateNewTexture(this, budgeted, desc, imageDesc,
-                                            fullMipMapDataProvided);
+                                            mipMapsStatus);
     }
 
     if (!tex) {
@@ -999,9 +1002,6 @@
         return;
     }
 
-    // Make sure we at least have some base layer to make mips from
-    SkASSERT(tex->texturePriv().mipMapsAreValid());
-
     // determine if we can blit to and from this format
     const GrVkCaps& caps = this->vkCaps();
     if (!caps.configCanBeDstofBlit(tex->config(), false) ||
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index e6eb4c3..a1b187d 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -570,7 +570,7 @@
         if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter()) {
             if (vkTexture->texturePriv().mipMapsAreDirty()) {
                 gpu->generateMipmap(vkTexture, sampler.proxy()->origin());
-                vkTexture->texturePriv().dirtyMipMaps(false);
+                vkTexture->texturePriv().markMipMapsClean();
             }
         }
         set_texture_layout(vkTexture, gpu);
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index 7d8f017..c4f55d7 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -32,13 +32,14 @@
                          const GrSurfaceDesc& desc,
                          const GrVkImageInfo& info,
                          const GrVkImageView* view,
-                         bool wasFullMipMapDataProvided)
+                         GrMipMapsStatus mipMapsStatus)
     : GrSurface(gpu, desc)
     , GrVkImage(info, GrBackendObjectOwnership::kOwned)
     , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
-                info.fLevelCount > 1, wasFullMipMapDataProvided)
+                mipMapsStatus)
     , fTextureView(view)
     , fLinearTextureView(nullptr) {
+    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
     this->registerWithCache(budgeted);
 }
 
@@ -47,13 +48,15 @@
                          const GrSurfaceDesc& desc,
                          const GrVkImageInfo& info,
                          const GrVkImageView* view,
+                         GrMipMapsStatus mipMapsStatus,
                          GrBackendObjectOwnership ownership)
     : GrSurface(gpu, desc)
     , GrVkImage(info, ownership)
     , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
-                info.fLevelCount > 1, false)
+                mipMapsStatus)
     , fTextureView(view)
     , fLinearTextureView(nullptr) {
+    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
     this->registerWithCacheWrapped();
 }
 
@@ -62,20 +65,21 @@
                          const GrSurfaceDesc& desc,
                          const GrVkImageInfo& info,
                          const GrVkImageView* view,
-                         GrBackendObjectOwnership ownership,
-                         bool wasFullMipMapDataProvided)
+                         GrMipMapsStatus mipMapsStatus,
+                         GrBackendObjectOwnership ownership)
     : GrSurface(gpu, desc)
     , GrVkImage(info, ownership)
     , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
-                info.fLevelCount > 1, wasFullMipMapDataProvided)
+                mipMapsStatus)
     , fTextureView(view)
     , fLinearTextureView(nullptr) {
+    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
 }
 
 sk_sp<GrVkTexture> GrVkTexture::CreateNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
                                                  const GrSurfaceDesc& desc,
                                                  const GrVkImage::ImageDesc& imageDesc,
-                                                 bool fullMipMapDataProvided) {
+                                                 GrMipMapsStatus mipMapsStatus) {
     SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
 
     GrVkImageInfo info;
@@ -92,7 +96,7 @@
     }
 
     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, desc, info, imageView,
-                                              fullMipMapDataProvided));
+                                              mipMapsStatus));
 }
 
 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
@@ -110,9 +114,13 @@
         return nullptr;
     }
 
+    GrMipMapsStatus mipMapsStatus = info->fLevelCount > 1 ? GrMipMapsStatus::kValid
+                                                          : GrMipMapsStatus::kNotAllocated;
+
     GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
             ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
-    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, kWrapped, desc, *info, imageView, ownership));
+    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, kWrapped, desc, *info, imageView,
+                                              mipMapsStatus, ownership));
 }
 
 GrVkTexture::~GrVkTexture() {
diff --git a/src/gpu/vk/GrVkTexture.h b/src/gpu/vk/GrVkTexture.h
index fde7d72..d3acce8 100644
--- a/src/gpu/vk/GrVkTexture.h
+++ b/src/gpu/vk/GrVkTexture.h
@@ -21,7 +21,7 @@
                                                SkBudgeted budgeted,
                                                const GrSurfaceDesc&,
                                                const GrVkImage::ImageDesc&,
-                                               bool wasFullMipMapDataProvided);
+                                               GrMipMapsStatus);
 
     static sk_sp<GrVkTexture> MakeWrappedTexture(GrVkGpu*, const GrSurfaceDesc&,
                                                  GrWrapOwnership, const GrVkImageInfo*);
@@ -45,7 +45,7 @@
 
 protected:
     GrVkTexture(GrVkGpu*, const GrSurfaceDesc&, const GrVkImageInfo&, const GrVkImageView*,
-                GrBackendObjectOwnership, bool wasFullMipMapDataProvided);
+                GrMipMapsStatus, GrBackendObjectOwnership);
 
     GrVkGpu* getVkGpu() const;
 
@@ -56,9 +56,10 @@
     enum Wrapped { kWrapped };
     GrVkTexture(GrVkGpu*, SkBudgeted, const GrSurfaceDesc&,
                 const GrVkImageInfo&, const GrVkImageView* imageView,
-                bool wasFullMipMapDataProvided);
+                GrMipMapsStatus);
     GrVkTexture(GrVkGpu*, Wrapped, const GrSurfaceDesc&,
-                const GrVkImageInfo&, const GrVkImageView* imageView, GrBackendObjectOwnership);
+                const GrVkImageInfo&, const GrVkImageView* imageView, GrMipMapsStatus,
+                GrBackendObjectOwnership);
 
     const GrVkImageView*     fTextureView;
     const GrVkImageView*     fLinearTextureView;
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp
index 4a9859b..81509a9 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.cpp
+++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp
@@ -26,11 +26,11 @@
                                                  const GrVkImageInfo& msaaInfo,
                                                  const GrVkImageView* colorAttachmentView,
                                                  const GrVkImageView* resolveAttachmentView,
-                                                 GrBackendObjectOwnership ownership,
-                                                 bool wasFullMipMapDataProvided)
+                                                 GrMipMapsStatus mipMapsStatus,
+                                                 GrBackendObjectOwnership ownership)
         : GrSurface(gpu, desc)
         , GrVkImage(info, ownership)
-        , GrVkTexture(gpu, desc, info, texView, ownership, wasFullMipMapDataProvided)
+        , GrVkTexture(gpu, desc, info, texView, mipMapsStatus, ownership)
         , GrVkRenderTarget(gpu, desc, info, msaaInfo, colorAttachmentView,
                            resolveAttachmentView, GrBackendObjectOwnership::kOwned) {
     this->registerWithCache(budgeted);
@@ -42,11 +42,11 @@
                                                  const GrVkImageInfo& info,
                                                  const GrVkImageView* texView,
                                                  const GrVkImageView* colorAttachmentView,
-                                                 GrBackendObjectOwnership ownership,
-                                                 bool wasFullMipMapDataProvided)
+                                                 GrMipMapsStatus mipMapsStatus,
+                                                 GrBackendObjectOwnership ownership)
         : GrSurface(gpu, desc)
         , GrVkImage(info, ownership)
-        , GrVkTexture(gpu, desc, info, texView, ownership, wasFullMipMapDataProvided)
+        , GrVkTexture(gpu, desc, info, texView, mipMapsStatus, ownership)
         , GrVkRenderTarget(gpu, desc, info, colorAttachmentView, GrBackendObjectOwnership::kOwned) {
     this->registerWithCache(budgeted);
 }
@@ -58,10 +58,11 @@
                                                  const GrVkImageInfo& msaaInfo,
                                                  const GrVkImageView* colorAttachmentView,
                                                  const GrVkImageView* resolveAttachmentView,
+                                                 GrMipMapsStatus mipMapsStatus,
                                                  GrBackendObjectOwnership ownership)
         : GrSurface(gpu, desc)
         , GrVkImage(info, ownership)
-        , GrVkTexture(gpu, desc, info, texView, ownership, false)
+        , GrVkTexture(gpu, desc, info, texView, mipMapsStatus, ownership)
         , GrVkRenderTarget(gpu, desc, info, msaaInfo, colorAttachmentView,
                            resolveAttachmentView, ownership) {
     this->registerWithCacheWrapped();
@@ -72,23 +73,22 @@
                                                  const GrVkImageInfo& info,
                                                  const GrVkImageView* texView,
                                                  const GrVkImageView* colorAttachmentView,
+                                                 GrMipMapsStatus mipMapsStatus,
                                                  GrBackendObjectOwnership ownership)
         : GrSurface(gpu, desc)
         , GrVkImage(info, ownership)
-        , GrVkTexture(gpu, desc, info, texView, ownership, false)
+        , GrVkTexture(gpu, desc, info, texView, mipMapsStatus, ownership)
         , GrVkRenderTarget(gpu, desc, info, colorAttachmentView, ownership) {
     this->registerWithCacheWrapped();
 }
 
-
 sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu,
                                                              const GrSurfaceDesc& desc,
                                                              const GrVkImageInfo& info,
+                                                             GrMipMapsStatus mipMapsStatus,
                                                              SkBudgeted budgeted,
                                                              GrBackendObjectOwnership ownership,
-                                                             bool isWrapped,
-                                                             bool wasFullMipMapDataProvided) {
-    SkASSERT(!wasFullMipMapDataProvided || !isWrapped);
+                                                             bool isWrapped) {
     VkImage image = info.fImage;
     // Create the texture ImageView
     const GrVkImageView* imageView = GrVkImageView::Create(gpu, image, info.fFormat,
@@ -160,27 +160,29 @@
                                                       gpu, budgeted, desc,
                                                       info, imageView, msInfo,
                                                       colorAttachmentView,
-                                                      resolveAttachmentView, ownership,
-                                                      wasFullMipMapDataProvided));
+                                                      resolveAttachmentView, mipMapsStatus,
+                                                      ownership));
         } else {
             texRT = sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
                                                         gpu, desc,
                                                         info, imageView, msInfo,
                                                         colorAttachmentView,
-                                                        resolveAttachmentView, ownership));
+                                                        resolveAttachmentView, mipMapsStatus,
+                                                        ownership));
         }
     } else {
         if (!isWrapped) {
             texRT = sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
                                                         gpu, budgeted, desc,
                                                         info, imageView,
-                                                        colorAttachmentView, ownership,
-                                                        wasFullMipMapDataProvided));
+                                                        colorAttachmentView, mipMapsStatus,
+                                                        ownership));
         } else {
             texRT = sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
                                                         gpu, desc,
                                                         info, imageView,
-                                                        colorAttachmentView, ownership));
+                                                        colorAttachmentView, mipMapsStatus,
+                                                        ownership));
         }
     }
     return texRT;
@@ -191,7 +193,7 @@
                                                       SkBudgeted budgeted,
                                                       const GrSurfaceDesc& desc,
                                                       const GrVkImage::ImageDesc& imageDesc,
-                                                      bool wasFullMipMapDataProvided) {
+                                                      GrMipMapsStatus mipMapsStatus) {
     SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
     SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
 
@@ -200,9 +202,8 @@
         return nullptr;
     }
 
-    sk_sp<GrVkTextureRenderTarget> trt = Make(gpu, desc, info, budgeted,
-                                              GrBackendObjectOwnership::kOwned, false,
-                                              wasFullMipMapDataProvided);
+    sk_sp<GrVkTextureRenderTarget> trt = Make(gpu, desc, info, mipMapsStatus, budgeted,
+                                              GrBackendObjectOwnership::kOwned, false);
     if (!trt) {
         GrVkImage::DestroyImageInfo(gpu, &info);
     }
@@ -219,10 +220,13 @@
     // Wrapped textures require both image and allocation (because they can be mapped)
     SkASSERT(VK_NULL_HANDLE != info->fImage && VK_NULL_HANDLE != info->fAlloc.fMemory);
 
+    GrMipMapsStatus mipMapsStatus = info->fLevelCount > 1 ? GrMipMapsStatus::kDirty
+                                                          : GrMipMapsStatus::kNotAllocated;
+
     GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
             ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
 
-    return Make(gpu, desc, *info, SkBudgeted::kNo, ownership, true, false);
+    return Make(gpu, desc, *info, mipMapsStatus, SkBudgeted::kNo, ownership, true);
 }
 
 bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo& newInfo) {
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.h b/src/gpu/vk/GrVkTextureRenderTarget.h
index 056be2e..4b3e057 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.h
+++ b/src/gpu/vk/GrVkTextureRenderTarget.h
@@ -28,7 +28,7 @@
     static sk_sp<GrVkTextureRenderTarget> CreateNewTextureRenderTarget(GrVkGpu*, SkBudgeted,
                                                                        const GrSurfaceDesc&,
                                                                        const GrVkImage::ImageDesc&,
-                                                                       bool fullMipMapDataProvided);
+                                                                       GrMipMapsStatus);
 
     static sk_sp<GrVkTextureRenderTarget> MakeWrappedTextureRenderTarget(GrVkGpu*,
                                                                          const GrSurfaceDesc&,
@@ -57,8 +57,8 @@
                             const GrVkImageInfo& msaaInfo,
                             const GrVkImageView* colorAttachmentView,
                             const GrVkImageView* resolveAttachmentView,
-                            GrBackendObjectOwnership,
-                            bool wasFullMipMapDataProvided);
+                            GrMipMapsStatus,
+                            GrBackendObjectOwnership);
 
     GrVkTextureRenderTarget(GrVkGpu* gpu,
                             SkBudgeted budgeted,
@@ -66,8 +66,8 @@
                             const GrVkImageInfo& info,
                             const GrVkImageView* texView,
                             const GrVkImageView* colorAttachmentView,
-                            GrBackendObjectOwnership,
-                            bool wasFullMipMapDataProvided);
+                            GrMipMapsStatus,
+                            GrBackendObjectOwnership);
 
     GrVkTextureRenderTarget(GrVkGpu* gpu,
                             const GrSurfaceDesc& desc,
@@ -76,6 +76,7 @@
                             const GrVkImageInfo& msaaInfo,
                             const GrVkImageView* colorAttachmentView,
                             const GrVkImageView* resolveAttachmentView,
+                            GrMipMapsStatus,
                             GrBackendObjectOwnership);
 
     GrVkTextureRenderTarget(GrVkGpu* gpu,
@@ -83,15 +84,16 @@
                             const GrVkImageInfo& info,
                             const GrVkImageView* texView,
                             const GrVkImageView* colorAttachmentView,
+                            GrMipMapsStatus,
                             GrBackendObjectOwnership);
 
     static sk_sp<GrVkTextureRenderTarget> Make(GrVkGpu*,
                                                const GrSurfaceDesc&,
                                                const GrVkImageInfo&,
+                                               GrMipMapsStatus,
                                                SkBudgeted budgeted,
                                                GrBackendObjectOwnership,
-                                               bool isWrapped,
-                                               bool wasFullMipMapDataProvided);
+                                               bool isWrapped);
 
     // GrGLRenderTarget accounts for the texture's memory and any MSAA renderbuffer's memory.
     size_t onGpuMemorySize() const override;