Add a deferred copy surface (take 3)

This CL forces all GrSurface copies to go through a GrSurfaceContext (rather than GrContext).

There is a bit of goofiness going on here until read/writePixels is also consolidated in GrSurfaceContext and a proxy-backed SkImage/SkSurface is added.

This is a reland of https://skia-review.googlesource.com/c/5773/ (Add a deferred copy surface)

Change-Id: Ib8fd96d0569274ef781366eb900ed8ee839ae9bd
Reviewed-on: https://skia-review.googlesource.com/6109
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 2567bf1..4f48f78 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -17,6 +17,7 @@
 
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
+#include "GrSurfaceContext.h"
 #include "GrTexture.h"
 #include "GrSamplerParams.h"
 #include "GrTextureProxy.h"
@@ -346,6 +347,20 @@
 #include "GrTexture.h"
 #include "SkImage_Gpu.h"
 
+static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, GrSurfaceProxy* proxy,
+                                          SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
+    // TODO: add GrTextureProxy-backed SkImage_Gpus
+    GrSurface* surf = proxy->instantiate(context->textureProvider());
+    if (!surf) {
+        return nullptr;
+    }
+
+    return sk_make_sp<SkImage_Gpu>(proxy->width(), proxy->height(),
+                                   kNeedNewImageUniqueID, alphaType,
+                                   sk_ref_sp(surf->asTexture()),
+                                   std::move(colorSpace), SkBudgeted::kYes);
+}
+
 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
 public:
     SkSpecialImage_Gpu(const SkIRect& subset,
@@ -478,34 +493,21 @@
                                                    fAlphaType);
     }
 
+    // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
     sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
-        // TODO: add GrTextureProxy-backed SkImage_Gpus
-        GrSurface* surf = fSurfaceProxy->instantiate(fContext->textureProvider());
-        if (!surf) {
-            return nullptr;
-        }
-
+        // TODO: this is problematic since the surfaceProxy could be loose
         if (0 == subset.fLeft && 0 == subset.fTop &&
             fSurfaceProxy->width() == subset.width() &&
             fSurfaceProxy->height() == subset.height()) {
             // The existing GrTexture is already tight so reuse it in the SkImage
-            return sk_make_sp<SkImage_Gpu>(surf->width(), surf->height(),
-                                           kNeedNewImageUniqueID, fAlphaType,
-                                           sk_ref_sp(surf->asTexture()),
-                                           fColorSpace, SkBudgeted::kYes);
+            return wrap_proxy_in_image(fContext, fSurfaceProxy.get(),
+                                       fAlphaType, fColorSpace);
         }
 
-        GrSurfaceDesc desc = fSurfaceProxy->desc();
-        desc.fWidth = subset.width();
-        desc.fHeight = subset.height();
+        sk_sp<GrSurfaceProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fSurfaceProxy.get(),
+                                                               subset, SkBudgeted::kYes));
 
-        sk_sp<GrTexture> subTx(fContext->textureProvider()->createTexture(desc, SkBudgeted::kYes));
-        if (!subTx) {
-            return nullptr;
-        }
-        fContext->copySurface(subTx.get(), surf, subset, SkIPoint::Make(0, 0));
-        return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
-                                       fAlphaType, std::move(subTx), fColorSpace, SkBudgeted::kYes);
+        return wrap_proxy_in_image(fContext, subsetProxy.get(), fAlphaType, fColorSpace);
     }
 
     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,