Speculative fix for Android Debug only crash in r4049

http://codereview.appspot.com/6251049/



git-svn-id: http://skia.googlecode.com/svn/trunk@4053 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 79d6d48..a568ca7 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -14,11 +14,10 @@
 #include "GrRefCnt.h"
 #include "GrSamplerState.h"
 #include "GrStencil.h"
+#include "GrRenderTarget.h"
 
 #include "SkXfermode.h"
 
-class GrRenderTarget;
-class GrTexture;
 
 class GrDrawState : public GrRefCnt {
 
@@ -53,18 +52,52 @@
     typedef uint32_t StageMask;
     GR_STATIC_ASSERT(sizeof(StageMask)*8 >= GrDrawState::kNumStages);
 
-    GrDrawState() {
+    GrDrawState() 
+        : fRenderTarget(NULL) {
+
+        for (int i = 0; i < kNumStages; ++i) {
+            fTextures[i] = NULL;
+        }
+
         this->reset();
     }
 
-    GrDrawState(const GrDrawState& state) {
+    GrDrawState(const GrDrawState& state) 
+        : fRenderTarget(NULL) {
+
+        for (int i = 0; i < kNumStages; ++i) {
+            fTextures[i] = NULL;
+        }
+
         *this = state;
     }
 
+    virtual ~GrDrawState() {
+        for (int i = 0; i < kNumStages; ++i) {
+            GrSafeSetNull(fTextures[i]);
+        }
+        GrSafeSetNull(fRenderTarget);
+    }
+
     /**
      * Resets to the default state. Sampler states will not be modified.
      */ 
     void reset() {
+
+        for (int i = 0; i < kNumStages; ++i) {
+            // just as in setTexture we have to detach the texture before
+            // unreffing it because, if a texture is actually freed here,
+            // GrGLTexture's onRelease method will try to remove it from all
+            // possible owner's (including this one) via setTexture(NULL)
+            GrTexture* temp = fTextures[i];
+            fTextures[i] = NULL;
+            GrSafeUnref(temp);
+        }
+
+        GrRenderTarget* temp = fRenderTarget;
+        fRenderTarget = NULL;
+        GrSafeUnref(temp);
+
         // make sure any pad is zero for memcmp
         // all GrDrawState members should default to something valid by the
         // the memset except those initialized individually below. There should
@@ -85,14 +118,13 @@
         fSrcBlend = kOne_BlendCoeff;
         fDstBlend = kZero_BlendCoeff;
         fViewMatrix.reset();
-        fBehaviorBits = 0;
 
         // ensure values that will be memcmp'ed in == but not memset in reset()
         // are tightly packed
         GrAssert(this->memsetSize() +  sizeof(fColor) + sizeof(fCoverage) +
                  sizeof(fFirstCoverageStage) + sizeof(fColorFilterMode) +
-                 sizeof(fSrcBlend) + sizeof(fDstBlend) ==
-                 this->podSize());
+                 sizeof(fSrcBlend) + sizeof(fDstBlend) + sizeof(fTextures) +
+                 sizeof(fRenderTarget) == this->podSize());
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -174,16 +206,14 @@
     void setTexture(int stage, GrTexture* texture) {
         GrAssert((unsigned)stage < kNumStages);
 
-        if (isBehaviorEnabled(kTexturesNeedRef_BehaviorBit)) {
-            // If we don't clear out the current texture before unreffing
-            // it we can get into an infinite loop as the GrGLTexture's
-            // onRelease method recursively calls setTexture
-            GrTexture* temp = fTextures[stage];
-            fTextures[stage] = NULL;
+        // If we don't clear out the current texture before unreffing
+        // it we can get into an infinite loop as the GrGLTexture's
+        // onRelease method recursively calls setTexture
+        GrTexture* temp = fTextures[stage];
+        fTextures[stage] = NULL;
 
-            SkSafeRef(texture);
-            SkSafeUnref(temp);
-        }
+        SkSafeRef(texture);
+        SkSafeUnref(temp);
 
         fTextures[stage] = texture;
     }
@@ -461,7 +491,18 @@
      *
      * @param target  The render target to set.
      */
-    void setRenderTarget(GrRenderTarget* target) { fRenderTarget = target; }
+    void setRenderTarget(GrRenderTarget* target) { 
+
+        // If we don't clear out the current render target before unreffing
+        // it we can get into an infinite loop as the GrGLRenderTarget's
+        // onRelease method recursively calls setTexture
+        GrRenderTarget* temp = fRenderTarget;
+        fRenderTarget = NULL;
+
+        SkSafeRef(target);
+        SkSafeUnref(temp);
+        fRenderTarget = target; 
+    }
 
     /**
      * Retrieves the currently set rendertarget.
@@ -479,16 +520,26 @@
             fSavedTarget = NULL;
             this->set(ds, newTarget);
         }
-        ~AutoRenderTargetRestore() { this->set(NULL, NULL); }
-        void set(GrDrawState* ds, GrRenderTarget* newTarget) {
+        ~AutoRenderTargetRestore() { this->restore(); }
+
+        void restore() {
             if (NULL != fDrawState) {
                 fDrawState->setRenderTarget(fSavedTarget);
+                fDrawState = NULL;
             }
+            GrSafeSetNull(fSavedTarget);
+        }
+
+        void set(GrDrawState* ds, GrRenderTarget* newTarget) {
+            this->restore();
+
             if (NULL != ds) {
+                GrAssert(NULL == fSavedTarget);
                 fSavedTarget = ds->getRenderTarget();
+                SkSafeRef(fSavedTarget);
                 ds->setRenderTarget(newTarget);
+                fDrawState = ds;
             }
-            fDrawState = ds;
         }
     private:
         GrDrawState* fDrawState;
@@ -681,28 +732,6 @@
         fFlagBits = ds.fFlagBits;
     }
 
-    /**
-     *  Flags that do not affect rendering. 
-     */
-    enum GrBehaviorBits {
-        /**
-         * Calls to setTexture will ref/unref the texture
-         */
-        kTexturesNeedRef_BehaviorBit = 0x01,
-    };
-
-    void enableBehavior(uint32_t behaviorBits) {
-        fBehaviorBits |= behaviorBits;
-    }
-
-    void disableBehavior(uint32_t behaviorBits) {
-        fBehaviorBits &= ~(behaviorBits);
-    }
-
-    bool isBehaviorEnabled(uint32_t behaviorBits) const {
-        return 0 != (behaviorBits & fBehaviorBits);
-    }
-
     /// @}
 
     ///////////////////////////////////////////////////////////////////////////
@@ -748,14 +777,6 @@
             return false;
         }
 
-        // kTexturesNeedRef is an internal flag for altering the draw state's 
-        // behavior rather than a property that will impact drawing - ignore it
-        // here
-        if ((fBehaviorBits & ~kTexturesNeedRef_BehaviorBit) != 
-            (s.fBehaviorBits & ~kTexturesNeedRef_BehaviorBit)) {
-            return false;
-        }
-
         for (int i = 0; i < kNumStages; i++) {
             if (fTextures[i] &&
                 this->fSamplerStates[i] != s.fSamplerStates[i]) {
@@ -780,13 +801,16 @@
         memcpy(this->podStart(), s.podStart(), this->podSize());
 
         fViewMatrix = s.fViewMatrix;
-        fBehaviorBits = s.fBehaviorBits;
 
         for (int i = 0; i < kNumStages; i++) {
+            SkSafeRef(fTextures[i]);            // already copied by memcpy
             if (s.fTextures[i]) {
                 this->fSamplerStates[i] = s.fSamplerStates[i];
             }
         }
+
+        SkSafeRef(fRenderTarget);               // already copied by memcpy
+
         if (kColorMatrix_StateBit & s.fFlagBits) {
             memcpy(this->fColorMatrix, s.fColorMatrix, sizeof(fColorMatrix));
         }
@@ -820,15 +844,13 @@
         GrColor             fBlendConstant;
         GrColor             fPodStartMarker;
     };
-    GrTexture*          fTextures[kNumStages];
     GrColor             fColorFilterColor;
     uint32_t            fFlagBits;
     DrawFace            fDrawFace; 
-    VertexEdgeType      fVertexEdgeType;
     GrStencilSettings   fStencilSettings;
     union {
-        GrRenderTarget* fRenderTarget;
-        GrRenderTarget* fMemsetEndMarker;
+        VertexEdgeType  fVertexEdgeType;
+        VertexEdgeType  fMemsetEndMarker;
     };
     // @}
 
@@ -839,13 +861,14 @@
     int                 fFirstCoverageStage;
     SkXfermode::Mode    fColorFilterMode;
     GrBlendCoeff        fSrcBlend;
+    GrBlendCoeff        fDstBlend;
+    GrTexture*          fTextures[kNumStages];
     union {
-        GrBlendCoeff    fDstBlend;
-        GrBlendCoeff    fPodEndMarker;
+        GrRenderTarget* fRenderTarget;
+        GrRenderTarget* fPodEndMarker;
     };
     // @}
 
-    uint32_t            fBehaviorBits;
     GrMatrix            fViewMatrix;
 
     // This field must be last; it will not be copied or compared