Wrap GrEffects in GrEffectPtr.

This is the first step towards automatic recycling of scratch resouces in the cache via ref-cnts.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/7092061

git-svn-id: http://skia.googlecode.com/svn/trunk@7222 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index 5fca4b2..431159c 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -17,19 +17,52 @@
 
 class GrBackendEffectFactory;
 class GrContext;
+class GrEffect;
 class SkString;
 
+/**
+ * A Wrapper class for GrEffect. Its ref-count will track owners that may use effects to enqueue
+ * new draw operations separately from ownership within a deferred drawing queue. When the
+ * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled
+ * in service of later draws. However, the deferred draw queue may still own direct references to
+ * the underlying GrEffect.
+ */
+class GrEffectRef : public SkRefCnt {
+public:
+    SK_DECLARE_INST_COUNT(GrEffectRef);
+
+    GrEffect* get() { return fEffect; }
+    const GrEffect* get() const { return fEffect; }
+
+    void* operator new(size_t size);
+    void operator delete(void* target);
+
+private:
+    friend GrEffect; // to construct these
+
+    explicit GrEffectRef(GrEffect* effect);
+
+    virtual ~GrEffectRef();
+
+    GrEffect* fEffect;
+
+    typedef SkRefCnt INHERITED;
+};
+
 /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
     Ganesh shading pipeline.
     Subclasses must have a function that produces a human-readable name:
         static const char* Name();
     GrEffect objects *must* be immutable: after being constructed, their fields may not change.
+
+    GrEffect subclass objects should be created by factory functions that return GrEffectRef.
+    There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static
+    member function of a GrEffect subclass.
   */
 class GrEffect : public GrRefCnt {
 public:
     SK_DECLARE_INST_COUNT(GrEffect)
 
-    GrEffect() {};
     virtual ~GrEffect();
 
     /**
@@ -120,9 +153,36 @@
      */
     void addTextureAccess(const GrTextureAccess* textureAccess);
 
+    GrEffect() : fEffectPtr(NULL) {};
+
+    /** This should be called by GrEffect subclass factories */
+    static GrEffectRef* CreateEffectPtr(GrEffect* effect) {
+        if (NULL == effect->fEffectPtr) {
+            effect->fEffectPtr = SkNEW_ARGS(GrEffectRef, (effect));
+        } else {
+            effect->fEffectPtr->ref();
+            GrCrash("This function should only be called once per effect currently.");
+        }
+        return effect->fEffectPtr;
+    }
+
 private:
-    SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
+    void effectPtrDestroyed() {
+        fEffectPtr = NULL;
+    }
+
+    friend GrEffectRef; // to call GrEffectRef destroyed
+
+    SkSTArray<4, const GrTextureAccess*, true>  fTextureAccesses;
+    GrEffectRef*                                fEffectPtr;
+
     typedef GrRefCnt INHERITED;
 };
 
+inline GrEffectRef::GrEffectRef(GrEffect* effect) {
+    GrAssert(NULL != effect);
+    effect->ref();
+    fEffect = effect;
+}
+
 #endif
diff --git a/include/gpu/GrEffectStage.h b/include/gpu/GrEffectStage.h
index e42f198..0b532d6 100644
--- a/include/gpu/GrEffectStage.h
+++ b/include/gpu/GrEffectStage.h
@@ -22,28 +22,28 @@
 public:
 
     GrEffectStage()
-    : fEffect (NULL) {
+    : fEffectPtr (NULL) {
         GR_DEBUGCODE(fSavedCoordChangeCnt = 0;)
     }
 
     ~GrEffectStage() {
-        GrSafeUnref(fEffect);
+        GrSafeUnref(fEffectPtr);
         GrAssert(0 == fSavedCoordChangeCnt);
     }
 
     bool operator ==(const GrEffectStage& other) const {
         // first handle cases where one or the other has no effect
-        if (NULL == fEffect) {
-            return NULL == other.fEffect;
-        } else if (NULL == other.fEffect) {
+        if (NULL == fEffectPtr) {
+            return NULL == other.fEffectPtr;
+        } else if (NULL == other.fEffectPtr) {
             return false;
         }
 
-        if (fEffect->getFactory() != other.fEffect->getFactory()) {
+        if (this->getEffect()->getFactory() != other.getEffect()->getFactory()) {
             return false;
         }
 
-        if (!fEffect->isEqual(*other.fEffect)) {
+        if (!this->getEffect()->isEqual(*other.getEffect())) {
             return false;
         }
 
@@ -53,8 +53,8 @@
     bool operator !=(const GrEffectStage& s) const { return !(*this == s); }
 
     GrEffectStage& operator =(const GrEffectStage& other) {
-        GrSafeAssign(fEffect, other.fEffect);
-        if (NULL != fEffect) {
+        GrSafeAssign(fEffectPtr, other.fEffectPtr);
+        if (NULL != fEffectPtr) {
             fCoordChangeMatrix = other.fCoordChangeMatrix;
         }
         return *this;
@@ -70,7 +70,7 @@
     class SavedCoordChange {
     private:
         SkMatrix fCoordChangeMatrix;
-        GR_DEBUGCODE(mutable SkAutoTUnref<const GrEffect> fEffect;)
+        GR_DEBUGCODE(mutable SkAutoTUnref<const GrEffectRef> fEffectPtr;)
 
         friend class GrEffectStage;
     };
@@ -83,9 +83,9 @@
      */
     void saveCoordChange(SavedCoordChange* savedCoordChange) const {
         savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix;
-        GrAssert(NULL == savedCoordChange->fEffect.get());
-        GR_DEBUGCODE(GrSafeRef(fEffect);)
-        GR_DEBUGCODE(savedCoordChange->fEffect.reset(fEffect);)
+        GrAssert(NULL == savedCoordChange->fEffectPtr.get());
+        GR_DEBUGCODE(GrSafeRef(fEffectPtr);)
+        GR_DEBUGCODE(savedCoordChange->fEffectPtr.reset(fEffectPtr);)
         GR_DEBUGCODE(++fSavedCoordChangeCnt);
     }
 
@@ -94,9 +94,9 @@
      */
     void restoreCoordChange(const SavedCoordChange& savedCoordChange) {
         fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix;
-        GrAssert(savedCoordChange.fEffect.get() == fEffect);
+        GrAssert(savedCoordChange.fEffectPtr.get() == fEffectPtr);
         GR_DEBUGCODE(--fSavedCoordChangeCnt);
-        GR_DEBUGCODE(savedCoordChange.fEffect.reset(NULL);)
+        GR_DEBUGCODE(savedCoordChange.fEffectPtr.reset(NULL);)
     }
 
     /**
@@ -106,21 +106,28 @@
     const SkMatrix& getCoordChangeMatrix() const { return fCoordChangeMatrix; }
 
     void reset() {
-        GrSafeSetNull(fEffect);
+        GrSafeSetNull(fEffectPtr);
     }
 
-    const GrEffect* setEffect(const GrEffect* effect) {
+    const GrEffectRef* setEffect(const GrEffectRef* effectPtr) {
         GrAssert(0 == fSavedCoordChangeCnt);
-        GrSafeAssign(fEffect, effect);
+        GrSafeAssign(fEffectPtr, effectPtr);
         fCoordChangeMatrix.reset();
-        return effect;
+        return effectPtr;
     }
 
-    const GrEffect* getEffect() const { return fEffect; }
+    // TODO: Push GrEffectRef deeper and make this getter return it rather than GrEffect.
+    const GrEffect* getEffect() const {
+        if (NULL != fEffectPtr) {
+            return fEffectPtr->get();
+        } else {
+            return NULL;
+        }
+    }
 
 private:
     SkMatrix            fCoordChangeMatrix;
-    const GrEffect*     fEffect;
+    const GrEffectRef*  fEffectPtr;
 
     GR_DEBUGCODE(mutable int fSavedCoordChangeCnt;)
 };
diff --git a/include/gpu/GrEffectUnitTest.h b/include/gpu/GrEffectUnitTest.h
index 8cc2689..51fa637 100644
--- a/include/gpu/GrEffectUnitTest.h
+++ b/include/gpu/GrEffectUnitTest.h
@@ -31,22 +31,22 @@
 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
 
 class GrContext;
-class GrEffect;
+class GrEffectRef;
 class GrTexture;
 
 class GrEffectTestFactory : GrNoncopyable {
 public:
 
-    typedef GrEffect* (*CreateProc)(SkRandom*, GrContext*, GrTexture* dummyTextures[]);
+    typedef GrEffectRef* (*CreateProc)(SkRandom*, GrContext*, GrTexture* dummyTextures[]);
 
     GrEffectTestFactory(CreateProc createProc) {
         fCreateProc = createProc;
         GetFactories()->push_back(this);
     }
 
-    static GrEffect* CreateStage(SkRandom* random,
-                                      GrContext* context,
-                                      GrTexture* dummyTextures[]) {
+    static GrEffectRef* CreateStage(SkRandom* random,
+                                    GrContext* context,
+                                    GrTexture* dummyTextures[]) {
         uint32_t idx = random->nextRangeU(0, GetFactories()->count() - 1);
         GrEffectTestFactory* factory = (*GetFactories())[idx];
         return factory->fCreateProc(random, context, dummyTextures);
@@ -62,7 +62,7 @@
  */
 #define GR_DECLARE_EFFECT_TEST                                                      \
     static GrEffectTestFactory gTestFactory;                                        \
-    static GrEffect* TestCreate(SkRandom*, GrContext*, GrTexture* dummyTextures[2])
+    static GrEffectRef* TestCreate(SkRandom*, GrContext*, GrTexture* dummyTextures[2])
 
 /** GrEffect subclasses should insert this macro in their implementation file. They must then
  *  also implement this static function: