First pass at stencil clip mask refactoring

http://codereview.appspot.com/6031043/



git-svn-id: http://skia.googlecode.com/svn/trunk@3692 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 57e73c4..4acb4f6 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -31,8 +31,7 @@
 #define DEBUG_INVAL_START_IDX -1
 
 GrGpu::GrGpu()
-    : fClipInStencil(false)
-    , fContext(NULL)
+    : fContext(NULL)
     , fResetTimestamp(kExpiredTimestamp+1)
     , fVertexPool(NULL)
     , fIndexPool(NULL)
@@ -40,7 +39,6 @@
     , fIndexPoolUseCnt(0)
     , fQuadIndexBuffer(NULL)
     , fUnitSquareVertexBuffer(NULL)
-    , fPathRendererChain(NULL)
     , fContextIsDirty(true)
     , fResourceHead(NULL) {
 
@@ -82,8 +80,8 @@
     fVertexPool = NULL;
     delete fIndexPool;
     fIndexPool = NULL;
-    // in case path renderer has any GrResources, start from scratch
-    GrSafeSetNull(fPathRendererChain);
+
+    fClipMaskManager.freeResources();
 }
 
 void GrGpu::releaseResources() {
@@ -101,8 +99,8 @@
     fVertexPool = NULL;
     delete fIndexPool;
     fIndexPool = NULL;
-    // in case path renderer has any GrResources, start from scratch
-    GrSafeSetNull(fPathRendererChain);
+
+    fClipMaskManager.freeResources();
 }
 
 void GrGpu::insertResource(GrResource* resource) {
@@ -543,206 +541,255 @@
 }
 }
 
-bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
-    const GrIRect* r = NULL;
-    GrIRect clipRect;
 
-    GrDrawState* drawState = this->drawState();
+
+// sort out what kind of clip mask needs to be created: A8/R8, stencil or scissor
+bool GrClipMaskManager::createClipMask(GrGpu* gpu, 
+                                       const GrClip& clipIn,
+                                       ScissoringSettings* scissorSettings) {
+
+    GrAssert(scissorSettings);
+
+    scissorSettings->fEnableScissoring = false;
+    fClipMaskInStencil = false;
+
+    GrDrawState* drawState = gpu->drawState();
+    if (!drawState->isClipState()) {
+        return true;
+    }
+
     GrRenderTarget* rt = drawState->getRenderTarget();
 
     // GrDrawTarget should have filtered this for us
     GrAssert(NULL != rt);
 
-    if (drawState->isClipState()) {
+    GrRect bounds;
+    GrRect rtRect;
+    rtRect.setLTRB(0, 0,
+                    GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
+    if (clipIn.hasConservativeBounds()) {
+        bounds = clipIn.getConservativeBounds();
+        if (!bounds.intersect(rtRect)) {
+            bounds.setEmpty();
+        }
+    } else {
+        bounds = rtRect;
+    }
 
-        GrRect bounds;
+    bounds.roundOut(&scissorSettings->fScissorRect);
+    if  (scissorSettings->fScissorRect.isEmpty()) {
+        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
+        // TODO: I think we can do an early exit here - after refactoring try:
+        //  set fEnableScissoring to true but leave fClipMaskInStencil false
+        //  and return - everything is going to be scissored away anyway!
+    }
+    scissorSettings->fEnableScissoring = true;
+
+    // use the stencil clip if we can't represent the clip as a rectangle.
+    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
+                         !bounds.isEmpty();
+
+    if (fClipMaskInStencil) {
+        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
+    }
+
+    return true;
+}
+
+// Create a 1-bit clip mask in the stencil buffer
+bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu, 
+                                              const GrClip& clipIn,
+                                              const GrRect& bounds,
+                                              ScissoringSettings* scissorSettings) {
+
+    GrAssert(fClipMaskInStencil);
+
+    GrDrawState* drawState = gpu->drawState();
+    GrAssert(drawState->isClipState());
+
+    GrRenderTarget* rt = drawState->getRenderTarget();
+    GrAssert(NULL != rt);
+
+    // TODO: dynamically attach a SB when needed.
+    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
+    if (NULL == stencilBuffer) {
+        return false;
+    }
+
+    if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) {
+
+        stencilBuffer->setLastClip(clipIn, rt->width(), rt->height());
+
+        // we set the current clip to the bounds so that our recursive
+        // draws are scissored to them. We use the copy of the complex clip
+        // we just stashed on the SB to render from. We set it back after
+        // we finish drawing it into the stencil.
+        const GrClip& clipCopy = stencilBuffer->getLastClip();
+        gpu->setClip(GrClip(bounds));
+
+        GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
+        drawState = gpu->drawState();
+        drawState->setRenderTarget(rt);
+        GrDrawTarget::AutoGeometryPush agp(gpu);
+
+        gpu->disableScissor();
+#if !VISUALIZE_COMPLEX_CLIP
+        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
+#endif
+
+        int count = clipCopy.getElementCount();
+        int clipBit = stencilBuffer->bits();
+        SkASSERT((clipBit <= 16) &&
+                    "Ganesh only handles 16b or smaller stencil buffers");
+        clipBit = (1 << (clipBit-1));
+
         GrRect rtRect;
         rtRect.setLTRB(0, 0,
                        GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
-        if (fClip.hasConservativeBounds()) {
-            bounds = fClip.getConservativeBounds();
-            if (!bounds.intersect(rtRect)) {
-                bounds.setEmpty();
+
+        bool clearToInside;
+        GrSetOp startOp = kReplace_SetOp; // suppress warning
+        int start = process_initial_clip_elements(clipCopy,
+                                                    rtRect,
+                                                    &clearToInside,
+                                                    &startOp);
+
+        gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
+
+        // walk through each clip element and perform its set op
+        // with the existing clip.
+        for (int c = start; c < count; ++c) {
+            GrPathFill fill;
+            bool fillInverted;
+            // enabled at bottom of loop
+            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
+
+            bool canRenderDirectToStencil; // can the clip element be drawn
+                                            // directly to the stencil buffer
+                                            // with a non-inverted fill rule
+                                            // without extra passes to
+                                            // resolve in/out status.
+
+            GrPathRenderer* pr = NULL;
+            const GrPath* clipPath = NULL;
+            if (kRect_ClipType == clipCopy.getElementType(c)) {
+                canRenderDirectToStencil = true;
+                fill = kEvenOdd_PathFill;
+                fillInverted = false;
+                // there is no point in intersecting a screen filling
+                // rectangle.
+                if (kIntersect_SetOp == clipCopy.getOp(c) &&
+                    clipCopy.getRect(c).contains(rtRect)) {
+                    continue;
+                }
+            } else {
+                fill = clipCopy.getPathFill(c);
+                fillInverted = GrIsFillInverted(fill);
+                fill = GrNonInvertedFill(fill);
+                clipPath = &clipCopy.getPath(c);
+                pr = this->getClipPathRenderer(gpu, *clipPath, fill);
+                if (NULL == pr) {
+                    fClipMaskInStencil = false;
+                    gpu->setClip(clipCopy);     // restore to the original
+                    return false;
+                }
+                canRenderDirectToStencil =
+                    !pr->requiresStencilPass(*clipPath, fill, gpu);
             }
-        } else {
-            bounds = rtRect;
-        }
 
-        bounds.roundOut(&clipRect);
-        if  (clipRect.isEmpty()) {
-            clipRect.setLTRB(0,0,0,0);
-        }
-        r = &clipRect;
+            GrSetOp op = (c == start) ? startOp : clipCopy.getOp(c);
+            int passes;
+            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
 
-        // use the stencil clip if we can't represent the clip as a rectangle.
-        fClipInStencil = !fClip.isRect() && !fClip.isEmpty() && 
-                         !bounds.isEmpty();
+            bool canDrawDirectToClip; // Given the renderer, the element,
+                                        // fill rule, and set operation can
+                                        // we render the element directly to
+                                        // stencil bit used for clipping.
+            canDrawDirectToClip =
+                GrStencilSettings::GetClipPasses(op,
+                                                    canRenderDirectToStencil,
+                                                    clipBit,
+                                                    fillInverted,
+                                                    &passes, stencilSettings);
 
-        // TODO: dynamically attach a SB when needed.
-        GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
-        if (fClipInStencil && NULL == stencilBuffer) {
-            return false;
-        }
-
-        if (fClipInStencil &&
-            stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) {
-
-            stencilBuffer->setLastClip(fClip, rt->width(), rt->height());
-
-            // we set the current clip to the bounds so that our recursive
-            // draws are scissored to them. We use the copy of the complex clip
-            // we just stashed on the SB to render from. We set it back after
-            // we finish drawing it into the stencil.
-            const GrClip& clip = stencilBuffer->getLastClip();
-            fClip.setFromRect(bounds);
-
-            AutoStateRestore asr(this, GrDrawTarget::kReset_ASRInit);
-            drawState = this->drawState();
-            drawState->setRenderTarget(rt);
-            AutoGeometryPush agp(this);
-
-            this->flushScissor(NULL);
-#if !VISUALIZE_COMPLEX_CLIP
-            drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
-#endif
-
-            int count = clip.getElementCount();
-            int clipBit = stencilBuffer->bits();
-            SkASSERT((clipBit <= 16) &&
-                     "Ganesh only handles 16b or smaller stencil buffers");
-            clipBit = (1 << (clipBit-1));
-            
-            bool clearToInside;
-            GrSetOp startOp = kReplace_SetOp; // suppress warning
-            int start = process_initial_clip_elements(clip,
-                                                      rtRect,
-                                                      &clearToInside,
-                                                      &startOp);
-
-            this->clearStencilClip(clipRect, clearToInside);
-
-            // walk through each clip element and perform its set op
-            // with the existing clip.
-            for (int c = start; c < count; ++c) {
-                GrPathFill fill;
-                bool fillInverted;
-                // enabled at bottom of loop
-                drawState->disableState(kModifyStencilClip_StateBit);
-
-                bool canRenderDirectToStencil; // can the clip element be drawn
-                                               // directly to the stencil buffer
-                                               // with a non-inverted fill rule
-                                               // without extra passes to
-                                               // resolve in/out status.
-
-                GrPathRenderer* pr = NULL;
-                const GrPath* clipPath = NULL;
-                if (kRect_ClipType == clip.getElementType(c)) {
-                    canRenderDirectToStencil = true;
-                    fill = kEvenOdd_PathFill;
-                    fillInverted = false;
-                    // there is no point in intersecting a screen filling
-                    // rectangle.
-                    if (kIntersect_SetOp == clip.getOp(c) &&
-                        clip.getRect(c).contains(rtRect)) {
-                        continue;
-                    }
+            // draw the element to the client stencil bits if necessary
+            if (!canDrawDirectToClip) {
+                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
+                    kIncClamp_StencilOp,
+                    kIncClamp_StencilOp,
+                    kAlways_StencilFunc,
+                    0xffff,
+                    0x0000,
+                    0xffff);
+                SET_RANDOM_COLOR
+                if (kRect_ClipType == clipCopy.getElementType(c)) {
+                    *drawState->stencil() = gDrawToStencil;
+                    gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
                 } else {
-                    fill = clip.getPathFill(c);
-                    fillInverted = GrIsFillInverted(fill);
-                    fill = GrNonInvertedFill(fill);
-                    clipPath = &clip.getPath(c);
-                    pr = this->getClipPathRenderer(*clipPath, fill);
-                    if (NULL == pr) {
-                        fClipInStencil = false;
-                        fClip = clip;
-                        return false;
-                    }
-                    canRenderDirectToStencil =
-                        !pr->requiresStencilPass(*clipPath, fill, this);
-                }
-
-                GrSetOp op = (c == start) ? startOp : clip.getOp(c);
-                int passes;
-                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
-
-                bool canDrawDirectToClip; // Given the renderer, the element,
-                                          // fill rule, and set operation can
-                                          // we render the element directly to
-                                          // stencil bit used for clipping.
-                canDrawDirectToClip =
-                    GrStencilSettings::GetClipPasses(op,
-                                                     canRenderDirectToStencil,
-                                                     clipBit,
-                                                     fillInverted,
-                                                     &passes, stencilSettings);
-
-                // draw the element to the client stencil bits if necessary
-                if (!canDrawDirectToClip) {
-                    GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
-                        kIncClamp_StencilOp,
-                        kIncClamp_StencilOp,
-                        kAlways_StencilFunc,
-                        0xffff,
-                        0x0000,
-                        0xffff);
-                    SET_RANDOM_COLOR
-                    if (kRect_ClipType == clip.getElementType(c)) {
+                    if (canRenderDirectToStencil) {
                         *drawState->stencil() = gDrawToStencil;
-                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
+                        pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
                     } else {
-                        if (canRenderDirectToStencil) {
-                            *drawState->stencil() = gDrawToStencil;
-                            pr->drawPath(*clipPath, fill, NULL, this, 0, false);
-                        } else {
-                            pr->drawPathToStencil(*clipPath, fill, this);
-                        }
+                        pr->drawPathToStencil(*clipPath, fill, gpu);
                     }
                 }
+            }
 
-                // now we modify the clip bit by rendering either the clip
-                // element directly or a bounding rect of the entire clip.
-                drawState->enableState(kModifyStencilClip_StateBit);
-                for (int p = 0; p < passes; ++p) {
-                    *drawState->stencil() = stencilSettings[p];
-                    if (canDrawDirectToClip) {
-                        if (kRect_ClipType == clip.getElementType(c)) {
-                            SET_RANDOM_COLOR
-                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
-                        } else {
-                            SET_RANDOM_COLOR
-                            pr->drawPath(*clipPath, fill, NULL, this, 0, false);
-                        }
+            // now we modify the clip bit by rendering either the clip
+            // element directly or a bounding rect of the entire clip.
+            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
+            for (int p = 0; p < passes; ++p) {
+                *drawState->stencil() = stencilSettings[p];
+                if (canDrawDirectToClip) {
+                    if (kRect_ClipType == clipCopy.getElementType(c)) {
+                        SET_RANDOM_COLOR
+                        gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
                     } else {
                         SET_RANDOM_COLOR
-                        this->drawSimpleRect(bounds, NULL, 0);
+                        pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
                     }
+                } else {
+                    SET_RANDOM_COLOR
+                    gpu->drawSimpleRect(bounds, NULL, 0);
                 }
             }
-            // restore clip
-            fClip = clip;
-            // recusive draws would have disabled this since they drew with
-            // the clip bounds as clip.
-            fClipInStencil = true;
         }
+        // restore clip
+        gpu->setClip(clipCopy);
+        // recusive draws would have disabled this since they drew with
+        // the clip bounds as clip.
+        fClipMaskInStencil = true;
+    }
+
+    return true;
+}
+
+bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
+
+    ScissoringSettings scissoringSettings;
+
+    if (!fClipMaskManager.createClipMask(this, fClip, &scissoringSettings)) {
+        return false;
     }
 
     // Must flush the scissor after graphics state
     if (!this->flushGraphicsState(type)) {
         return false;
     }
-    this->flushScissor(r);
+
+    scissoringSettings.setupScissoring(this);
     return true;
 }
 
-GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
-                                           GrPathFill fill) {
+GrPathRenderer* GrClipMaskManager::getClipPathRenderer(GrGpu* gpu,
+                                                       const GrPath& path,
+                                                       GrPathFill fill) {
     if (NULL == fPathRendererChain) {
         fPathRendererChain = 
-            new GrPathRendererChain(this->getContext(),
+            new GrPathRendererChain(gpu->getContext(),
                                     GrPathRendererChain::kNonAAOnly_UsageFlag);
     }
-    return fPathRendererChain->getPathRenderer(path, fill, this, false);
+    return fPathRendererChain->getPathRenderer(path, fill, gpu, false);
 }
 
 
@@ -982,3 +1029,19 @@
     }
 }
 
+
+////////////////////////////////////////////////////////////////////////////////
+void ScissoringSettings::setupScissoring(GrGpu* gpu) {
+    if (!fEnableScissoring) {
+        gpu->disableScissor();
+        return;
+    }
+
+    gpu->enableScissoring(fScissorRect);
+}
+
+
+void GrClipMaskManager::freeResources() {
+    // in case path renderer has any GrResources, start from scratch
+    GrSafeSetNull(fPathRendererChain);
+}
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 4a986b1..7bba355 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -51,6 +51,66 @@
     uint32_t fRenderTargetCreateCnt;
 };
 
+/**
+ * Scissoring needs special handling during stencil clip mask creation
+ * since the creation process re-entrantly invokes setupClipAndFlushState.
+ * During this process the call stack is used to keep 
+ * track of (and apply to the GPU) the current scissor settings.
+ */
+struct ScissoringSettings {
+    bool    fEnableScissoring;
+    GrIRect fScissorRect;
+
+    void setupScissoring(GrGpu* gpu);
+};
+
+/**
+ * The clip mask creator handles the generation of the clip mask. If anti 
+ * aliasing is requested it will (in the future) generate a single channel 
+ * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit 
+ * mask in the stencil buffer. In the non anti-aliasing case, if the clip
+ * mask can be represented as a rectangle then scissoring is used. In all
+ * cases scissoring is used to bound the range of the clip mask.
+ */
+class GrClipMaskManager {
+public:
+    GrClipMaskManager()
+        : fClipMaskInStencil(false)
+        , fPathRendererChain(NULL) {
+    }
+
+    bool createClipMask(GrGpu* gpu, 
+                        const GrClip& clip, 
+                        ScissoringSettings* scissorSettings);
+
+    void freeResources();
+
+    bool isClipInStencil() const { return fClipMaskInStencil; }
+
+    void resetMask() {
+        fClipMaskInStencil = false;
+    }
+
+protected:
+private:
+    bool fClipMaskInStencil;        // is the clip mask in the stencil buffer?
+
+    // must be instantiated after GrGpu object has been given its owning
+    // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
+    GrPathRendererChain*        fPathRendererChain;
+
+    bool createStencilClipMask(GrGpu* gpu, 
+                               const GrClip& clip, 
+                               const GrRect& bounds,
+                               ScissoringSettings* scissorSettings);
+
+    // determines the path renderer used to draw a clip path element.
+    GrPathRenderer* getClipPathRenderer(GrGpu* gpu,
+                                        const SkPath& path, 
+                                        GrPathFill fill);
+
+};
+
 class GrGpu : public GrDrawTarget {
 
 public:
@@ -341,7 +401,14 @@
         return fConfigRenderSupport[config];
     }
 
-protected:
+    virtual void enableScissoring(const GrIRect& rect) = 0;
+    virtual void disableScissor() = 0;
+
+    // GrGpu subclass sets clip bit in the stencil buffer. The subclass is
+    // free to clear the remaining bits to zero if masked clears are more
+    // expensive than clearing all bits.
+    virtual void clearStencilClip(const GrIRect& rect, bool insideClip) = 0;
+
     enum PrivateDrawStateStateBits {
         kFirstBit = (GrDrawState::kLastPublicStateBit << 1),
 
@@ -350,10 +417,7 @@
                                                  // clipping.
     };
 
-    // keep track of whether we are using stencil clipping (as opposed to
-    // scissor).
-    bool    fClipInStencil;
-
+protected:
     // prepares clip flushes gpu state before a draw
     bool setupClipAndFlushState(GrPrimitiveType type);
 
@@ -374,6 +438,8 @@
 
     GrGpuStats fStats;
 
+    GrClipMaskManager           fClipMaskManager;
+
     struct GeometryPoolState {
         const GrVertexBuffer* fPoolVertexBuffer;
         int                   fPoolStartVertex;
@@ -485,14 +551,6 @@
     // returns false if current state is unsupported.
     virtual bool flushGraphicsState(GrPrimitiveType type) = 0;
 
-    // Sets the scissor rect, or disables if rect is NULL.
-    virtual void flushScissor(const GrIRect* rect) = 0;
-
-    // GrGpu subclass sets clip bit in the stencil buffer. The subclass is
-    // free to clear the remaining bits to zero if masked clears are more
-    // expensive than clearing all bits.
-    virtual void clearStencilClip(const GrIRect& rect, bool insideClip) = 0;
-
     // clears the entire stencil buffer to 0
     virtual void clearStencil() = 0;
 
@@ -521,10 +579,6 @@
     mutable GrVertexBuffer*     fUnitSquareVertexBuffer; // mutable so it can be
                                                          // created on-demand
 
-    // must be instantiated after GrGpu object has been given its owning
-    // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
-    GrPathRendererChain*        fPathRendererChain;
-
     bool                        fContextIsDirty;
 
     GrResource*                 fResourceHead;
@@ -546,9 +600,6 @@
     void prepareVertexPool();
     void prepareIndexPool();
 
-    // determines the path renderer used to draw a clip path element.
-    GrPathRenderer* getClipPathRenderer(const SkPath& path, GrPathFill fill);
-
     void resetContext() {
         this->onResetContext();
         ++fResetTimestamp;
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
index 143e525..39700fe 100644
--- a/src/gpu/GrStencil.h
+++ b/src/gpu/GrStencil.h
@@ -289,7 +289,8 @@
     }
 
 private:
-    friend class GrGpu;
+    friend class GrClipMaskManager;
+
     enum {
         kMaxStencilClipPasses = 2  // maximum number of passes to add a clip 
                                    // element to the stencil buffer.
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 9114a0e..a17f7d7 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -516,13 +516,16 @@
     }
 
     fHWBounds.fScissorRect.invalidate();
-    fHWBounds.fScissorEnabled = false;
-    GL_CALL(Disable(GR_GL_SCISSOR_TEST));
+    this->disableScissor();
+
     fHWBounds.fViewportRect.invalidate();
 
     fHWDrawState.stencil()->invalidate();
     fHWStencilClip = false;
-    fClipInStencil = false;
+
+    // TODO: I believe this should actually go in GrGpu::onResetContext
+    // rather than here
+    fClipMaskManager.resetMask();
 
     fHWGeometryState.fIndexBuffer = NULL;
     fHWGeometryState.fVertexBuffer = NULL;
@@ -1311,7 +1314,7 @@
     return NULL;
 }
 
-void GrGpuGL::flushScissor(const GrIRect* rect) {
+void GrGpuGL::enableScissoring(const GrIRect& rect) {
     const GrDrawState& drawState = this->getDrawState();
     const GrGLRenderTarget* rt =
         static_cast<const GrGLRenderTarget*>(drawState.getRenderTarget());
@@ -1320,28 +1323,28 @@
     const GrGLIRect& vp = rt->getViewport();
 
     GrGLIRect scissor;
-    if (NULL != rect) {
-        scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
-                              rect->width(), rect->height());
-        if (scissor.contains(vp)) {
-            rect = NULL;
-        }
+    scissor.setRelativeTo(vp, rect.fLeft, rect.fTop,
+                          rect.width(), rect.height());
+    if (scissor.contains(vp)) {
+        disableScissor();
+        return;
     }
 
-    if (NULL != rect) {
-        if (fHWBounds.fScissorRect != scissor) {
-            scissor.pushToGLScissor(this->glInterface());
-            fHWBounds.fScissorRect = scissor;
-        }
-        if (!fHWBounds.fScissorEnabled) {
-            GL_CALL(Enable(GR_GL_SCISSOR_TEST));
-            fHWBounds.fScissorEnabled = true;
-        }
-    } else {
-        if (fHWBounds.fScissorEnabled) {
-            GL_CALL(Disable(GR_GL_SCISSOR_TEST));
-            fHWBounds.fScissorEnabled = false;
-        }
+    if (fHWBounds.fScissorRect != scissor) {
+        scissor.pushToGLScissor(this->glInterface());
+        fHWBounds.fScissorRect = scissor;
+    }
+    if (!fHWBounds.fScissorEnabled) {
+        GL_CALL(Enable(GR_GL_SCISSOR_TEST));
+        fHWBounds.fScissorEnabled = true;
+    }
+}
+
+void GrGpuGL::disableScissor() {
+    if (fHWBounds.fScissorEnabled) {
+        GL_CALL(Disable(GR_GL_SCISSOR_TEST));
+        fHWBounds.fScissorEnabled = false;
+//        fHWBounds.fScissorRect.invalidate();
     }
 }
 
@@ -1363,7 +1366,10 @@
         }
     }
     this->flushRenderTarget(rect);
-    this->flushScissor(rect);
+    if (NULL != rect)
+        this->enableScissoring(*rect);
+    else
+        this->disableScissor();
 
     GrGLfloat r, g, b, a;
     static const GrGLfloat scale255 = 1.f / 255.f;
@@ -1389,10 +1395,8 @@
     
     this->flushRenderTarget(&GrIRect::EmptyIRect());
 
-    if (fHWBounds.fScissorEnabled) {
-        GL_CALL(Disable(GR_GL_SCISSOR_TEST));
-        fHWBounds.fScissorEnabled = false;
-    }
+    this->disableScissor();
+
     GL_CALL(StencilMask(0xffffffff));
     GL_CALL(ClearStencil(0));
     GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
@@ -1426,7 +1430,7 @@
         value = 0;
     }
     this->flushRenderTarget(&GrIRect::EmptyIRect());
-    this->flushScissor(&rect);
+    this->enableScissoring(rect);
     GL_CALL(StencilMask(clipStencilMask));
     GL_CALL(ClearStencil(value));
     GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
@@ -1733,18 +1737,23 @@
 
         if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) {
             // Apple's extension uses the scissor as the blit bounds.
+#if 1
             GL_CALL(Enable(GR_GL_SCISSOR_TEST));
             GL_CALL(Scissor(r.fLeft, r.fBottom,
                             r.fWidth, r.fHeight));
             GL_CALL(ResolveMultisampleFramebuffer());
             fHWBounds.fScissorRect.invalidate();
             fHWBounds.fScissorEnabled = true;
+#else
+            this->enableScissoring(dirtyRect);
+            GL_CALL(ResolveMultisampleFramebuffer());
+#endif
         } else {
             if (GrGLCaps::kDesktopARB_MSFBOType != this->glCaps().msFBOType()) {
                 // this respects the scissor during the blit, so disable it.
                 GrAssert(GrGLCaps::kDesktopEXT_MSFBOType ==
                          this->glCaps().msFBOType());
-                this->flushScissor(NULL);
+                this->disableScissor();
             }
             int right = r.fLeft + r.fWidth;
             int top = r.fBottom + r.fHeight;
@@ -1803,7 +1812,7 @@
 
     // use stencil for clipping if clipping is enabled and the clip
     // has been written into the stencil.
-    bool stencilClip = fClipInStencil && drawState.isClipState();
+    bool stencilClip = fClipMaskManager.isClipInStencil() && drawState.isClipState();
     bool drawClipToStencil =
         drawState.isStateFlagEnabled(kModifyStencilClip_StateBit);
     bool stencilChange = (fHWDrawState.getStencil() != *settings) ||
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 928b50e..77b300a 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -140,7 +140,9 @@
     virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
                                      uint32_t vertexCount,
                                      uint32_t numVertices);
-    virtual void flushScissor(const GrIRect* rect);
+    virtual void enableScissoring(const GrIRect& rect);
+    virtual void disableScissor();
+
     virtual void clearStencil();
     virtual void clearStencilClip(const GrIRect& rect, bool insideClip);
     virtual int getMaxEdges() const;