Add GrGpuTextureProxyRef

Basically a GrTextureProxified clone of GrGpuResourceRef

Change-Id: I8772550bb867ef2cf2d53efef0a0346bb7c90eb6
Reviewed-on: https://skia-review.googlesource.com/15221
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrGpuResourceRef.h b/include/gpu/GrGpuResourceRef.h
index 3a170f4..f82b502 100644
--- a/include/gpu/GrGpuResourceRef.h
+++ b/include/gpu/GrGpuResourceRef.h
@@ -89,6 +89,64 @@
     typedef SkNoncopyable INHERITED;
 };
 
+class GrTextureProxy;
+
+class GrTextureProxyRef : SkNoncopyable {
+public:
+    virtual ~GrTextureProxyRef();
+
+    GrTextureProxy* getProxy() const { return fProxy; }
+
+    /** Does this object own a pending read or write on the resource it is wrapping. */
+    bool ownsPendingIO() const { return fPendingIO; }
+
+    /** What type of IO does this represent? This is independent of whether a normal ref or a
+        pending IO is currently held. */
+    GrIOType ioType() const { return fIOType; }
+
+    /** Shortcut for calling setProxy() with NULL. It cannot be called after markingPendingIO
+        is called. */
+    void reset();
+
+protected:
+    GrTextureProxyRef();
+
+    /** ioType expresses what type of IO operations will be marked as
+        pending on the resource when markPendingIO is called. */
+    GrTextureProxyRef(sk_sp<GrTextureProxy>, GrIOType);
+
+    /** ioType expresses what type of IO operations will be marked as
+        pending on the resource when markPendingIO is called. */
+    void setProxy(sk_sp<GrTextureProxy>, GrIOType);
+
+private:
+    /** Called by owning GrProgramElement when the program element is first scheduled for
+        execution. It can only be called once. */
+    void markPendingIO() const;
+
+    /** Called when the program element/draw state is no longer owned by GrOpList-client code.
+        This lets the cache know that the drawing code will no longer schedule additional reads or
+        writes to the resource using the program element or draw state. It can only be called once.
+      */
+    void removeRef() const;
+
+    /** Called to indicate that the previous pending IO is complete. Useful when the owning object
+        still has refs, so it is not about to destroy this GrGpuResourceRef, but its previously
+        pending executions have been complete. Can only be called if removeRef() was not previously
+        called. */
+    void pendingIOComplete() const;
+
+    friend class GrResourceIOProcessor;
+
+    GrTextureProxy* fProxy;
+    mutable bool    fOwnRef;
+    mutable bool    fPendingIO;
+    GrIOType        fIOType;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+
 /**
  * Templated version of GrGpuResourceRef to enforce type safety.
  */
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index 7f47145..9449060 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -125,7 +125,7 @@
 
 private:
     // This class is used to manage conversion of refs to pending reads/writes.
-    friend class GrGpuResourceRef;
+    friend class GrTextureProxyRef;
     template <typename, GrIOType> friend class GrPendingIOResource;
 
     void addPendingRead() const {
diff --git a/src/gpu/GrGpuResourceRef.cpp b/src/gpu/GrGpuResourceRef.cpp
index 532e065..fc1c8b9 100644
--- a/src/gpu/GrGpuResourceRef.cpp
+++ b/src/gpu/GrGpuResourceRef.cpp
@@ -125,3 +125,116 @@
     fResource->unref();
     fOwnRef = false;
 }
+
+///////////////////////////////////////////////////////////////////////////////
+#include "GrTextureProxy.h"
+
+GrTextureProxyRef::GrTextureProxyRef() {
+    fProxy = nullptr;
+    fOwnRef = false;
+    fPendingIO = false;
+}
+
+GrTextureProxyRef::GrTextureProxyRef(sk_sp<GrTextureProxy> proxy, GrIOType ioType) {
+    fProxy = nullptr;
+    fOwnRef = false;
+    fPendingIO = false;
+    this->setProxy(proxy, ioType);
+}
+
+GrTextureProxyRef::~GrTextureProxyRef() {
+    if (fOwnRef) {
+        SkASSERT(fProxy);
+        fProxy->unref();
+    }
+    if (fPendingIO) {
+        switch (fIOType) {
+            case kRead_GrIOType:
+                fProxy->completedRead();
+                break;
+            case kWrite_GrIOType:
+                fProxy->completedWrite();
+                break;
+            case kRW_GrIOType:
+                fProxy->completedRead();
+                fProxy->completedWrite();
+                break;
+        }
+    }
+}
+
+void GrTextureProxyRef::reset() {
+    SkASSERT(!fPendingIO);
+    SkASSERT(SkToBool(fProxy) == fOwnRef);
+    if (fOwnRef) {
+        fProxy->unref();
+        fOwnRef = false;
+        fProxy = nullptr;
+    }
+}
+
+void GrTextureProxyRef::setProxy(sk_sp<GrTextureProxy> proxy, GrIOType ioType) {
+    SkASSERT(!fPendingIO);
+    SkASSERT(SkToBool(fProxy) == fOwnRef);
+    SkSafeUnref(fProxy);
+    if (!proxy) {
+        fProxy = nullptr;
+        fOwnRef = false;
+    } else {
+        fProxy = proxy.release();   // due to the semantics of this class we unpack from sk_sp
+        fOwnRef = true;
+        fIOType = ioType;
+    }
+}
+
+void GrTextureProxyRef::markPendingIO() const {
+    // This should only be called when the owning GrProgramElement gets its first
+    // pendingExecution ref.
+    SkASSERT(!fPendingIO);
+    SkASSERT(fProxy);
+    fPendingIO = true;
+    switch (fIOType) {
+        case kRead_GrIOType:
+            fProxy->addPendingRead();
+            break;
+        case kWrite_GrIOType:
+            fProxy->addPendingWrite();
+            break;
+        case kRW_GrIOType:
+            fProxy->addPendingRead();
+            fProxy->addPendingWrite();
+            break;
+    }
+}
+
+void GrTextureProxyRef::pendingIOComplete() const {
+    // This should only be called when the owner's pending executions have ocurred but it is still
+    // reffed.
+    SkASSERT(fOwnRef);
+    SkASSERT(fPendingIO);
+    switch (fIOType) {
+        case kRead_GrIOType:
+            fProxy->completedRead();
+            break;
+        case kWrite_GrIOType:
+            fProxy->completedWrite();
+            break;
+        case kRW_GrIOType:
+            fProxy->completedRead();
+            fProxy->completedWrite();
+            break;
+
+    }
+    fPendingIO = false;
+}
+
+void GrTextureProxyRef::removeRef() const {
+    // This should only be called once, when the owners last ref goes away and
+    // there is a pending execution.
+    SkASSERT(fOwnRef);
+    SkASSERT(fPendingIO);
+    SkASSERT(fProxy);
+    fProxy->unref();
+    fOwnRef = false;
+}
+