Add GrProgramElement base class for GrEffect with deferred exec ref.

BUG=skia:2889
R=robertphillips@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/537773004
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index ec1b0ba..b7a6d17 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -10,16 +10,14 @@
 
 #include "GrColor.h"
 #include "GrEffectUnitTest.h"
-#include "GrTexture.h"
+#include "GrProgramElement.h"
 #include "GrTextureAccess.h"
 #include "GrTypesPriv.h"
 
 class GrBackendEffectFactory;
 class GrContext;
 class GrCoordTransform;
-class GrEffect;
-class GrVertexEffect;
-class SkString;
+
 
 /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
     Ganesh shading pipeline.
@@ -31,7 +29,7 @@
     effect must reach 0 before the thread terminates and the pool is destroyed. To create a static
     effect use the macro GR_CREATE_STATIC_EFFECT declared below.
   */
-class GrEffect : public SkRefCnt {
+class GrEffect : public GrProgramElement {
 public:
     SK_DECLARE_INST_COUNT(GrEffect)
 
@@ -205,7 +203,7 @@
     bool                                         fWillUseInputColor;
     bool                                         fRequiresVertexShader;
 
-    typedef SkRefCnt INHERITED;
+    typedef GrProgramElement INHERITED;
 };
 
 /**
@@ -217,5 +215,4 @@
 static GrEffect* NAME SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);         \
 static SkAutoTDestroy<GrEffect> NAME##_ad(NAME);
 
-
 #endif
diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h
index f18f5c5..189237a 100644
--- a/include/gpu/GrGpuResource.h
+++ b/include/gpu/GrGpuResource.h
@@ -110,7 +110,7 @@
     mutable int32_t fPendingWrites;
 
     // These functions need access to the pending read/write member functions.
-    friend class GrDrawState;
+    friend class GrRODrawState;
     friend class GrProgramResource;
 };
 
diff --git a/include/gpu/GrProgramElement.h b/include/gpu/GrProgramElement.h
new file mode 100644
index 0000000..67135a3
--- /dev/null
+++ b/include/gpu/GrProgramElement.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProgramElement_DEFINED
+#define GrProgramElement_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkTArray.h"
+
+class GrProgramResource;
+
+/**
+ * Base class for GrEffect (and future GrGeometryProcessor). GrDrawState uses this to manage
+ * transitioning a GrEffect from being owned by a client to being scheduled for execution. It
+ * converts resources owned by the effect from being ref'ed to having pending reads/writes.
+ *
+ * All GrGpuResource objects owned by a GrProgramElement or derived classes (either directly or
+ * indirectly) must be wrapped in a GrProgramResource and registered with the GrProgramElement using
+ * addGrProgramResource(). This allows the regular refs to be converted to pending IO events
+ * when the program element is scheduled for deferred execution.
+ */
+class GrProgramElement : public SkNoncopyable {
+public:
+    SK_DECLARE_INST_COUNT_ROOT(GrProgramElement)
+
+    virtual ~GrProgramElement() {
+        // fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
+        SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
+        // Set to invalid values.
+        SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
+    }
+
+    void ref() const {
+        // Once the ref cnt reaches zero it should never be ref'ed again.
+        SkASSERT(fRefCnt > 0);
+        this->validate();
+        ++fRefCnt;
+    }
+
+    void unref() const {
+        this->validate();
+        --fRefCnt;
+        if (0 == fRefCnt && 0 == fPendingExecutions) {
+            SkDELETE(this);
+        }
+    }
+
+    void validate() const {
+#ifdef SK_DEBUG
+        SkASSERT(fRefCnt >= 0);
+        SkASSERT(fPendingExecutions >= 0);
+        SkASSERT(fRefCnt + fPendingExecutions > 0);
+#endif
+    }
+
+protected:
+    GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {}
+
+    /** Subclasses registers their resources using this function. It is assumed the GrProgramResouce
+        is and will remain owned by the subclass and this function will retain a raw ptr. Once a
+        GrProgramResource is registered its setResource must not be called.
+     */
+    void addProgramResource(const GrProgramResource* res) {
+        fProgramResources.push_back(res);
+    }
+
+private:
+    void convertRefToPendingExecution() const;
+
+    void completedExecution() const {
+        this->validate();
+        --fPendingExecutions;
+        if (0 == fRefCnt && 0 == fPendingExecutions) {
+            SkDELETE(this);
+        }
+    }
+
+    mutable int32_t fRefCnt;
+    // Count of deferred executions not yet issued to the 3D API.
+    mutable int32_t fPendingExecutions;
+
+    SkSTArray<4, const GrProgramResource*, true> fProgramResources;
+
+    // Only this class can access convertRefToPendingExecution() and completedExecution().
+    template <typename T> friend class GrProgramElementRef;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+#endif
diff --git a/include/gpu/GrProgramElementRef.h b/include/gpu/GrProgramElementRef.h
new file mode 100644
index 0000000..ea11f44
--- /dev/null
+++ b/include/gpu/GrProgramElementRef.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProgramElementRef_DEFINED
+#define GrProgramElementRef_DEFINED
+
+#include "SkRefCnt.h"
+#include "GrTypes.h"
+
+/**
+ * Helper for owning a GrProgramElement subclass and being able to convert a ref to pending
+ * execution. It is like an SkAutoTUnref for program elements whose execution can be deferred. Once
+ * in the pending execution state it is illegal to change the object that is owned by the
+ * GrProgramElementRef. Its destructor will either unref the GrProgramElement or signal that
+ * the pending execution has completed, depending on whether convertToPendingExec() was called.
+ */
+template <typename T> class GrProgramElementRef : SkNoncopyable {
+public:
+    GrProgramElementRef() : fOwnPendingExec(false), fObj(NULL) {};
+
+    // Adopts a ref from the caller.
+    explicit GrProgramElementRef(T* obj) : fOwnPendingExec(false), fObj(obj)  {}
+
+    // Adopts a ref from the caller. Do not call after convertToPendingExec.
+    void reset(T* obj) {
+        SkASSERT(!fOwnPendingExec);
+        SkSafeUnref(fObj);
+        fObj = obj;
+    }
+
+    void convertToPendingExec() {
+        SkASSERT(!fOwnPendingExec);
+        fObj->convertRefToPendingExecution();
+        fOwnPendingExec = true;
+    }
+
+    T* get() const { return fObj; }
+    operator T*() { return fObj; }
+
+    /** If T is const, the type returned from operator-> will also be const. */
+    typedef typename SkTConstType<typename SkAutoTUnref<T>::BlockRef<T>,
+                                  SkTIsConst<T>::value>::type BlockRefType;
+
+    /**
+     * GrProgramElementRef assumes ownership of the ref and manages converting the ref to a
+     * pending execution. As a result, it is an error for the user to ref or unref through
+     * GrProgramElementRef. Therefore operator-> returns BlockRef<T>*.
+     */
+    BlockRefType *operator->() const {
+        return static_cast<BlockRefType*>(fObj);
+    }
+
+    ~GrProgramElementRef() {
+        if (NULL != fObj) {
+            if (fOwnPendingExec) {
+                fObj->completedExecution();
+            } else {
+                fObj->unref();
+            }
+        }
+    }
+
+private:
+    bool fOwnPendingExec;
+    T*   fObj;
+
+    typedef SkNoncopyable INHERITED;
+};
+#endif
diff --git a/include/gpu/GrProgramResource.h b/include/gpu/GrProgramResource.h
new file mode 100644
index 0000000..277ae9d
--- /dev/null
+++ b/include/gpu/GrProgramResource.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProgramResource_DEFINED
+#define GrProgramResource_DEFINED
+
+#include "SkRefCnt.h"
+
+class GrGpuResource;
+
+/**
+ * Class that wraps a resource referenced by a GrProgramElement or GrDrawState. It manages
+ * converting refs to pending io operations. Like SkAutoTUnref, its constructor and setter adopt
+ * a ref from their caller. This class is intended only for internal use in core Gr code.
+ */
+class GrProgramResource : SkNoncopyable {
+public:
+    enum IOType {
+        kRead_IOType,
+        kWrite_IOType,
+        kRW_IOType,
+
+        kNone_IOType, // For internal use only, don't specify to constructor or setResource().
+    };
+
+    SK_DECLARE_INST_COUNT_ROOT(GrProgramResource);
+    GrProgramResource();
+
+    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
+        pending on the resource when markPendingIO is called. */
+    explicit GrProgramResource(GrGpuResource*, IOType ioType);
+
+    ~GrProgramResource();
+
+    GrGpuResource* getResource() const { return fResource; }
+
+    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
+        pending on the resource when markPendingIO is called. */
+    void setResource(GrGpuResource*, IOType ioType);
+
+    /** Does this object own a pending read or write on the resource it is wrapping. */
+    bool ownsPendingIO() const { return fPendingIO; }
+
+    /** Shortcut for calling setResource() with NULL. It cannot be called after markingPendingIO
+        is called. */
+    void reset();
+
+private:
+    /** Called by owning GrProgramElement when the program element is first scheduled for
+        execution. */
+    void markPendingIO() const;
+
+    /** Called when the program element/draw state is no longer owned by GrDrawTarget-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. */
+    void removeRef() const;
+
+    friend class GrDrawState;
+    friend class GrProgramElement;
+
+    GrGpuResource*      fResource;
+    mutable bool        fOwnRef;
+    mutable bool        fPendingIO;
+    IOType              fIOType;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+#endif