Added GrSurfaceContext and GrTextureContext

This lets copy-to-texture to be treated like copy-to-rt.
To match current behavior, though, copies to texture are
still executed immediately (forcing a flush).

Once MDB is enabled, copies to texture will be deferred.

BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5093

Change-Id: Icc0ce5435507a5f0a237c22eedef879824952367
Reviewed-on: https://skia-review.googlesource.com/5093
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index a705ed6..1779f7f 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -31,7 +31,9 @@
   "$_include/gpu/GrResourceKey.h",
   "$_include/gpu/GrShaderVar.h",
   "$_include/gpu/GrSurface.h",
+  "$_include/gpu/GrSurfaceContext.h",
   "$_include/gpu/GrTexture.h",
+  "$_include/gpu/GrTextureContext.h",
   "$_include/gpu/GrSamplerParams.h",
   "$_include/gpu/GrTextureProvider.h",
   "$_include/gpu/GrTestUtils.h",
@@ -192,9 +194,11 @@
   "$_src/gpu/GrSoftwarePathRenderer.h",
   "$_src/gpu/GrSurfacePriv.h",
   "$_src/gpu/GrSurface.cpp",
+  "$_src/gpu/GrSurfaceContext.cpp",
   "$_src/gpu/GrSurfaceProxy.cpp",
   "$_src/gpu/GrSwizzle.h",
   "$_src/gpu/GrTexture.cpp",
+  "$_src/gpu/GrTextureContext.cpp",
   "$_src/gpu/GrTextureParamsAdjuster.h",
   "$_src/gpu/GrTextureParamsAdjuster.cpp",
   "$_src/gpu/GrTexturePriv.h",
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
index dcbe8ea..2d4eaf7 100644
--- a/include/gpu/GrRenderTarget.h
+++ b/include/gpu/GrRenderTarget.h
@@ -115,10 +115,6 @@
     GrRenderTargetPriv renderTargetPriv();
     const GrRenderTargetPriv renderTargetPriv() const;
 
-    GrRenderTargetOpList* getLastRenderTargetOpList() {
-        return (GrRenderTargetOpList*) this->getLastOpList();
-    }
-
 protected:
     enum class Flags {
         kNone                = 0,
diff --git a/include/gpu/GrRenderTargetContext.h b/include/gpu/GrRenderTargetContext.h
index 6ed321c..20ca59f 100644
--- a/include/gpu/GrRenderTargetContext.h
+++ b/include/gpu/GrRenderTargetContext.h
@@ -11,25 +11,19 @@
 #include "GrColor.h"
 #include "GrContext.h"
 #include "GrPaint.h"
-#include "GrRenderTarget.h"
+#include "GrSurfaceContext.h"
 #include "SkRefCnt.h"
-#include "SkRegion.h"
 #include "SkSurfaceProps.h"
 #include "../private/GrInstancedPipelineInfo.h"
 #include "../private/GrRenderTargetProxy.h"
-#include "../private/GrSingleOwner.h"
 
-class GrAuditTrail;
 class GrClip;
 class GrDrawBatch;
-class GrRenderTargetContextPriv;
-class GrDrawPathBatchBase;
 class GrDrawingManager;
 class GrFixedClip;
-class GrPaint;
-class GrPathProcessor;
 class GrPipelineBuilder;
 class GrRenderTarget;
+class GrRenderTargetContextPriv;
 class GrRenderTargetOpList;
 class GrStyle;
 class GrSurface;
@@ -44,18 +38,19 @@
 class SkPath;
 struct SkPoint;
 struct SkRect;
+class SkRegion;
 class SkRRect;
 struct SkRSXform;
 class SkTextBlob;
 
-/*
- * A helper object to orchestrate draws
+/**
+ * A helper object to orchestrate commands (draws, etc...) for GrSurfaces that are GrRenderTargets.
  */
-class SK_API GrRenderTargetContext : public SkRefCnt {
+class SK_API GrRenderTargetContext : public GrSurfaceContext {
 public:
     ~GrRenderTargetContext() override;
 
-    bool copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint);
+    bool copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
 
     // TODO: it is odd that we need both the SkPaint in the following 3 methods.
     // We should extract the text parameters from SkPaint and pass them separately
@@ -385,8 +380,6 @@
     GrRenderTargetContextPriv priv();
     const GrRenderTargetContextPriv priv() const;
 
-    GrAuditTrail* auditTrail() { return fAuditTrail; }
-
     bool isWrapped_ForTesting() const;
 
 protected:
@@ -396,7 +389,6 @@
 
     GrDrawingManager* drawingManager() { return fDrawingManager; }
 
-    SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; })
     SkDEBUGCODE(void validate() const;)
 
 private:
@@ -462,16 +454,11 @@
     // In MDB-mode the GrOpList can be closed by some other renderTargetContext that has picked
     // it up. For this reason, the GrOpList should only ever be accessed via 'getOpList'.
     GrRenderTargetOpList*             fOpList;
-    GrContext*                        fContext;
     GrInstancedPipelineInfo           fInstancedPipelineInfo;
 
     sk_sp<SkColorSpace>               fColorSpace;
     sk_sp<GrColorSpaceXform>          fColorXformFromSRGB;
     SkSurfaceProps                    fSurfaceProps;
-    GrAuditTrail*                     fAuditTrail;
-
-    // In debug builds we guard against improper thread handling
-    SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;)
 };
 
 #endif
diff --git a/include/gpu/GrSurfaceContext.h b/include/gpu/GrSurfaceContext.h
new file mode 100644
index 0000000..a05d37f
--- /dev/null
+++ b/include/gpu/GrSurfaceContext.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrSurfaceContext_DEFINED
+#define GrSurfaceContext_DEFINED
+
+#include "SkRefCnt.h"
+
+class GrAuditTrail;
+class GrContext;
+class GrSingleOwner;
+class GrSurface;
+struct SkIPoint;
+struct SkIRect;
+
+/**
+ * A helper object to orchestrate commands for a particular surface
+ */
+class SK_API GrSurfaceContext : public SkRefCnt {
+public:
+    ~GrSurfaceContext() override {}
+
+    virtual bool copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) = 0;
+
+    GrAuditTrail* auditTrail() { return fAuditTrail; }
+
+protected:
+    GrSurfaceContext(GrContext*, GrAuditTrail*, GrSingleOwner*);
+
+    SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; })
+
+    GrContext*            fContext;
+    GrAuditTrail*         fAuditTrail;
+
+    // In debug builds we guard against improper thread handling
+    SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;)
+};
+
+#endif
diff --git a/include/gpu/GrTextureContext.h b/include/gpu/GrTextureContext.h
new file mode 100644
index 0000000..da71c07
--- /dev/null
+++ b/include/gpu/GrTextureContext.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureContext_DEFINED
+#define GrTextureContext_DEFINED
+
+#include "GrSurfaceContext.h"
+#include "../private/GrTextureProxy.h"
+
+class GrContext;
+class GrDrawingManager;
+class GrSurface;
+class GrTextureOpList;
+class GrTextureProxy;
+struct SkIPoint;
+struct SkIRect;
+
+/**
+ * A helper object to orchestrate commands (currently just copies) for GrSurfaces that are
+ * GrTextures and not GrRenderTargets.
+ */
+class SK_API GrTextureContext : public GrSurfaceContext {
+public:
+    ~GrTextureContext() override;
+
+    bool copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
+
+protected:
+    GrTextureContext(GrContext*, GrDrawingManager*, sk_sp<GrTextureProxy>, GrAuditTrail*,
+                     GrSingleOwner*);
+
+    GrDrawingManager* drawingManager() { return fDrawingManager; }
+
+    SkDEBUGCODE(void validate() const;)
+
+private:
+    friend class GrDrawingManager; // for ctor
+
+    GrTextureOpList* getOpList();
+
+    GrDrawingManager*            fDrawingManager;
+    sk_sp<GrTextureProxy>        fTextureProxy;
+
+    // In MDB-mode the GrOpList can be closed by some other renderTargetContext that has picked
+    // it up. For this reason, the GrOpList should only ever be accessed via 'getOpList'.
+    GrTextureOpList*             fOpList;
+};
+
+#endif
diff --git a/include/private/GrRenderTargetProxy.h b/include/private/GrRenderTargetProxy.h
index bfc6e05..83107da 100644
--- a/include/private/GrRenderTargetProxy.h
+++ b/include/private/GrRenderTargetProxy.h
@@ -53,12 +53,6 @@
 
     GrRenderTarget::Flags testingOnly_getFlags() const;
 
-    GrRenderTargetOpList* getLastRenderTargetOpList() {
-        return (GrRenderTargetOpList*) this->getLastOpList();
-    }
-
-    SkDEBUGCODE(void validate(GrContext*) const;)
-
 protected:
     friend class GrSurfaceProxy;  // for ctors
 
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index 1ff6df8..61dc9e1 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -13,11 +13,11 @@
 #include "SkRect.h"
 
 class GrCaps;
-class GrOpList;
+class GrRenderTargetOpList;
+class GrRenderTargetProxy;
+class GrTextureOpList;
 class GrTextureProvider;
 class GrTextureProxy;
-class GrRenderTargetProxy;
-class GrTextureProvider;
 
 // This class replicates the functionality GrIORef<GrSurface> but tracks the
 // utilitization for later resource allocation (for the deferred case) and
@@ -244,6 +244,9 @@
     void setLastOpList(GrOpList* opList);
     GrOpList* getLastOpList() { return fLastOpList; }
 
+    GrRenderTargetOpList* getLastRenderTargetOpList();
+    GrTextureOpList* getLastTextureOpList();
+
     /**
      * Retrieves the amount of GPU memory that will be or currently is used by this resource 
      * in bytes. It is approximate since we aren't aware of additional padding or copies made
@@ -261,6 +264,8 @@
 
     bool isWrapped_ForTesting() const;
 
+    SkDEBUGCODE(void validate(GrContext*) const;)
+
 protected:
     // Deferred version
     GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted)
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index a206e76..5eb3066 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -12,6 +12,7 @@
 #include "GrTexture.h"
 
 class GrCaps;
+class GrTextureOpList;
 class GrTextureProvider;
 
 // This class delays the acquisition of textures until they are actually required
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 1a5ee20..7b789bd 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -14,7 +14,9 @@
 #include "GrResourceProvider.h"
 #include "GrRenderTargetProxy.h"
 #include "GrSoftwarePathRenderer.h"
+#include "GrSurfaceContext.h"
 #include "GrSurfacePriv.h"
+#include "GrTextureContext.h"
 
 #include "SkConfig8888.h"
 #include "SkGrPriv.h"
@@ -557,31 +559,23 @@
         return false;
     }
 
-    if (!dst->asRenderTarget()) {
-        SkIRect clippedSrcRect;
-        SkIPoint clippedDstPoint;
-        if (!GrCopySurfaceBatch::ClipSrcRectAndDstPoint(dst, src, srcRect, dstPoint,
-                                                        &clippedSrcRect, &clippedDstPoint)) {
-            return false;
-        }
-        // If we don't have an RT for the dst then we won't have a GrRenderTargetContext to insert
-        // the copy surface into. In the future we plan to have a more limited Context type
-        // (GrCopyContext?) that has the subset of GrRenderTargetContext operations that should be
-        // allowed on textures that aren't render targets.
-        // For now we just flush any writes to the src and issue an immediate copy to the dst.
-        src->flushWrites();
-        return fGpu->copySurface(dst, src, clippedSrcRect, clippedDstPoint);
-    }
-    sk_sp<GrRenderTargetContext> renderTargetContext(
-        this->contextPriv().makeWrappedRenderTargetContext(sk_ref_sp(dst->asRenderTarget()),
-                                                           nullptr));
-    if (!renderTargetContext) {
+#ifndef ENABLE_MDB
+    // We can't yet fully defer copies to textures, so GrTextureContext::copySurface will
+    // execute the copy immediately. Ensure the data is ready.
+    src->flushWrites();
+#endif
+
+    sk_sp<GrSurfaceContext> surfaceContext(
+        this->contextPriv().makeWrappedSurfaceContext(sk_ref_sp(dst)));
+
+    if (!surfaceContext) {
         return false;
     }
 
-    if (!renderTargetContext->copySurface(src, srcRect, dstPoint)) {
+    if (!surfaceContext->copySurface(src, srcRect, dstPoint)) {
         return false;
     }
+
     return true;
 }
 
@@ -633,6 +627,19 @@
                                                            surfaceProps);
 }
 
+sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurface> surface) {
+    ASSERT_SINGLE_OWNER_PRIV
+
+    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
+
+    if (proxy->asRenderTargetProxy()) {
+        return this->drawingManager()->makeRenderTargetContext(std::move(proxy), nullptr, nullptr);
+    } else {
+        SkASSERT(proxy->asTextureProxy());
+        return this->drawingManager()->makeTextureContext(std::move(proxy));
+    }
+}
+
 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
                                                                    const GrBackendTextureDesc& desc, 
                                                                    sk_sp<SkColorSpace> colorSpace,
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index d2fa7c1..dcf0807 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -9,6 +9,7 @@
 #define GrContextPriv_DEFINED
 
 #include "GrContext.h"
+#include "GrSurfaceContext.h"
 
 /** Class that adds methods to GrContext that are only intended for use internal to Skia.
     This class is purely a privileged window into GrContext. It should never have additional
@@ -22,6 +23,9 @@
                                                                 sk_sp<SkColorSpace> colorSpace,
                                                                 const SkSurfaceProps* = nullptr);
 
+    // Create a surfaceContext that wraps an existing texture or renderTarget
+    sk_sp<GrSurfaceContext> makeWrappedSurfaceContext(sk_sp<GrSurface> tex);
+
     sk_sp<GrRenderTargetContext> makeBackendTextureRenderTargetContext(
                                                          const GrBackendTextureDesc& desc,
                                                          sk_sp<SkColorSpace> colorSpace,
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 5267df3..e1dff8b 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -14,6 +14,8 @@
 #include "GrResourceProvider.h"
 #include "GrSoftwarePathRenderer.h"
 #include "GrSurfacePriv.h"
+#include "GrTextureContext.h"
+#include "GrTextureOpList.h"
 #include "SkSurface_Gpu.h"
 #include "SkTTopoSort.h"
 
@@ -172,6 +174,24 @@
     return SkRef(opList);
 }
 
+GrTextureOpList* GrDrawingManager::newOpList(GrTextureProxy* textureProxy) {
+    SkASSERT(fContext);
+
+    GrTextureOpList* opList = new GrTextureOpList(textureProxy, fContext->getGpu(),
+                                                  fContext->getAuditTrail());
+
+#ifndef ENABLE_MDB
+    // When MDB is disabled we still create a new GrOpList, but don't store or ref it - we rely
+    // on the caller to immediately execute and free it.
+    return opList;
+#else
+    *fOpLists.append() = opList;
+
+    // Drawing manager gets the creation ref - this ref is for the caller
+    return SkRef(opList);
+#endif
+}
+
 GrAtlasTextContext* GrDrawingManager::getAtlasTextContext() {
     if (!fAtlasTextContext) {
         fAtlasTextContext.reset(GrAtlasTextContext::Create());
@@ -253,3 +273,17 @@
                                                                   fContext->getAuditTrail(),
                                                                   fSingleOwner));
 }
+
+sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy) {
+    if (this->wasAbandoned() || !sProxy->asTextureProxy()) {
+        return nullptr;
+    }
+
+    // GrTextureRenderTargets should always be using GrRenderTargetContext
+    SkASSERT(!sProxy->asRenderTargetProxy());
+
+    sk_sp<GrTextureProxy> textureProxy(sk_ref_sp(sProxy->asTextureProxy()));
+
+    return sk_sp<GrTextureContext>(new GrTextureContext(fContext, this, std::move(textureProxy),
+                                                        fContext->getAuditTrail(), fSingleOwner));
+}
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index 3816868..90a3064 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -22,6 +22,8 @@
 class GrRenderTargetProxy;
 class GrSingleOWner;
 class GrSoftwarePathRenderer;
+class GrTextureContext;
+class GrTextureOpList;
 
 // The GrDrawingManager allocates a new GrRenderTargetContext for each GrRenderTarget
 // but all of them still land in the same GrOpList!
@@ -38,10 +40,12 @@
     sk_sp<GrRenderTargetContext> makeRenderTargetContext(sk_sp<GrSurfaceProxy>,
                                                          sk_sp<SkColorSpace>,
                                                          const SkSurfaceProps*);
+    sk_sp<GrTextureContext> makeTextureContext(sk_sp<GrSurfaceProxy>);
 
     // The caller automatically gets a ref on the returned opList. It must
     // be balanced by an unref call.
     GrRenderTargetOpList* newOpList(GrRenderTargetProxy* rtp);
+    GrTextureOpList* newOpList(GrTextureProxy* textureProxy);
 
     GrContext* getContext() { return fContext; }
 
diff --git a/src/gpu/GrOpList.h b/src/gpu/GrOpList.h
index 9c965f8..313807d 100644
--- a/src/gpu/GrOpList.h
+++ b/src/gpu/GrOpList.h
@@ -15,8 +15,10 @@
 
 class GrAuditTrail;
 class GrBatchFlushState;
+class GrRenderTargetOpList;
 class GrSurface;
 class GrSurfaceProxy;
+class GrTextureOpList;
 
 class GrOpList : public SkRefCnt {
 public:
@@ -62,6 +64,16 @@
     }
 
     /*
+     * Safely cast this GrOpList to a GrTextureOpList (if possible).
+     */
+    virtual GrTextureOpList* asTextureOpList() { return nullptr; }
+
+    /*
+     * Safely case this GrOpList to a GrRenderTargetOpList (if possible).
+     */
+    virtual GrRenderTargetOpList* asRenderTargetOpList() { return nullptr; }
+
+    /*
      * Dump out the GrOpList dependency DAG
      */
     SkDEBUGCODE(virtual void dump() const;)
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 6238fa8..f08f39a 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -81,18 +81,14 @@
                                              const SkSurfaceProps* surfaceProps,
                                              GrAuditTrail* auditTrail,
                                              GrSingleOwner* singleOwner)
-    : fDrawingManager(drawingMgr)
+    : GrSurfaceContext(context, auditTrail, singleOwner)
+    , fDrawingManager(drawingMgr)
     , fRenderTargetProxy(std::move(rtp))
     , fOpList(SkSafeRef(fRenderTargetProxy->getLastRenderTargetOpList()))
-    , fContext(context)
     , fInstancedPipelineInfo(fRenderTargetProxy.get())
     , fColorSpace(std::move(colorSpace))
     , fColorXformFromSRGB(nullptr)
     , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
-    , fAuditTrail(auditTrail)
-#ifdef SK_DEBUG
-    , fSingleOwner(singleOwner)
-#endif
 {
     if (fColorSpace) {
         // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index b084d48..d96f83d 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -127,6 +127,8 @@
         return fInstancedRendering.get();
     }
 
+    GrRenderTargetOpList* asRenderTargetOpList() override { return this; }
+
     SkDEBUGCODE(void dump() const override;)
 
 private:
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index cb9b97a..03637cf 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -54,17 +54,6 @@
     return surf->asRenderTarget();
 }
 
-
-#ifdef SK_DEBUG
-void GrRenderTargetProxy::validate(GrContext* context) const {
-    if (fTarget) {
-        SkASSERT(fTarget->getContext() == context);
-    }
-
-    INHERITED::validate();
-}
-#endif
-
 size_t GrRenderTargetProxy::onGpuMemorySize() const {
     if (fTarget) {
         return fTarget->gpuMemorySize();
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
new file mode 100644
index 0000000..682233b
--- /dev/null
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrSurfaceContext.h"
+
+#include "../private/GrAuditTrail.h"
+
+
+// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
+// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
+// stack. When this occurs with a closed GrOpList, a new one will be allocated
+// when the renderTargetContext attempts to use it (via getOpList).
+GrSurfaceContext::GrSurfaceContext(GrContext* context,
+                                   GrAuditTrail* auditTrail,
+                                   GrSingleOwner* singleOwner)
+    : fContext(context)
+    , fAuditTrail(auditTrail)
+#ifdef SK_DEBUG
+    , fSingleOwner(singleOwner)
+#endif
+{
+}
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index 9de41ef..95fc8b9 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -66,6 +66,14 @@
     SkRefCnt_SafeAssign(fLastOpList, opList);
 }
 
+GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() {
+    return fLastOpList ? fLastOpList->asRenderTargetOpList() : nullptr;
+}
+
+GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() {
+    return fLastOpList ? fLastOpList->asTextureOpList() : nullptr;
+}
+
 sk_sp<GrSurfaceProxy> GrSurfaceProxy::MakeWrapped(sk_sp<GrSurface> surf) {
     if (surf->asTexture()) {
         if (surf->asRenderTarget()) {
@@ -109,3 +117,12 @@
     return GrSurfaceProxy::MakeDeferred(caps, desc, SkBackingFit::kExact, budgeted);
 }
 
+#ifdef SK_DEBUG
+void GrSurfaceProxy::validate(GrContext* context) const {
+    if (fTarget) {
+        SkASSERT(fTarget->getContext() == context);
+    }
+
+    INHERITED::validate();
+}
+#endif
diff --git a/src/gpu/GrTextureContext.cpp b/src/gpu/GrTextureContext.cpp
new file mode 100644
index 0000000..5c0c17b
--- /dev/null
+++ b/src/gpu/GrTextureContext.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTextureContext.h"
+#include "GrDrawingManager.h"
+#include "GrResourceProvider.h"
+#include "GrTextureOpList.h"
+
+#include "../private/GrAuditTrail.h"
+
+#define ASSERT_SINGLE_OWNER \
+    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
+#define RETURN_FALSE_IF_ABANDONED  if (fDrawingManager->wasAbandoned()) { return false; }
+
+GrTextureContext::GrTextureContext(GrContext* context,
+                                   GrDrawingManager* drawingMgr,
+                                   sk_sp<GrTextureProxy> textureProxy,
+                                   GrAuditTrail* auditTrail,
+                                   GrSingleOwner* singleOwner)
+    : GrSurfaceContext(context, auditTrail, singleOwner)
+    , fDrawingManager(drawingMgr)
+    , fTextureProxy(std::move(textureProxy))
+    , fOpList(SkSafeRef(fTextureProxy->getLastTextureOpList()))
+{
+    SkDEBUGCODE(this->validate();)
+}
+
+#ifdef SK_DEBUG
+void GrTextureContext::validate() const {
+    SkASSERT(fTextureProxy);
+    fTextureProxy->validate(fContext);
+
+    if (fOpList && !fOpList->isClosed()) {
+        SkASSERT(fTextureProxy->getLastOpList() == fOpList);
+    }
+}
+#endif
+
+GrTextureContext::~GrTextureContext() {
+    ASSERT_SINGLE_OWNER
+    SkSafeUnref(fOpList);
+}
+
+GrTextureOpList* GrTextureContext::getOpList() {
+    ASSERT_SINGLE_OWNER
+    SkDEBUGCODE(this->validate();)
+
+    if (!fOpList || fOpList->isClosed()) {
+        fOpList = fDrawingManager->newOpList(fTextureProxy.get());
+    }
+
+    return fOpList;
+}
+
+bool GrTextureContext::copySurface(GrSurface* src, const SkIRect& srcRect,
+                                   const SkIPoint& dstPoint) {
+    ASSERT_SINGLE_OWNER
+    RETURN_FALSE_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrTextureContext::copySurface");
+
+    // TODO: this needs to be fixed up since it ends the deferrable of the GrTexture
+    sk_sp<GrTexture> tex(sk_ref_sp(fTextureProxy->instantiate(fContext->textureProvider())));
+    if (!tex) {
+        return false;
+    }
+
+    GrTextureOpList* opList = this->getOpList();
+    bool result = opList->copySurface(tex.get(), src, srcRect, dstPoint);
+
+#ifndef ENABLE_MDB
+    GrBatchFlushState flushState(fContext->getGpu(), nullptr);
+    opList->prepareBatches(&flushState);
+    opList->drawBatches(&flushState);
+    opList->reset();
+#endif
+
+    return result;
+}
diff --git a/src/gpu/GrTextureOpList.h b/src/gpu/GrTextureOpList.h
index 33ca656..7674184 100644
--- a/src/gpu/GrTextureOpList.h
+++ b/src/gpu/GrTextureOpList.h
@@ -55,6 +55,8 @@
                      const SkIRect& srcRect,
                      const SkIPoint& dstPoint);
 
+    GrTextureOpList* asTextureOpList() override { return this; }
+
     SkDEBUGCODE(void dump() const override;)
 
 private: