Fall back to non mipped Texture when we can't copy base to mipped texture

TBR: bsalomon@google.com
Bug: skia:7094
Change-Id: I9d2ba78c4d4332a22e2357cde0598de51299067d
Reviewed-on: https://skia-review.googlesource.com/53541
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h
index 14673e9..817d715 100644
--- a/include/gpu/GrCaps.h
+++ b/include/gpu/GrCaps.h
@@ -145,6 +145,8 @@
 
     virtual bool isConfigTexturable(GrPixelConfig) const = 0;
     virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0;
+    // Returns whether a texture of the given config can be copied to a texture of the same config.
+    virtual bool isConfigCopyable(GrPixelConfig config) const = 0;
     virtual bool canConfigBeImageStorage(GrPixelConfig config) const = 0;
 
     bool suppressPrints() const { return fSuppressPrints; }
diff --git a/src/gpu/GrBitmapTextureMaker.cpp b/src/gpu/GrBitmapTextureMaker.cpp
index 00dd48d..ab8ee24 100644
--- a/src/gpu/GrBitmapTextureMaker.cpp
+++ b/src/gpu/GrBitmapTextureMaker.cpp
@@ -55,6 +55,12 @@
         } else {
             proxy = GrCopyBaseMipMapToTextureProxy(this->context(), originalProxy.get(),
                                                    dstColorSpace);
+            if (!proxy) {
+                // 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 originalProxy;
+            }
         }
     }
     if (!proxy) {
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index e26de49..8035027 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -223,6 +223,10 @@
                                                      SkColorSpace* dstColorSpace) {
     SkASSERT(baseProxy);
 
+    if (!ctx->caps()->isConfigCopyable(baseProxy->config())) {
+        return nullptr;
+    }
+
     SkDestinationSurfaceColorMode colorMode = dstColorSpace
         ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
         : SkDestinationSurfaceColorMode::kLegacy;
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 1ce6094..68cbc9b 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -125,6 +125,15 @@
             return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag);
         }
     }
+
+    bool isConfigCopyable(GrPixelConfig config) const override {
+        // 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);
+    }
+
     bool canConfigBeImageStorage(GrPixelConfig config) const override {
         return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseAsImageStorage_Flag);
     }
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index b1d9a84..90cc824 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -31,6 +31,10 @@
     bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
         return fOptions.fConfigOptions[config].fRenderable[withMSAA];
     }
+    bool isConfigCopyable(GrPixelConfig config) const override {
+        return false;
+    }
+
     bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
     bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
                             bool* rectsMustMatch, bool* disallowSubrect) const override {
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index 9590bb9..b793159 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -39,6 +39,10 @@
         }
     }
 
+    bool isConfigCopyable(GrPixelConfig config) const override {
+        return true;
+    }
+
     bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
 
 #if 0
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 0161bf7..ad51495 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -39,6 +39,10 @@
         return SkToBool(ConfigInfo::kRenderable_Flag & fConfigTable[config].fOptimalFlags);
     }
 
+    bool isConfigCopyable(GrPixelConfig config) const override {
+        return true;
+    }
+
     bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
 
     bool isConfigTexturableLinearly(GrPixelConfig config) const {