Reland "Reland "Require mips to be allocated at texture creation time and disable late allocations.""

This reverts commit 01422bc8eff0c317b9c234b3b4f5a82f1011dfce.

Reason for revert: follow on change may be ready

Original change's description:
> Revert "Reland "Require mips to be allocated at texture creation time and disable late allocations.""
> 
> This reverts commit 9eb36b9eb8e81e970e02fa985ae82fe64de0a8f0.
> 
> Reason for revert: Alpha8 isn't renderable on es2 so we end up dropping draws on certain A8 mip requests
> 
> Original change's description:
> > Reland "Require mips to be allocated at texture creation time and disable late allocations."
> > 
> > This reverts commit 0c78238e2991c95b6fb3c945d4ad2b5d941ae21b.
> > 
> > Reason for revert: <INSERT REASONING HERE>
> > 
> > Original change's description:
> > > Revert "Require mips to be allocated at texture creation time and disable late allocations."
> > > 
> > > This reverts commit cd2c3f9055452d413d6be7ea6dc63fd1922fe994.
> > > 
> > > Reason for revert: Looks to be causing angle failures on initial clear test
> > > 
> > > Original change's description:
> > > > Require mips to be allocated at texture creation time and disable late allocations.
> > > > 
> > > > If we get a non-mipped texture for a draw that wants to be use mip map filter, we
> > > > will copy the texture into a new mipped texture.
> > > > 
> > > > Clean up of unused code in the GPU backends for reallocating for mips will be done
> > > > in a follow up CL.
> > > > 
> > > > Bug: skia:
> > > > Change-Id: Idab588c1abf4bbbf7eeceb3727d500e5df274188
> > > > Reviewed-on: https://skia-review.googlesource.com/132830
> > > > Reviewed-by: Brian Salomon <bsalomon@google.com>
> > > > Commit-Queue: Greg Daniel <egdaniel@google.com>
> > > 
> > >
> > > 
> > > Change-Id: I49f0ace52f2586d61b451630b2e6aae84b420b81
> > > No-Presubmit: true
> > > No-Tree-Checks: true
> > > No-Try: true
> > > Bug: skia:
> > > Reviewed-on: https://skia-review.googlesource.com/133041
> > > Reviewed-by: Greg Daniel <egdaniel@google.com>
> > > Commit-Queue: Greg Daniel <egdaniel@google.com>
> > 
> > Bug: skia:
> > Change-Id: I004447a5f1ec72c3be2318ddea803f57efb12ea4
> > Reviewed-on: https://skia-review.googlesource.com/133340
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> > Commit-Queue: Greg Daniel <egdaniel@google.com>
> 
> TBR=egdaniel@google.com,bsalomon@google.com,robertphillips@google.com
> 
> Change-Id: I9e9718d380c4d9927ec39e46008750ab7396391f
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/133680
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Commit-Queue: Greg Daniel <egdaniel@google.com>

TBR=egdaniel@google.com,bsalomon@google.com,robertphillips@google.com

Change-Id: Ic3df69f65a89962b21cdb50ee436a29fd121ab1f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/133740
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/bench/GrMipMapBench.cpp b/bench/GrMipMapBench.cpp
index e756c13..e7f34de 100644
--- a/bench/GrMipMapBench.cpp
+++ b/bench/GrMipMapBench.cpp
@@ -37,7 +37,11 @@
             auto srgb = SkColorSpace::MakeSRGB();
             SkImageInfo info =
                     SkImageInfo::Make(fW, fH, kRGBA_8888_SkColorType, kPremul_SkAlphaType, srgb);
-            fSurface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
+            // We're benching the regeneration of the mip levels not the need to allocate them every
+            // frame. Thus we create the surface with mips to begin with.
+            fSurface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
+                                                   kBottomLeft_GrSurfaceOrigin, nullptr, true);
+
         }
 
         // Clear surface once:
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index f3771a7..3a7294b 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -63,20 +63,9 @@
                               GrMipMapped, bool useNextPow2 = false);
 
 protected:
-    void setDoesNotSupportMipMaps() {
-        SkASSERT(this->asTexture());
-        fSurfaceFlags |= GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
-    }
-    bool doesNotSupportMipMaps() const {
-        return fSurfaceFlags & GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
-    }
-
     void setIsGLTextureRectangleOrExternal() {
         SkASSERT(this->asTexture());
         fSurfaceFlags |= GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
-        // If we are a GL rectangle or external texture, it also means that we do not support
-        // generating mip maps.
-        this->setDoesNotSupportMipMaps();
     }
     bool isGLTextureRectangleOrExternal() const {
         return fSurfaceFlags & GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index 8bbdbf2..fc7f1c5 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -100,18 +100,8 @@
 
     sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
 
-    void setDoesNotSupportMipMaps() {
-        fSurfaceFlags |= GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
-    }
-    bool doesNotSupportMipMaps() const {
-        return fSurfaceFlags & GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
-    }
-
     void setIsGLTextureRectangleOrExternal() {
         fSurfaceFlags |= GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
-        // If we are a GL rectangle or external texture, it also means that we do not support
-        // generating mip maps.
-        this->setDoesNotSupportMipMaps();
     }
     bool isGLTextureRectangleOrExternal() const {
         return fSurfaceFlags & GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 71871a0..5913a1e 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -873,20 +873,14 @@
 
     // Texture-only flags
 
-    // This flag is set when the internal texture target doesn't support mipmaps (e.g.,
-    // external and rectangle textures). Note that Ganesh does not internally
-    // create resources with this limitation - this flag will only appear on resources passed
-    // into Ganesh.
-    kDoesNotSupportMipMaps          = 1 << 1,
-
     // This flag is for GL only. It says that the GL texture we will use has a target which is
     // either GL_TEXTURE_RECTANGLE or GL_GL_TEXTURE_EXTERNAL. We use this information to make
     // decisions about various rendering capabilites (e.g. is clamp the only supported wrap mode).
     // Note: Ganesh does not internally create these types of textures so they will only occur on
     // resources passed into Ganesh.
-    kIsGLTextureRectangleOrExternal = 1 << 2,
+    kIsGLTextureRectangleOrExternal = 1 << 1,
 
-    kTextureMask                    = kDoesNotSupportMipMaps | kIsGLTextureRectangleOrExternal,
+    kTextureMask                    = kIsGLTextureRectangleOrExternal,
 
     // RT-only
 
@@ -896,17 +890,17 @@
     //    this is disabled for FBO0
     //    but, otherwise, is enabled whenever MSAA is enabled and GrCaps reports mixed samples
     //        are supported
-    kMixedSampled                   = 1 << 3,
+    kMixedSampled                   = 1 << 2,
 
     // For internal resources:
     //    this is enabled whenever GrCaps reports window rect support
     // For wrapped resources1
     //    this is disabled for FBO0
     //    but, otherwise, is enabled whenever GrCaps reports window rect support
-    kWindowRectsSupport             = 1 << 4,
+    kWindowRectsSupport             = 1 << 3,
 
     // This flag is for use with GL only. It tells us that the internal render target wraps FBO 0.
-    kGLRTFBOIDIs0                   = 1 << 5,
+    kGLRTFBOIDIs0                   = 1 << 4,
 
     kRenderTargetMask               = kMixedSampled | kWindowRectsSupport | kGLRTFBOIDIs0,
 };
diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp
index 56826d2..4147abd 100644
--- a/src/gpu/GrBackendTextureImageGenerator.cpp
+++ b/src/gpu/GrBackendTextureImageGenerator.cpp
@@ -180,12 +180,6 @@
         return nullptr;
     }
 
-    // We can't pass the fact that this creates a wrapped texture into createLazyProxy so we need
-    // to manually call setDoesNotSupportMipMaps.
-    if (GrMipMapped::kNo == mipMapped) {
-        proxy->texPriv().setDoesNotSupportMipMaps();
-    }
-
     if (0 == origin.fX && 0 == origin.fY &&
         info.width() == fBackendTexture.width() && info.height() == fBackendTexture.height() &&
         (!willNeedMipMaps || GrMipMapped::kYes == proxy->mipMapped())) {
diff --git a/src/gpu/GrBitmapTextureMaker.cpp b/src/gpu/GrBitmapTextureMaker.cpp
index d2a1fbe..4ecd761 100644
--- a/src/gpu/GrBitmapTextureMaker.cpp
+++ b/src/gpu/GrBitmapTextureMaker.cpp
@@ -89,10 +89,6 @@
             }
             return mippedProxy;
         }
-        // We failed to make a mipped proxy with the base copied into it. This could have
-        // been from failure to make the proxy or failure to do the copy. Thus we will fall
-        // back to just using the non mipped proxy; See skbug.com/7094.
-        return proxy;
     }
     return nullptr;
 }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 5c2864d..8781cbf 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -50,13 +50,34 @@
                                           const GrSamplerState& textureParams,
                                           GrTextureProducer::CopyParams* copyParams,
                                           SkScalar scaleAdjust[2]) {
+    if (textureParams.isRepeated() && !caps->npotTextureTileSupport() &&
+        (!SkIsPow2(width) || !SkIsPow2(height))) {
+        SkASSERT(scaleAdjust);
+        copyParams->fWidth = GrNextPow2(width);
+        copyParams->fHeight = GrNextPow2(height);
+        SkASSERT(scaleAdjust);
+        scaleAdjust[0] = ((SkScalar)copyParams->fWidth) / width;
+        scaleAdjust[1] = ((SkScalar)copyParams->fHeight) / height;
+        switch (textureParams.filter()) {
+        case GrSamplerState::Filter::kNearest:
+            copyParams->fFilter = GrSamplerState::Filter::kNearest;
+            break;
+        case GrSamplerState::Filter::kBilerp:
+        case GrSamplerState::Filter::kMipMap:
+            // We are only ever scaling up so no reason to ever indicate kMipMap.
+            copyParams->fFilter = GrSamplerState::Filter::kBilerp;
+            break;
+        }
+        return true;
+    }
 
     if (texProxy) {
+        bool willNeedMips = GrSamplerState::Filter::kMipMap == textureParams.filter() &&
+                            caps->mipMapSupport();
         // If the texture format itself doesn't support repeat wrap mode or mipmapping (and
         // those capabilities are required) force a copy.
         if ((textureParams.isRepeated() && texProxy->texPriv().isClampOnly()) ||
-            (GrSamplerState::Filter::kMipMap == textureParams.filter() &&
-                                                    texProxy->texPriv().doesNotSupportMipMaps())) {
+            (willNeedMips && texProxy->mipMapped() == GrMipMapped::kNo)) {
             copyParams->fFilter = GrSamplerState::Filter::kNearest;
             copyParams->fWidth = texProxy->width();
             copyParams->fHeight = texProxy->height();
@@ -64,26 +85,6 @@
         }
     }
 
-    if (textureParams.isRepeated() && !caps->npotTextureTileSupport() &&
-        (!SkIsPow2(width) || !SkIsPow2(height))) {
-        SkASSERT(scaleAdjust);
-        copyParams->fWidth = GrNextPow2(width);
-        copyParams->fHeight = GrNextPow2(height);
-        SkASSERT(scaleAdjust);
-        scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width;
-        scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height;
-        switch (textureParams.filter()) {
-            case GrSamplerState::Filter::kNearest:
-                copyParams->fFilter = GrSamplerState::Filter::kNearest;
-                break;
-            case GrSamplerState::Filter::kBilerp:
-            case GrSamplerState::Filter::kMipMap:
-                // We are only ever scaling up so no reason to ever indicate kMipMap.
-                copyParams->fFilter = GrSamplerState::Filter::kBilerp;
-                break;
-        }
-        return true;
-    }
     return false;
 }
 
@@ -138,13 +139,7 @@
         backendTex.height() > this->caps()->maxTextureSize()) {
         return nullptr;
     }
-    sk_sp<GrTexture> tex = this->onWrapBackendTexture(backendTex, ownership);
-    if (tex && !backendTex.hasMipMaps()) {
-        // Ganesh will not ever allocate mipmaps for a wrapped resource. By setting this flag here,
-        // it will be propagated to any proxy that wraps this texture.
-        tex->texturePriv().setDoesNotSupportMipMaps();
-    }
-    return tex;
+    return this->onWrapBackendTexture(backendTex, ownership);
 }
 
 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
@@ -163,11 +158,6 @@
         return nullptr;
     }
     sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, ownership);
-    if (tex && !backendTex.hasMipMaps()) {
-        // Ganesh will not ever allocate mipmaps for a wrapped resource. By setting this flag here,
-        // it will be propagated to any proxy that wraps this texture.
-        tex->texturePriv().setDoesNotSupportMipMaps();
-    }
     SkASSERT(!tex || tex->asRenderTarget());
     return tex;
 }
diff --git a/src/gpu/GrSurfacePriv.h b/src/gpu/GrSurfacePriv.h
index 5c98e3f..45a097b 100644
--- a/src/gpu/GrSurfacePriv.h
+++ b/src/gpu/GrSurfacePriv.h
@@ -40,7 +40,6 @@
 
     GrInternalSurfaceFlags flags() const { return fSurface->fSurfaceFlags; }
 
-    bool doesNotSupportMipMaps() const { return fSurface->doesNotSupportMipMaps(); }
     bool isGLTextureRectangleOrExternal() const {
         return fSurface->isGLTextureRectangleOrExternal();
     }
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index cd3e705..0051a22 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -25,14 +25,8 @@
 }
 
 void GrTexture::markMipMapsClean() {
-    const bool sizeChanged = GrMipMapsStatus::kNotAllocated == fMipMapsStatus;
+    SkASSERT(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.
-    }
 }
 
 size_t GrTexture::onGpuMemorySize() const {
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp
index cc61533..cb296f9 100644
--- a/src/gpu/GrTextureAdjuster.cpp
+++ b/src/gpu/GrTextureAdjuster.cpp
@@ -43,10 +43,11 @@
 
     GrUniqueKey key;
     this->makeCopyKey(copyParams, &key, nullptr);
+    sk_sp<GrTextureProxy> cachedCopy;
     if (key.isValid()) {
-        sk_sp<GrTextureProxy> cachedCopy =
-                proxyProvider->findOrCreateProxyByUniqueKey(key, this->originalProxy()->origin());
-        if (cachedCopy) {
+        cachedCopy = proxyProvider->findOrCreateProxyByUniqueKey(key,
+                                                                 this->originalProxy()->origin());
+        if (cachedCopy && (!willBeMipped || GrMipMapped::kYes == cachedCopy->mipMapped())) {
             return cachedCopy;
         }
     }
@@ -57,6 +58,14 @@
     if (copy) {
         if (key.isValid()) {
             SkASSERT(copy->origin() == this->originalProxy()->origin());
+            if (cachedCopy) {
+                SkASSERT(GrMipMapped::kYes == copy->mipMapped() &&
+                         GrMipMapped::kNo == cachedCopy->mipMapped());
+                // If we had a cachedProxy, that means there already is a proxy in the cache which
+                // matches the key, but it does not have mip levels and we require them. Thus we
+                // must remove the unique key from that proxy.
+                proxyProvider->removeUniqueKeyFromProxy(key, cachedCopy.get());
+            }
             proxyProvider->assignUniqueKeyToProxy(key, copy.get());
             this->didCacheCopy(key);
         }
@@ -89,7 +98,8 @@
         return proxy;
     }
 
-    bool willBeMipped = GrSamplerState::Filter::kMipMap == params.filter();
+    bool willBeMipped = GrSamplerState::Filter::kMipMap == params.filter() &&
+                        fContext->contextPriv().caps()->mipMapSupport();
     return this->refTextureProxyCopy(copyParams, willBeMipped);
 }
 
diff --git a/src/gpu/GrTexturePriv.h b/src/gpu/GrTexturePriv.h
index 4517e9e..2979e8b 100644
--- a/src/gpu/GrTexturePriv.h
+++ b/src/gpu/GrTexturePriv.h
@@ -44,10 +44,6 @@
         return fTexture->fMaxMipMapLevel;
     }
 
-    void setDoesNotSupportMipMaps() {
-        fTexture->setDoesNotSupportMipMaps();
-    }
-
     GrSLType samplerType() const { return fTexture->fSamplerType; }
 
     /** The filter used is clamped to this value in GrProcessor::TextureSampler. */
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index d9fffbc..1e9c3ac 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -10,6 +10,7 @@
 #include "GrProxyProvider.h"
 #include "GrRenderTargetContext.h"
 #include "GrTextureProxy.h"
+#include "SkGr.h"
 #include "SkRectPriv.h"
 #include "effects/GrBicubicEffect.h"
 #include "effects/GrSimpleTextureEffect.h"
@@ -24,6 +25,24 @@
     const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
     GrMipMapped mipMapped = dstWillRequireMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
 
+    SkRect localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height());
+
+    bool needsDomain = false;
+    bool resizing = false;
+    if (copyParams.fFilter != GrSamplerState::Filter::kNearest) {
+        bool resizing = localRect.width()  != dstRect.width() ||
+                        localRect.height() != dstRect.height();
+        needsDomain = resizing && !GrProxyProvider::IsFunctionallyExact(inputProxy.get());
+    }
+
+    if (copyParams.fFilter == GrSamplerState::Filter::kNearest && !needsDomain && !resizing &&
+        dstWillRequireMipMaps) {
+        sk_sp<GrTextureProxy> proxy = GrCopyBaseMipMapToTextureProxy(context, inputProxy.get());
+        if (proxy) {
+            return proxy;
+        }
+    }
+
     sk_sp<GrRenderTargetContext> copyRTC =
         context->contextPriv().makeDeferredRenderTargetContextWithFallback(
             SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(),
@@ -33,14 +52,6 @@
     }
 
     GrPaint paint;
-    SkRect localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height());
-
-    bool needsDomain = false;
-    if (copyParams.fFilter != GrSamplerState::Filter::kNearest) {
-        bool resizing = localRect.width()  != dstRect.width() ||
-                        localRect.height() != dstRect.height();
-        needsDomain = resizing && !GrProxyProvider::IsFunctionallyExact(inputProxy.get());
-    }
 
     if (needsDomain) {
         const SkRect domain = localRect.makeInset(0.5f, 0.5f);
diff --git a/src/gpu/GrTextureProxyPriv.h b/src/gpu/GrTextureProxyPriv.h
index cadd2fd..358369d 100644
--- a/src/gpu/GrTextureProxyPriv.h
+++ b/src/gpu/GrTextureProxyPriv.h
@@ -31,7 +31,6 @@
     // been instantiated or not.
     GrMipMapped proxyMipMapped() const { return fTextureProxy->fMipMapped; }
 
-    bool doesNotSupportMipMaps() const { return fTextureProxy->doesNotSupportMipMaps(); }
     bool isGLTextureRectangleOrExternal() const {
         return fTextureProxy->isGLTextureRectangleOrExternal();
     }
@@ -41,10 +40,6 @@
     // We only support the clamp wrap mode with gl rectangle or external textures.
     bool isClampOnly() const { return fTextureProxy->isGLTextureRectangleOrExternal(); }
 
-    void setDoesNotSupportMipMaps() {
-        fTextureProxy->setDoesNotSupportMipMaps();
-    }
-
 private:
     explicit GrTextureProxyPriv(GrTextureProxy* textureProxy) : fTextureProxy(textureProxy) {}
     GrTextureProxyPriv(const GrTextureProxyPriv&) {} // unimpl
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index e20d013..4f9b63f 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1338,12 +1338,15 @@
     bool disableR8TexStorageForANGLEGL = false;
     bool disableSRGBRenderWithMSAAForMacAMD = false;
     bool disableRGB8ForMali400 = false;
+    bool disableGrayLumFBOForMesa = false;
 
     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
         // ARB_texture_rg is part of OpenGL 3.0, but osmesa doesn't support GL_RED
         // and GL_RG on FBO textures.
         disableTextureRedForMesa = kOSMesa_GrGLRenderer == ctxInfo.renderer();
 
+        disableGrayLumFBOForMesa = kOSMesa_GrGLRenderer == ctxInfo.renderer();
+
         bool isX86PowerVR = false;
 #if defined(SK_CPU_X86)
         if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
@@ -1742,17 +1745,16 @@
     grayRedInfo.fSwizzle = GrSwizzle::RRRA();
     grayRedInfo.fFlags = ConfigInfo::kTextureable_Flag;
 
-#if 0 // Leaving Gray8 as non-renderable, to keep things simple and match raster. Needs to be
-      // updated to support Gray8_as_Lum and Gray8_as_red if this is ever enabled.
-    if (this->textureRedSupport() ||
-        (kDesktop_ARB_MSFBOType == this->msFBOType() &&
-         ctxInfo.renderer() != kOSMesa_GrGLRenderer)) {
+    // Leaving Gray8 as non-renderable, to keep things simple and match raster. However, we do
+    // enable the FBOColorAttachment_Flag so that we can bind it to an FBO for copies.
+    grayRedInfo.fFlags |= ConfigInfo::kFBOColorAttachment_Flag;;
+    if (kStandard_MSFBOType == this->msFBOType() && kGL_GrGLStandard == standard &&
+        !disableGrayLumFBOForMesa) {
         // desktop ARB extension/3.0+ supports LUMINANCE8 as renderable.
         // However, osmesa fails if it used even when GL_ARB_framebuffer_object is present.
         // Core profile removes LUMINANCE8 support, but we should have chosen R8 in that case.
-        fConfigTable[kGray_8_GrPixelConfig].fFlags |= allRenderFlags;
+        grayLumInfo.fFlags |= ConfigInfo::kFBOColorAttachment_Flag;;
     }
-#endif
     if (texStorageSupported && !isCommandBufferES2) {
         if (!disableR8TexStorageForANGLEGL) {
             grayLumInfo.fFlags |= ConfigInfo::kCanUseTexStorage_Flag;
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index e258eaa..1596dfd 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -123,8 +123,8 @@
         // In GL we have three ways to be able to copy. CopyTexImage, blit, and draw. CopyTexImage
         // requires the src to be an FBO attachment, blit requires both src and dst to be FBO
         // attachments, and draw requires the dst to be an FBO attachment. Thus to copy from and to
-        // the same config, we need that config to be renderable so we can attach it to an FBO.
-        return this->isConfigRenderable(config, false);
+        // the same config, we need that config to be bindable to an FBO.
+        return this->canConfigBeFBOColorAttachment(config);
     }
 
     bool canConfigBeFBOColorAttachment(GrPixelConfig config) const {
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 42a8992..f373564 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2858,6 +2858,8 @@
         return;
     }
 
+    SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes);
+
     // If the mips aren't dirty, we're done:
     if (!texture->texturePriv().mipMapsAreDirty()) {
         return;
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index e76f5bc..ec20e24 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -1046,10 +1046,16 @@
     desc.fHeight = random->nextULessThan(90) + 10;
     desc.fWidth = random->nextULessThan(90) + 10;
     auto origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin;
-    SkBackingFit fit = random->nextBool() ? SkBackingFit::kApprox : SkBackingFit::kExact;
+    GrMipMapped mipMapped = random->nextBool() ? GrMipMapped::kYes : GrMipMapped::kNo;
+    SkBackingFit fit = SkBackingFit::kExact;
+    if (mipMapped == GrMipMapped::kNo) {
+        fit = random->nextBool() ? SkBackingFit::kApprox : SkBackingFit::kExact;
+    }
 
     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, origin, fit, SkBudgeted::kNo);
+    sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, origin, mipMapped, fit,
+                                                             SkBudgeted::kNo,
+                                                             GrInternalSurfaceFlags::kNone);
 
     SkRect rect = GrTest::TestRect(random);
     SkRect srcRect;
@@ -1061,6 +1067,10 @@
     GrColor color = SkColorToPremulGrColor(random->nextU());
     GrSamplerState::Filter filter = (GrSamplerState::Filter)random->nextULessThan(
             static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
+    while (mipMapped == GrMipMapped::kNo && filter == GrSamplerState::Filter::kMipMap) {
+        filter = (GrSamplerState::Filter)random->nextULessThan(
+                static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
+    }
     auto csxf = GrTest::TestColorXform(random);
     GrAAType aaType = GrAAType::kNone;
     if (random->nextBool()) {
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index dde64f3..e28a532 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -620,6 +620,7 @@
 
         // Check if we need to regenerate any mip maps
         if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter()) {
+            SkASSERT(vkTexture->texturePriv().mipMapped() == GrMipMapped::kYes);
             if (vkTexture->texturePriv().mipMapsAreDirty()) {
                 gpu->generateMipmap(vkTexture, sampler.proxy()->origin());
                 vkTexture->texturePriv().markMipMapsClean();
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 4759f4e..01f0c1f 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -663,8 +663,7 @@
 static GrInternalSurfaceFlags get_flags_from_format(const GrBackendFormat& backendFormat) {
     if (const GrGLenum* target = backendFormat.getGLTarget()) {
         if (GR_GL_TEXTURE_RECTANGLE == *target || GR_GL_TEXTURE_EXTERNAL == *target) {
-            return GrInternalSurfaceFlags::kDoesNotSupportMipMaps |
-                   GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
+            return GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
         }
     }
 
@@ -706,6 +705,15 @@
         return nullptr;
     }
 
+    GrInternalSurfaceFlags formatFlags = get_flags_from_format(backendFormat);
+
+    if (mipMapped == GrMipMapped::kYes &&
+        SkToBool(formatFlags & GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal)) {
+        // It is invalid to have a GL_TEXTURE_EXTERNAL or GL_TEXTURE_RECTANGLE and have mips as
+        // well.
+        return nullptr;
+    }
+
     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
 
     GrSurfaceDesc desc;
@@ -716,16 +724,6 @@
     PromiseImageHelper promiseHelper(textureFulfillProc, textureReleaseProc, promiseDoneProc,
                                      textureContext);
 
-    GrInternalSurfaceFlags formatFlags = get_flags_from_format(backendFormat);
-
-    // Promise images always wrap resources. So if the promise image doesn't have mip maps, we
-    // cannot allocate mips for them and thus will need a copy to use a mipped image. We can't pass
-    // the fact that this creates a wrapped texture into createLazyProxy so we need to manually set
-    // in in the passed in flags.
-    if (GrMipMapped::kNo == mipMapped) {
-        formatFlags |= GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
-    }
-
     sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
             [promiseHelper, config] (GrResourceProvider* resourceProvider) mutable {
                 if (!resourceProvider) {
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index 19b324b..33e4307 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -866,10 +866,6 @@
             set_key_on_proxy(proxyProvider, mippedProxy.get(), proxy.get(), key);
             return mippedProxy;
         }
-        // We failed to make a mipped proxy with the base copied into it. This could have
-        // been from failure to make the proxy or failure to do the copy. Thus we will fall
-        // back to just using the non mipped proxy; See skbug.com/7094.
-        return proxy;
     }
 
     SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
diff --git a/tests/DeferredDisplayListTest.cpp b/tests/DeferredDisplayListTest.cpp
index 996e04f..697f003 100644
--- a/tests/DeferredDisplayListTest.cpp
+++ b/tests/DeferredDisplayListTest.cpp
@@ -846,26 +846,31 @@
     SkDeferredDisplayListRecorder recorder(characterization);
 
     for (GrGLenum target : { GR_GL_TEXTURE_EXTERNAL, GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_2D } ) {
-        GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, target);
+        for (auto mipMapped : { GrMipMapped::kNo, GrMipMapped::kYes }) {
+            GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, target);
 
-        sk_sp<SkImage> image = recorder.makePromiseTexture(format, 32, 32, GrMipMapped::kYes,
-                                                           kTopLeft_GrSurfaceOrigin,
-                                                           kRGBA_8888_SkColorType,
-                                                           kPremul_SkAlphaType, nullptr,
-                                                           dummy_fulfill_proc,
-                                                           dummy_release_proc,
-                                                           dummy_done_proc,
-                                                           nullptr);
-        REPORTER_ASSERT(reporter, image);
+            sk_sp<SkImage> image = recorder.makePromiseTexture(format, 32, 32, mipMapped,
+                                                               kTopLeft_GrSurfaceOrigin,
+                                                               kRGBA_8888_SkColorType,
+                                                               kPremul_SkAlphaType, nullptr,
+                                                               dummy_fulfill_proc,
+                                                               dummy_release_proc,
+                                                               dummy_done_proc,
+                                                               nullptr);
+            if (GR_GL_TEXTURE_2D != target && mipMapped == GrMipMapped::kYes) {
+                REPORTER_ASSERT(reporter, !image);
+                continue;
+            }
+            REPORTER_ASSERT(reporter, image);
 
-        GrTextureProxy* backingProxy = ((SkImage_Gpu*) image.get())->peekProxy();
+            GrTextureProxy* backingProxy = ((SkImage_Gpu*) image.get())->peekProxy();
 
-        if (GR_GL_TEXTURE_2D == target) {
-            REPORTER_ASSERT(reporter, !backingProxy->texPriv().doesNotSupportMipMaps());
-            REPORTER_ASSERT(reporter, !backingProxy->texPriv().isClampOnly());
-        } else {
-            REPORTER_ASSERT(reporter, backingProxy->texPriv().doesNotSupportMipMaps());
-            REPORTER_ASSERT(reporter, backingProxy->texPriv().isClampOnly());
+            REPORTER_ASSERT(reporter, backingProxy->mipMapped() == mipMapped);
+            if (GR_GL_TEXTURE_2D == target) {
+                REPORTER_ASSERT(reporter, !backingProxy->texPriv().isClampOnly());
+            } else {
+                REPORTER_ASSERT(reporter, backingProxy->texPriv().isClampOnly());
+            }
         }
     }
 }
diff --git a/tests/EGLImageTest.cpp b/tests/EGLImageTest.cpp
index f2c7371..94cbaf9 100644
--- a/tests/EGLImageTest.cpp
+++ b/tests/EGLImageTest.cpp
@@ -16,6 +16,7 @@
 #include "GrTest.h"
 #include "GrTexture.h"
 #include "GrTextureContext.h"
+#include "GrTexturePriv.h"
 #include "GrTextureProxyPriv.h"
 #include "gl/GLTestContext.h"
 #include "gl/GrGLGpu.h"
@@ -166,8 +167,9 @@
     }
 
     GrTextureProxy* proxy = surfaceContext->asTextureProxy();
-    REPORTER_ASSERT(reporter, proxy->texPriv().doesNotSupportMipMaps());
-    REPORTER_ASSERT(reporter, proxy->priv().peekTexture()->surfacePriv().doesNotSupportMipMaps());
+    REPORTER_ASSERT(reporter, proxy->mipMapped() == GrMipMapped::kNo);
+    REPORTER_ASSERT(reporter,
+                    proxy->priv().peekTexture()->texturePriv().mipMapped() == GrMipMapped::kNo);
 
     REPORTER_ASSERT(reporter, proxy->texPriv().isGLTextureRectangleOrExternal());
     REPORTER_ASSERT(reporter,
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 81fb21f..359527f 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -273,7 +273,8 @@
         dummyDesc.fHeight = 18;
         dummyDesc.fConfig = kRGBA_8888_GrPixelConfig;
         proxies[0] = proxyProvider->createProxy(dummyDesc, kBottomLeft_GrSurfaceOrigin,
-                                                SkBackingFit::kExact, SkBudgeted::kNo);
+                                                GrMipMapped::kYes, SkBackingFit::kExact,
+                                                SkBudgeted::kNo, GrInternalSurfaceFlags::kNone);
     }
     {
         GrSurfaceDesc dummyDesc;
@@ -282,7 +283,8 @@
         dummyDesc.fHeight = 22;
         dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
         proxies[1] = proxyProvider->createProxy(dummyDesc, kTopLeft_GrSurfaceOrigin,
-                                                SkBackingFit::kExact, SkBudgeted::kNo);
+                                                GrMipMapped::kYes, SkBackingFit::kExact,
+                                                SkBudgeted::kNo, GrInternalSurfaceFlags::kNone);
     }
 
     if (!proxies[0] || !proxies[1]) {
diff --git a/tests/GrTextureMipMapInvalidationTest.cpp b/tests/GrTextureMipMapInvalidationTest.cpp
index d832889..8da79c9 100644
--- a/tests/GrTextureMipMapInvalidationTest.cpp
+++ b/tests/GrTextureMipMapInvalidationTest.cpp
@@ -27,27 +27,31 @@
 
     GrContext* context = ctxInfo.grContext();
     auto info = SkImageInfo::MakeN32Premul(256, 256);
-    auto surf1 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info);
-    auto surf2 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info);
-    // Draw something just in case we ever had a solid color optimization
-    surf1->getCanvas()->drawCircle(128, 128, 50, SkPaint());
-    surf1->getCanvas()->flush();
+    for (auto allocateMips : {false, true}) {
+        auto surf1 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
+                                                 kBottomLeft_GrSurfaceOrigin, nullptr,
+                                                 allocateMips);
+        auto surf2 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info);
+        // Draw something just in case we ever had a solid color optimization
+        surf1->getCanvas()->drawCircle(128, 128, 50, SkPaint());
+        surf1->getCanvas()->flush();
 
-    // No mipmaps initially
-    REPORTER_ASSERT(reporter, !isMipped(surf1.get()));
+        // No mipmaps initially
+        REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
 
-    // Painting with downscale and medium filter quality should result in mipmap creation
-    SkPaint paint;
-    paint.setFilterQuality(kMedium_SkFilterQuality);
-    surf2->getCanvas()->scale(0.2f, 0.2f);
-    surf2->getCanvas()->drawImage(surf1->makeImageSnapshot(), 0, 0, &paint);
-    surf2->getCanvas()->flush();
-    REPORTER_ASSERT(reporter, isMipped(surf1.get()));
-    REPORTER_ASSERT(reporter, !mipsAreDirty(surf1.get()));
+        // Painting with downscale and medium filter quality should result in mipmap creation
+        SkPaint paint;
+        paint.setFilterQuality(kMedium_SkFilterQuality);
+        surf2->getCanvas()->scale(0.2f, 0.2f);
+        surf2->getCanvas()->drawImage(surf1->makeImageSnapshot(), 0, 0, &paint);
+        surf2->getCanvas()->flush();
+        REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
+        REPORTER_ASSERT(reporter, !allocateMips || !mipsAreDirty(surf1.get()));
 
-    // Changing the contents of the surface should invalidate the mipmap, but not de-allocate
-    surf1->getCanvas()->drawCircle(128, 128, 100, SkPaint());
-    surf1->getCanvas()->flush();
-    REPORTER_ASSERT(reporter, isMipped(surf1.get()));
-    REPORTER_ASSERT(reporter, mipsAreDirty(surf1.get()));
+        // Changing the contents of the surface should invalidate the mipmap, but not de-allocate
+        surf1->getCanvas()->drawCircle(128, 128, 100, SkPaint());
+        surf1->getCanvas()->flush();
+        REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
+        REPORTER_ASSERT(reporter, mipsAreDirty(surf1.get()));
+    }
 }
diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp
index 901cd29..536ef36 100644
--- a/tests/LazyProxyTest.cpp
+++ b/tests/LazyProxyTest.cpp
@@ -443,10 +443,6 @@
 
         REPORTER_ASSERT(reporter, lazyProxy.get());
 
-        // We can't pass the fact that this creates a wrapped texture into createLazyProxy so we
-        // need to manually call setDoesNotSupportMipMaps.
-        lazyProxy->texPriv().setDoesNotSupportMipMaps();
-
         rtc->priv().testingOnly_addDrawOp(LazyUninstantiateTestOp::Make(ctx.get(), lazyProxy));
 
         ctx->flush();
diff --git a/tests/RectangleTextureTest.cpp b/tests/RectangleTextureTest.cpp
index 3516acf..90b723a 100644
--- a/tests/RectangleTextureTest.cpp
+++ b/tests/RectangleTextureTest.cpp
@@ -15,6 +15,7 @@
 #include "GrRenderTargetContext.h"
 #include "GrSurfacePriv.h"
 #include "GrTest.h"
+#include "GrTexturePriv.h"
 #include "GrTextureProxyPriv.h"
 #include "gl/GLTestContext.h"
 #include "gl/GrGLGpu.h"
@@ -136,8 +137,8 @@
             continue;
         }
 
-        SkASSERT(rectProxy->texPriv().doesNotSupportMipMaps());
-        SkASSERT(rectProxy->priv().peekTexture()->surfacePriv().doesNotSupportMipMaps());
+        SkASSERT(rectProxy->mipMapped() == GrMipMapped::kNo);
+        SkASSERT(rectProxy->priv().peekTexture()->texturePriv().mipMapped() == GrMipMapped::kNo);
 
         SkASSERT(rectProxy->texPriv().isGLTextureRectangleOrExternal());
         SkASSERT(rectProxy->priv().peekTexture()->surfacePriv().isGLTextureRectangleOrExternal());