Add support for SkImageGenerator creating external textures

Copy the SkImageGenerator texture if tiling is needed and
original texture target is GR_GL_TEXTURE_EXTERNAL.

Bug: skia:
Change-Id: I98f5acc3883e2060b1a35f80633b02b08a706107
Reviewed-on: https://skia-review.googlesource.com/18268
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Stan Iliev <stani@google.com>
diff --git a/src/gpu/GrAHardwareBufferImageGenerator.h b/src/gpu/GrAHardwareBufferImageGenerator.h
index 4a5004b..521fc7c 100644
--- a/src/gpu/GrAHardwareBufferImageGenerator.h
+++ b/src/gpu/GrAHardwareBufferImageGenerator.h
@@ -34,7 +34,7 @@
     bool onIsValid(GrContext*) const override;
 
 #if SK_SUPPORT_GPU
-    bool onCanGenerateTexture() const override { return true; }
+    TexGenType onCanGenerateTexture() const override { return TexGenType::kCheap; }
     sk_sp<GrTextureProxy> onGenerateTexture(GrContext*, const SkImageInfo&,
                                             const SkIPoint&) override;
 #endif
diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp
index 02f172b..3a3cd31 100644
--- a/src/gpu/GrBackendTextureImageGenerator.cpp
+++ b/src/gpu/GrBackendTextureImageGenerator.cpp
@@ -102,9 +102,8 @@
     refHelper->unref();
 }
 
-sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(GrContext* context,
-                                                                        const SkImageInfo& info,
-                                                                        const SkIPoint& origin) {
+sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
+        GrContext* context, const SkImageInfo& info, const SkIPoint& origin) {
     SkASSERT(context);
 
     if (context->contextPriv().getBackend() != fBackendTexture.backend()) {
diff --git a/src/gpu/GrBackendTextureImageGenerator.h b/src/gpu/GrBackendTextureImageGenerator.h
index 2ada687..675c553 100644
--- a/src/gpu/GrBackendTextureImageGenerator.h
+++ b/src/gpu/GrBackendTextureImageGenerator.h
@@ -27,7 +27,7 @@
     bool onIsValid(GrContext*) const override { return true; }
 
 #if SK_SUPPORT_GPU
-    bool onCanGenerateTexture() const override { return true; }
+    TexGenType onCanGenerateTexture() const override { return TexGenType::kCheap; }
     sk_sp<GrTextureProxy> onGenerateTexture(GrContext*, const SkImageInfo&,
                                             const SkIPoint&) override;
 #endif
diff --git a/src/gpu/GrBitmapTextureMaker.cpp b/src/gpu/GrBitmapTextureMaker.cpp
index bde8276..762b72c 100644
--- a/src/gpu/GrBitmapTextureMaker.cpp
+++ b/src/gpu/GrBitmapTextureMaker.cpp
@@ -28,7 +28,12 @@
 }
 
 sk_sp<GrTextureProxy> GrBitmapTextureMaker::refOriginalTextureProxy(bool willBeMipped,
-                                                                    SkColorSpace* dstColorSpace) {
+                                                                    SkColorSpace* dstColorSpace,
+                                                                    AllowedTexGenType onlyIfFast) {
+    if (AllowedTexGenType::kCheap == onlyIfFast) {
+        return nullptr;
+    }
+
     sk_sp<GrTextureProxy> proxy;
 
     if (fOriginalKey.isValid()) {
diff --git a/src/gpu/GrBitmapTextureMaker.h b/src/gpu/GrBitmapTextureMaker.h
index c706962..419649c 100644
--- a/src/gpu/GrBitmapTextureMaker.h
+++ b/src/gpu/GrBitmapTextureMaker.h
@@ -19,7 +19,8 @@
 
 protected:
     sk_sp<GrTextureProxy> refOriginalTextureProxy(bool willBeMipped,
-                                                  SkColorSpace* dstColorSpace) override;
+                                                  SkColorSpace* dstColorSpace,
+                                                  AllowedTexGenType onlyIfFast) override;
 
     void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey,
                      SkColorSpace* dstColorSpace) override;
diff --git a/src/gpu/GrImageTextureMaker.cpp b/src/gpu/GrImageTextureMaker.cpp
index bbdc9c1..5bf81d2 100644
--- a/src/gpu/GrImageTextureMaker.cpp
+++ b/src/gpu/GrImageTextureMaker.cpp
@@ -26,9 +26,10 @@
 }
 
 sk_sp<GrTextureProxy> GrImageTextureMaker::refOriginalTextureProxy(bool willBeMipped,
-                                                                   SkColorSpace* dstColorSpace) {
+                                                                   SkColorSpace* dstColorSpace,
+                                                                   AllowedTexGenType onlyIfFast) {
     return fCacher->lockTextureProxy(this->context(), fOriginalKey, fCachingHint,
-                                     willBeMipped, dstColorSpace);
+                                     willBeMipped, dstColorSpace, onlyIfFast);
 }
 
 void GrImageTextureMaker::makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey,
diff --git a/src/gpu/GrImageTextureMaker.h b/src/gpu/GrImageTextureMaker.h
index 4f3e8bd..1a72f68 100644
--- a/src/gpu/GrImageTextureMaker.h
+++ b/src/gpu/GrImageTextureMaker.h
@@ -24,7 +24,8 @@
     //       able to efficiently produce a "stretched" texture natively (e.g. picture-backed)
     //          GrTexture* generateTextureForParams(const CopyParams&) override;
     sk_sp<GrTextureProxy> refOriginalTextureProxy(bool willBeMipped,
-                                                  SkColorSpace* dstColorSpace) override;
+                                                  SkColorSpace* dstColorSpace,
+                                                  AllowedTexGenType onlyIfFast) override;
 
     void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey,
                      SkColorSpace* dstColorSpace) override;
diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp
index 4fb0c0d..69e3a6e 100644
--- a/src/gpu/GrTextureMaker.cpp
+++ b/src/gpu/GrTextureMaker.cpp
@@ -26,10 +26,21 @@
         *texColorSpace = this->getColorSpace(dstColorSpace);
     }
 
-    if (!fContext->getGpu()->isACopyNeededForTextureParams(this->width(), this->height(), params,
-                                                           &copyParams, scaleAdjust)) {
-        return this->refOriginalTextureProxy(willBeMipped, dstColorSpace);
+    sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
+                                                                 AllowedTexGenType::kCheap));
+    if (original) {
+        if (!fContext->getGpu()->isACopyNeededForTextureParams(original.get(), params, &copyParams,
+                                                               scaleAdjust)) {
+            return original;
+        }
+    } else {
+        if (!fContext->getGpu()->isACopyNeededForTextureParams(this->width(), this->height(),
+                                                               params, &copyParams, scaleAdjust)) {
+            return this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
+                                                 AllowedTexGenType::kAny);
+        }
     }
+
     GrUniqueKey copyKey;
     this->makeCopyKey(copyParams, &copyKey, dstColorSpace);
     if (copyKey.isValid()) {
@@ -39,8 +50,13 @@
         }
     }
 
-    sk_sp<GrTextureProxy> result(this->generateTextureProxyForParams(copyParams, willBeMipped,
-                                                                     dstColorSpace));
+    sk_sp<GrTextureProxy> result;
+    if (original) {
+        result = CopyOnGpu(fContext, std::move(original), nullptr, copyParams);
+    } else {
+        result = this->generateTextureProxyForParams(copyParams, willBeMipped, dstColorSpace);
+    }
+
     if (!result) {
         return nullptr;
     }
@@ -106,7 +122,8 @@
 sk_sp<GrTextureProxy> GrTextureMaker::generateTextureProxyForParams(const CopyParams& copyParams,
                                                                     bool willBeMipped,
                                                                     SkColorSpace* dstColorSpace) {
-    sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace));
+    sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
+                                                                 AllowedTexGenType::kAny));
     if (!original) {
         return nullptr;
     }
diff --git a/src/gpu/GrTextureMaker.h b/src/gpu/GrTextureMaker.h
index 909d348..9e1e0dd 100644
--- a/src/gpu/GrTextureMaker.h
+++ b/src/gpu/GrTextureMaker.h
@@ -16,6 +16,8 @@
  */
 class GrTextureMaker : public GrTextureProducer {
 public:
+    enum class AllowedTexGenType : bool { kCheap, kAny };
+
     /**
      *  Returns a texture that is safe for use with the params. If the size of the returned texture
      *  does not match width()/height() then the contents of the original must be scaled to fit
@@ -44,9 +46,13 @@
     /**
      *  Return the maker's "original" texture. It is the responsibility of the maker to handle any
      *  caching of the original if desired.
+     *  If "genType" argument equals AllowedTexGenType::kCheap and the texture is not trivial to
+     *  construct then refOriginalTextureProxy should return nullptr (for example if texture is made
+     *  by drawing into a render target).
      */
     virtual sk_sp<GrTextureProxy> refOriginalTextureProxy(bool willBeMipped,
-                                                          SkColorSpace* dstColorSpace) = 0;
+                                                          SkColorSpace* dstColorSpace,
+                                                          AllowedTexGenType genType) = 0;
 
     /**
      *  Returns the color space of the maker's "original" texture, assuming it was retrieved with