Plumbing to propagate save & restore from SkCanvas down to GrContext & lower

http://codereview.appspot.com/6203067/



git-svn-id: http://skia.googlecode.com/svn/trunk@4034 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index db9c542..1e4e0a3 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -351,6 +351,20 @@
     friend class SkDeviceFilteredPaint;
     friend class DeviceImageFilterProxy;
 
+    /**
+     * postSave is called by SkCanvas to inform the device that it has
+     * just completed a save operation. This allows derived
+     * classes to initialize their state-dependent caches.
+     */
+    virtual void postSave() {};
+
+    /**
+     * preRestore is called by SkCanvas right before it executes a restore
+     * operation. As the partner of postSave, it allows
+     * derived classes to clear their state-dependent caches.
+     */
+    virtual void preRestore() {};
+
     // just called by SkCanvas when built as a layer
     void setOrigin(int x, int y) { fOrigin.set(x, y); }
     // just called by SkCanvas for saveLayer
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 8a18331..e05c48a 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -680,6 +680,18 @@
     void unlockStencilBuffer(GrResourceEntry* sbEntry);
     GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
 
+    /*
+     * postClipPush acts as a hint to this and lower-level classes (e.g.,
+     * GrGpu) that the clip stack has changed.
+     */
+    virtual void postClipPush();
+
+    /*
+     * preClipPop acts as a hint that the clip stack has been restored to an
+     * earlier state.
+     */
+    virtual void preClipPop();
+
     GrPathRenderer* getPathRenderer(const SkPath& path,
                                     GrPathFill fill,
                                     const GrDrawTarget* target,
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index ffc24a8..ee4d791 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -146,11 +146,18 @@
     // used by createCompatibleDevice
     SkGpuDevice(GrContext*, GrTexture* texture, TexCache, bool needClear);
 
-    // override from SkDevice
+    // overrides from SkDevice
+    virtual void postSave() SK_OVERRIDE {
+        fContext->postClipPush();
+    }
+    virtual void preRestore() SK_OVERRIDE {
+        fContext->preClipPop();
+    }
+
     virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
                                                int width, int height,
                                                bool isOpaque,
-                                               Usage usage);
+                                               Usage usage) SK_OVERRIDE;
 
     SkDrawProcs* initDrawForText(GrTextContext*);
     bool bindDeviceAsTexture(GrPaint* paint);
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index f507284..af2e066 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -700,6 +700,14 @@
     fClipStack.save();
     SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
 
+    for (DeviceCM* curLayer = fMCRec->fTopLayer; 
+         curLayer; 
+         curLayer = curLayer->fNext) {
+        if (NULL != curLayer->fDevice) {
+            curLayer->fDevice->postSave();
+        }
+    }
+
     return saveCount;
 }
 
@@ -870,6 +878,14 @@
 void SkCanvas::internalRestore() {
     SkASSERT(fMCStack.count() != 0);
 
+    for (DeviceCM* curLayer = fMCRec->fTopLayer; 
+         curLayer; 
+         curLayer = curLayer->fNext) {
+        if (NULL != curLayer->fDevice) {
+            curLayer->fDevice->preRestore();
+        }
+    }
+
     fDeviceCMDirty = true;
     fLocalBoundsCompareTypeDirty = true;
     fLocalBoundsCompareTypeDirtyBW = true;
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index aa2c088..e4c9fb5 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -300,6 +300,17 @@
         fClipMaskInStencil = false;
     }
 
+    void postClipPush() {
+        // TODO: make sure that, if the clip stack is unaltered, the 
+        // prior clip mask is reused (i.e., a push w/ no change to the 
+        // clip stack)
+        fAACache.push();
+    }
+
+    void preClipPop() {
+        fAACache.pop();
+    }
+
     void setContext(GrContext* context) {
         fAACache.setContext(context);
     }
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index bd6d829..b45970b 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -2216,4 +2216,12 @@
     return srcTexture;
 }
 
+void GrContext::postClipPush() {
+    fGpu->postClipPush();
+}
+
+void GrContext::preClipPop() {
+    fGpu->preClipPop();
+};
+
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 715799c..35d50e9 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -1103,9 +1103,6 @@
     return layout;
 }
 
-void GrDrawTarget::clipWillBeSet(const GrClip& clip) {
-}
-
 void GrDrawTarget::SetRectVertices(const GrRect& rect,
                                    const GrMatrix* matrix, 
                                    const GrRect* srcRects[], 
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index bf6e41b..a6ab675 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -190,6 +190,9 @@
         return 1 << (stage + (texCoordIdx * GrDrawState::kNumStages));
     }
 
+    virtual void postClipPush() {};
+    virtual void preClipPop() {};
+
 private:
     static const int TEX_COORD_BIT_CNT = GrDrawState::kNumStages *
                                          GrDrawState::kMaxTexCoords;
@@ -1041,7 +1044,7 @@
                                   int vertexCount) = 0;
     // subclass overrides to be notified when clip is set. Must call
     // INHERITED::clipwillBeSet
-    virtual void clipWillBeSet(const GrClip& clip);
+    virtual void clipWillBeSet(const GrClip& clip) {}
 
     // Helpers for drawRect, protected so subclasses that override drawRect
     // can use them.
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index ba73f7d..500673b 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -365,6 +365,13 @@
                                                  // clipping.
     };
 
+    virtual void postClipPush() SK_OVERRIDE {
+        fClipMaskManager.postClipPush();
+    }
+    virtual void preClipPop() SK_OVERRIDE {
+        fClipMaskManager.preClipPop();
+    }
+
 protected:
     // prepares clip flushes gpu state before a draw
     bool setupClipAndFlushState(GrPrimitiveType type);
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 553bacc..7b3b04f 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -223,7 +223,7 @@
         bool clipChanged = this->needsNewClip();
         bool stateChanged = this->needsNewState();
         if (clipChanged) {
-            this->pushClip();
+            this->storeClip();
         }
         if (stateChanged) {
             this->pushState();
@@ -342,7 +342,7 @@
 
     draw.fClipChanged = this->needsNewClip();
     if (draw.fClipChanged) {
-       this->pushClip();
+       this->storeClip();
     }
 
     draw.fStateChanged = this->needsNewState();
@@ -409,7 +409,7 @@
 
     draw.fClipChanged = this->needsNewClip();
     if (draw.fClipChanged) {
-        this->pushClip();
+        this->storeClip();
     }
 
     draw.fStateChanged = this->needsNewState();
@@ -801,7 +801,7 @@
     return false;
 }
 
-void GrInOrderDrawBuffer::pushClip() {
+void GrInOrderDrawBuffer::storeClip() {
     fClips.push_back() = fClip;
     fClipSet = false;
 }
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 3b27d70..fa3e0a2 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -167,7 +167,7 @@
     bool needsNewClip() const;
 
     void pushState();
-    void pushClip();
+    void storeClip();
 
     // call this to invalidate the tracking data that is used to concatenate 
     // multiple draws into a single draw.