Revert of Remove gpu-specialization of SkSpecialImage (patchset #5 id:80001 of https://codereview.chromium.org/1918993002/ )

Reason for revert:
N6 bot has gone red

Original issue's description:
> Remove gpu-specialization of SkSpecialImage
>
> GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1918993002
>
> Committed: https://skia.googlesource.com/skia/+/0533d6e4142c2787d6d3c325ef0d8d1962292cad

TBR=reed@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/1921393003
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index fc6cffe..f18e6a7 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -218,18 +218,7 @@
     }
 
     bool onGetROPixels(SkBitmap* bm) const override {
-        SkBitmap tmp;
-
-        if (!as_IB(fImage)->getROPixels(&tmp)) {
-            return false;
-        }
-
-        if (this->subset().contains(tmp.bounds())) {
-            *bm = tmp;
-            return true;
-        }
-
-        return tmp.extractSubset(bm, this->subset());
+        return as_IB(fImage)->getROPixels(bm);
     }
 
     GrTexture* onPeekTexture() const override { return as_IB(fImage)->peekTexture(); }
@@ -273,7 +262,14 @@
     }
 
     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
-        return SkSpecialImage::MakeFromImage(subset, fImage, &this->props());
+        sk_sp<SkImage> subsetImg(fImage->makeSubset(subset));
+        if (!subsetImg) {
+            return nullptr;
+        }
+
+        return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(subset.width(), subset.height()),
+                                             subsetImg,
+                                             &this->props());
     }
 
     sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
@@ -442,20 +438,153 @@
 
 #if SK_SUPPORT_GPU
 ///////////////////////////////////////////////////////////////////////////////
-
+#include "GrTexture.h"
 #include "SkImage_Gpu.h"
 
+class SkSpecialImage_Gpu : public SkSpecialImage_Base {
+public:
+    SkSpecialImage_Gpu(const SkIRect& subset,
+                       uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
+                       const SkSurfaceProps* props)
+        : INHERITED(subset, uniqueID, props)
+        , fTexture(std::move(tex))
+        , fAlphaType(at)
+        , fAddedRasterVersionToCache(false) {
+    }
+
+    ~SkSpecialImage_Gpu() override {
+        if (fAddedRasterVersionToCache.load()) {
+            SkNotifyBitmapGenIDIsStale(this->uniqueID());
+        }
+    }
+
+    bool isOpaque() const override {
+        return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
+    }
+
+    size_t getSize() const override { return fTexture->gpuMemorySize(); }
+
+    void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
+        SkRect dst = SkRect::MakeXYWH(x, y,
+                                      this->subset().width(), this->subset().height());
+
+        SkBitmap bm;
+
+        GrWrapTextureInBitmap(fTexture.get(),
+                              fTexture->width(), fTexture->height(), this->isOpaque(), &bm);
+
+        canvas->drawBitmapRect(bm, this->subset(),
+                               dst, paint, SkCanvas::kStrict_SrcRectConstraint);
+    }
+
+    GrTexture* onPeekTexture() const override { return fTexture.get(); }
+
+    sk_sp<GrTexture> onAsTextureRef(GrContext*) const override { return fTexture; }
+
+    bool onGetROPixels(SkBitmap* dst) const override {
+        if (SkBitmapCache::Find(this->uniqueID(), dst)) {
+            SkASSERT(dst->getGenerationID() == this->uniqueID());
+            SkASSERT(dst->isImmutable());
+            SkASSERT(dst->getPixels());
+            return true;
+        }
+
+        SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
+                                                this->isOpaque() ? kOpaque_SkAlphaType
+                                                                 : kPremul_SkAlphaType);
+
+        if (!dst->tryAllocPixels(info)) {
+            return false;
+        }
+
+        if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
+                                  dst->getPixels(), dst->rowBytes())) {
+            return false;
+        }
+
+        dst->pixelRef()->setImmutableWithID(this->uniqueID());
+        SkBitmapCache::Add(this->uniqueID(), *dst);
+        fAddedRasterVersionToCache.store(true);
+        return true;
+    }
+
+    bool getBitmapDeprecated(SkBitmap* result) const override {
+        const SkImageInfo info = GrMakeInfoFromTexture(fTexture.get(),
+                                                       this->width(), this->height(),
+                                                       this->isOpaque());
+        if (!result->setInfo(info)) {
+            return false;
+        }
+
+        const SkImageInfo prInfo = info.makeWH(fTexture->width(), fTexture->height());
+
+        SkAutoTUnref<SkGrPixelRef> pixelRef(new SkGrPixelRef(prInfo, fTexture.get()));
+        result->setPixelRef(pixelRef, this->subset().fLeft, this->subset().fTop);
+        return true;
+    }
+
+    sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override {
+        if (!fTexture->getContext()) {
+            return nullptr;
+        }
+
+        GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info, *fTexture->getContext()->caps());
+        desc.fFlags = kRenderTarget_GrSurfaceFlag;
+
+        return SkSpecialSurface::MakeRenderTarget(fTexture->getContext(), desc);
+    }
+
+    sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
+        return SkSpecialImage::MakeFromGpu(subset,
+                                           this->uniqueID(),
+                                           fTexture,
+                                           &this->props(),
+                                           fAlphaType);
+    }
+
+    sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
+        if (0 == subset.fLeft && 0 == subset.fTop &&
+            fTexture->width() == subset.width() &&
+            fTexture->height() == subset.height()) {
+            // The existing GrTexture is already tight so reuse it in the SkImage
+            return sk_make_sp<SkImage_Gpu>(fTexture->width(), fTexture->height(),
+                                           kNeedNewImageUniqueID,
+                                           fAlphaType, fTexture.get(), SkBudgeted::kYes);
+        }
+
+        GrContext* ctx = fTexture->getContext();
+        GrSurfaceDesc desc = fTexture->desc();
+        desc.fWidth = subset.width();
+        desc.fHeight = subset.height();
+
+        sk_sp<GrTexture> subTx(ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes));
+        if (!subTx) {
+            return nullptr;
+        }
+        ctx->copySurface(subTx.get(), fTexture.get(), subset, SkIPoint::Make(0, 0));
+        return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
+                                       fAlphaType, subTx.get(), SkBudgeted::kYes);
+    }
+
+    sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override {
+        return SkSurface::MakeRenderTarget(fTexture->getContext(), SkBudgeted::kYes, info);
+    }
+
+private:
+    sk_sp<GrTexture>        fTexture;
+    const SkAlphaType       fAlphaType;
+    mutable SkAtomic<bool>  fAddedRasterVersionToCache;
+
+    typedef SkSpecialImage_Base INHERITED;
+};
+
 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
                                                   uint32_t uniqueID,
                                                   sk_sp<GrTexture> tex,
                                                   const SkSurfaceProps* props,
                                                   SkAlphaType at) {
     SkASSERT(rect_fits(subset, tex->width(), tex->height()));
-
-    sk_sp<SkImage> image(new SkImage_Gpu(tex->width(), tex->height(),
-                                         uniqueID, at,
-                                         tex.get(), SkBudgeted::kYes));
-    return sk_make_sp<SkSpecialImage_Image>(subset, std::move(image), props);
+    return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at, props);
 }
 
 #endif