Make GrClipMaskManager configure the stencil and scissor on GrGpu
Review URL: http://codereview.appspot.com/6308096/



git-svn-id: http://skia.googlecode.com/svn/trunk@4288 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 55a8192..c16b410 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -23,15 +23,6 @@
 //#define GR_SW_CLIP 1
 
 ////////////////////////////////////////////////////////////////////////////////
-void ScissoringSettings::setupScissoring(GrGpu* gpu) {
-    if (!fEnableScissoring) {
-        gpu->disableScissor();
-        return;
-    }
-
-    gpu->enableScissoring(fScissorRect);
-}
-
 namespace {
 // set up the draw state to enable the aa clipping mask. Besides setting up the 
 // sampler matrix this also alters the vertex layout
@@ -113,37 +104,50 @@
 ////////////////////////////////////////////////////////////////////////////////
 // sort out what kind of clip mask needs to be created: alpha, stencil,
 // scissor, or entirely software
-bool GrClipMaskManager::createClipMask(const GrClip& clipIn,
-                                       ScissoringSettings* scissorSettings) {
-
-    GrAssert(scissorSettings);
-
-    scissorSettings->fEnableScissoring = false;
-
+bool GrClipMaskManager::setupClipping(const GrClip& clipIn) {
     fCurrClipMaskType = kNone_ClipMaskType;
-    
+
     GrDrawState* drawState = fGpu->drawState();
-    if (!drawState->isClipState()) {
+    if (!drawState->isClipState() || clipIn.isEmpty()) {
+        fGpu->disableScissor();
+        this->setGpuStencil();
         return true;
     }
 
     GrRenderTarget* rt = drawState->getRenderTarget();
-
     // GrDrawTarget should have filtered this for us
     GrAssert(NULL != rt);
 
+    GrIRect bounds;
+    GrIRect rtRect;
+    rtRect.setLTRB(0, 0, rt->width(), rt->height());
+    if (clipIn.hasConservativeBounds()) {
+        GrRect softBounds = clipIn.getConservativeBounds();
+        softBounds.roundOut(&bounds);
+        if (!bounds.intersect(rtRect)) {
+            bounds.setEmpty();
+        }
+        if (bounds.isEmpty()) {
+            return false;
+        }
+    } else {
+        bounds = rtRect;
+    }
+
 #if GR_SW_CLIP
     // If MSAA is enabled we can do everything in the stencil buffer.
     // Otherwise check if we should just create the entire clip mask 
     // in software (this will only happen if the clip mask is anti-aliased
     // and too complex for the gpu to handle in its entirety)
-    if (0 == rt->numSamples() && useSWOnlyPath(gpu, clipIn)) {
+    if (0 == rt->numSamples() && this->useSWOnlyPath(clipIn)) {
         // The clip geometry is complex enough that it will be more
         // efficient to create it entirely in software
         GrTexture* result = NULL;
         GrIRect bound;
-        if (this->createSoftwareClipMask(fGpu, clipIn, &result, &bound)) {
+        if (this->createSoftwareClipMask(clipIn, &result, &bound)) {
             setup_drawstate_aaclip(fGpu, result, bound);
+            fGpu->disableScissor();
+            this->setGpuStencil();
             return true;
         }
 
@@ -162,8 +166,10 @@
         // path does (see scissorSettings below)
         GrTexture* result = NULL;
         GrIRect bound;
-        if (this->createAlphaClipMask(fGpu, clipIn, &result, &bound)) {
+        if (this->createAlphaClipMask(clipIn, &result, &bound)) {
             setup_drawstate_aaclip(fGpu, result, bound);
+            fGpu->disableScissor();
+            this->setGpuStencil();
             return true;
         }
 
@@ -181,36 +187,27 @@
     // AA cache.
     fAACache.reset();
 
-    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;
+    // If the clip is a rectangle then just set the scissor. Otherwise, create
+    // a stencil mask.
+    if (clipIn.isRect()) {
+        fGpu->enableScissor(bounds);
+        this->setGpuStencil();
+        return true;
     }
 
-    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.
     bool useStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
                       !bounds.isEmpty();
 
     if (useStencil) {
-        return this->createStencilClipMask(clipIn, bounds, scissorSettings);
+        this->createStencilClipMask(clipIn, bounds);
     }
-
+    // This must occur after createStencilClipMask. That function may change
+    // the scissor. Also, it only guarantees that the stencil mask is correct
+    // within the bounds it was passed, so we must use both stencil and scissor
+    // test to the bounds for the final draw.
+    fGpu->enableScissor(bounds);
+    this->setGpuStencil();
     return true;
 }
 
@@ -663,8 +660,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Create a 1-bit clip mask in the stencil buffer
 bool GrClipMaskManager::createStencilClipMask(const GrClip& clipIn,
-                                              const GrRect& bounds,
-                                              ScissoringSettings* scissorSettings) {
+                                              const GrIRect& bounds) {
 
     GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
 
@@ -696,7 +692,6 @@
         drawState->setRenderTarget(rt);
         GrDrawTarget::AutoGeometryPush agp(fGpu);
 
-        fGpu->disableScissor();
 #if !VISUALIZE_COMPLEX_CLIP
         drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
 #endif
@@ -716,7 +711,7 @@
                                                     &clearToInside,
                                                     &startOp);
 
-        fGpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
+        fGpu->clearStencilClip(bounds, clearToInside);
 
         // walk through each clip element and perform its set op
         // with the existing clip.
@@ -814,7 +809,12 @@
                     }
                 } else {
                     SET_RANDOM_COLOR
-                    fGpu->drawSimpleRect(bounds, NULL, 0);
+                    GrRect rect = GrRect::MakeLTRB(
+                            SkIntToScalar(bounds.fLeft),
+                            SkIntToScalar(bounds.fTop),
+                            SkIntToScalar(bounds.fRight),
+                            SkIntToScalar(bounds.fBottom));
+                    fGpu->drawSimpleRect(rect, NULL, 0);
                 }
             }
         }
@@ -863,60 +863,162 @@
     }
 };
 
-GrStencilFunc GrClipMaskManager::adjustStencilParams(GrStencilFunc func,
-                                                     StencilClipMode mode,
-                                                     unsigned int stencilBitCnt,
-                                                     unsigned int* ref,
-                                                     unsigned int* mask,
-                                                     unsigned int* writeMask) {
+namespace {
+// Sets the settings to clip against the stencil buffer clip while ignoring the
+// client bits.
+const GrStencilSettings& basic_apply_stencil_clip_settings() {
+    // stencil settings to use when clip is in stencil
+    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
+        kKeep_StencilOp,
+        kKeep_StencilOp,
+        kAlwaysIfInClip_StencilFunc,
+        0x0000,
+        0x0000,
+        0x0000);    
+    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
+}
+}
+
+void GrClipMaskManager::setGpuStencil() {
+    // We make two copies of the StencilSettings here (except in the early
+    // exit scenario. One copy from draw state to the stack var. Then another
+    // from the stack var to the gpu. We could make this class hold a ptr to
+    // GrGpu's fStencilSettings and eliminate the stack copy here.
+
+    const GrDrawState& drawState = fGpu->getDrawState();
+
+    // use stencil for clipping if clipping is enabled and the clip
+    // has been written into the stencil.
+    GrClipMaskManager::StencilClipMode clipMode;
+    if (this->isClipInStencil() && drawState.isClipState()) {
+        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
+        // We can't be modifying the clip and respecting it at the same time.
+        GrAssert(!drawState.isStateFlagEnabled(
+                    GrGpu::kModifyStencilClip_StateBit));
+    } else if (drawState.isStateFlagEnabled(
+                    GrGpu::kModifyStencilClip_StateBit)) {
+        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
+    } else {
+        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
+    }
+
+    GrStencilSettings settings;
+    // The GrGpu client may not be using the stencil buffer but we may need to
+    // enable it in order to respect a stencil clip.
+    if (drawState.getStencil().isDisabled()) {
+        if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
+            settings = basic_apply_stencil_clip_settings();
+        } else {
+            fGpu->disableStencil();
+            return;
+        }
+    } else {
+        settings = drawState.getStencil();
+    }
+
+    // TODO: dynamically attach a stencil buffer
+    int stencilBits = 0;
+    GrStencilBuffer* stencilBuffer = 
+        drawState.getRenderTarget()->getStencilBuffer();
+    if (NULL != stencilBuffer) {
+        stencilBits = stencilBuffer->bits();
+    }
+
+#if GR_DEBUG
+    if (!fGpu->getCaps().fStencilWrapOpsSupport) {
+        GrAssert(settings.frontPassOp() != kIncWrap_StencilOp);
+        GrAssert(settings.frontPassOp() != kDecWrap_StencilOp);
+        GrAssert(settings.frontFailOp() != kIncWrap_StencilOp);
+        GrAssert(settings.backFailOp() != kDecWrap_StencilOp);
+        GrAssert(settings.backPassOp() != kIncWrap_StencilOp);
+        GrAssert(settings.backPassOp() != kDecWrap_StencilOp);
+        GrAssert(settings.backFailOp() != kIncWrap_StencilOp);
+        GrAssert(settings.frontFailOp() != kDecWrap_StencilOp);
+    }
+#endif
+    this->adjustStencilParams(&settings, clipMode, stencilBits);
+    fGpu->setStencilSettings(settings);
+}
+
+void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
+                                            StencilClipMode mode,
+                                            int stencilBitCnt) {
     GrAssert(stencilBitCnt > 0);
-    GrAssert((unsigned) func < kStencilFuncCount);
 
     if (kModifyClip_StencilClipMode == mode) {
-        // We assume that this class is the client/draw-caller of the GrGpu and
-        // has already setup the correct values
-        return func;
+        // We assume that this clip manager itself is drawing to the GrGpu and
+        // has already setup the correct values.
+        return;
     }
+
     unsigned int clipBit = (1 << (stencilBitCnt - 1));
     unsigned int userBits = clipBit - 1;
 
-    *writeMask &= userBits;
+    GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
+    bool twoSided = fGpu->getCaps().fTwoSidedStencilSupport;
 
-    if (func >= kBasicStencilFuncCount) {
-        int respectClip = kRespectClip_StencilClipMode == mode;
-        if (respectClip) {
-            // The GrGpu class should have checked this
-            GrAssert(this->isClipInStencil());
-            switch (func) {
-                case kAlwaysIfInClip_StencilFunc:
-                    *mask = clipBit;
-                    *ref = clipBit;
-                    break;
-                case kEqualIfInClip_StencilFunc:
-                case kLessIfInClip_StencilFunc:
-                case kLEqualIfInClip_StencilFunc:
-                    *mask = (*mask & userBits) | clipBit;
-                    *ref = (*ref & userBits) | clipBit;
-                    break;
-                case kNonZeroIfInClip_StencilFunc:
-                    *mask = (*mask & userBits) | clipBit;
-                    *ref = clipBit;
-                    break;
-                default:
-                    GrCrash("Unknown stencil func");
+    bool finished = false;
+    while (!finished) {
+        GrStencilFunc func = settings->func(face);
+        uint16_t writeMask = settings->writeMask(face);
+        uint16_t funcMask = settings->funcMask(face);
+        uint16_t funcRef = settings->funcRef(face);
+
+        GrAssert((unsigned) func < kStencilFuncCount);
+
+        writeMask &= userBits;
+
+        if (func >= kBasicStencilFuncCount) {
+            int respectClip = kRespectClip_StencilClipMode == mode;
+            if (respectClip) {
+                // The GrGpu class should have checked this
+                GrAssert(this->isClipInStencil());
+                switch (func) {
+                    case kAlwaysIfInClip_StencilFunc:
+                        funcMask = clipBit;
+                        funcRef = clipBit;
+                        break;
+                    case kEqualIfInClip_StencilFunc:
+                    case kLessIfInClip_StencilFunc:
+                    case kLEqualIfInClip_StencilFunc:
+                        funcMask = (funcMask & userBits) | clipBit;
+                        funcRef  = (funcRef  & userBits) | clipBit;
+                        break;
+                    case kNonZeroIfInClip_StencilFunc:
+                        funcMask = (funcMask & userBits) | clipBit;
+                        funcRef = clipBit;
+                        break;
+                    default:
+                        GrCrash("Unknown stencil func");
+                }
+            } else {
+                funcMask &= userBits;
+                funcRef &= userBits;
             }
+            const GrStencilFunc* table = 
+                gSpecialToBasicStencilFunc[respectClip];
+            func = table[func - kBasicStencilFuncCount];
+            GrAssert(func >= 0 && func < kBasicStencilFuncCount);
         } else {
-            *mask &= userBits;
-            *ref &= userBits;
+            funcMask &= userBits;
+            funcRef &= userBits;
         }
-        const GrStencilFunc* table =  gSpecialToBasicStencilFunc[respectClip];
-        func = table[func - kBasicStencilFuncCount];
-        GrAssert(func >= 0 && func < kBasicStencilFuncCount);
-    } else {
-        *mask &= userBits;
-        *ref &= userBits;
+
+        settings->setFunc(face, func);
+        settings->setWriteMask(face, writeMask);
+        settings->setFuncMask(face, funcMask);
+        settings->setFuncRef(face, funcRef);
+
+        if (GrStencilSettings::kFront_Face == face) {
+            face = GrStencilSettings::kBack_Face;
+            finished = !twoSided;
+        } else {
+            finished = true;
+        }
     }
-    return func;
+    if (!twoSided) {
+        settings->copyFrontSettingsToBack();
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 1ceee16..144c042 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -28,19 +28,6 @@
 class GrDrawState;
 
 /**
- * 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 stencil buffer stores the last clip path - providing a single entry
  * "cache". This class provides similar functionality for AA clip paths
  */
@@ -288,8 +275,12 @@
         , fCurrClipMaskType(kNone_ClipMaskType) {
     }
 
-    bool createClipMask(const GrClip& clip, 
-                        ScissoringSettings* scissorSettings);
+    /**
+     * Creates a clip mask if necessary as a stencil buffer or alpha texture
+     * and sets the GrGpu's scissor and stencil state. If the return is false
+     * then the draw can be skipped.
+     */
+    bool setupClipping(const GrClip& clip);
 
     void releaseResources();
 
@@ -325,6 +316,7 @@
         return fAACache.getContext();
     }
 
+private:
     /**
      * Informs the helper function adjustStencilParams() about how the stencil
      * buffer clip is being used.
@@ -339,21 +331,6 @@
         kIgnoreClip_StencilClipMode,
     };
 
-    /**
-     * The stencil func, mask, and reference value are specified by GrGpu's
-     * caller but the actual values passed to the API may have to be adjusted
-     * due to the stencil buffer simultaneously being used for clipping. This
-     * function should be called even when clipping is disabled in order to
-     * prevent the clip from being accidentally overwritten.
-     */
-    GrStencilFunc adjustStencilParams(GrStencilFunc,
-                                      StencilClipMode mode,
-                                      unsigned int stencilBitCnt,
-                                      unsigned int* ref,
-                                      unsigned int* mask,
-                                      unsigned int* writeMask);
-
-private:
     GrGpu* fGpu;
 
     /**
@@ -369,9 +346,8 @@
     
     GrClipMaskCache fAACache;       // cache for the AA path
 
-    bool createStencilClipMask(const GrClip& clip, 
-                               const GrRect& bounds,
-                               ScissoringSettings* scissorSettings);
+    bool createStencilClipMask(const GrClip& clip,
+                               const GrIRect& bounds);
     bool createAlphaClipMask(const GrClip& clipIn,
                              GrTexture** result,
                              GrIRect *resultBounds);
@@ -396,6 +372,21 @@
     void setupCache(const GrClip& clip, 
                     const GrIRect& bounds);
 
+    /**
+     * Called prior to return control back the GrGpu in setupClipping. It
+     * updates the GrGpu with stencil settings that account stencil-based
+     * clipping.
+     */
+    void setGpuStencil();
+
+    /**
+     * Adjusts the stencil settings to account for interaction with stencil
+     * clipping.
+     */
+    void adjustStencilParams(GrStencilSettings* settings,
+                             StencilClipMode mode,
+                             int stencilBitCnt);
+
     typedef GrNoncopyable INHERITED;
 };
 
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 6e5bc67..7bd3307 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -16,6 +16,7 @@
 #include "GrIndexBuffer.h"
 #include "GrMatrix.h"
 #include "GrRefCnt.h"
+#include "GrTemplates.h"
 
 #include "SkXfermode.h"
 #include "SkTLazy.h"
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index c8c983c..132d2ed 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -351,34 +351,16 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-const GrStencilSettings* GrGpu::GetClipStencilSettings(void) {
-    // stencil settings to use when clip is in stencil
-    GR_STATIC_CONST_SAME_STENCIL_STRUCT(sClipStencilSettings,
-        kKeep_StencilOp,
-        kKeep_StencilOp,
-        kAlwaysIfInClip_StencilFunc,
-        0x0000,
-        0x0000,
-        0x0000);
-    return GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&sClipStencilSettings);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 bool GrGpu::setupClipAndFlushState(DrawType type) {
 
-    ScissoringSettings scissoringSettings;
-
-    if (!fClipMaskManager.createClipMask(fClip, &scissoringSettings)) {
+    if (!fClipMaskManager.setupClipping(fClip)) {
         return false;
     }
 
-    // Must flush the scissor after graphics state
     if (!this->flushGraphicsState(type)) {
         return false;
     }
 
-    scissoringSettings.setupScissoring(this);
     return true;
 }
 
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index edbad34..53c7424 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -323,8 +323,29 @@
         return fConfigRenderSupport[config];
     }
 
-    virtual void enableScissoring(const GrIRect& rect) = 0;
-    virtual void disableScissor() = 0;
+    /**
+     * These methods are called by the clip manager's setupClipping function
+     * which (called as part of GrGpu's implementation of onDraw* and
+     * onStencilPath member functions.) The GrGpu subclass should flush the
+     * stencil state to the 3D API in its implementation of flushGraphicsState.
+     */
+    void enableScissor(const GrIRect& rect) {
+        fScissorState.fEnabled = true;
+        fScissorState.fRect = rect;
+    }
+    void disableScissor() { fScissorState.fEnabled = false; }
+
+    /**
+     * Like the scissor methods above this is called by setupClipping and
+     * should be flushed by the GrGpu subclass in flushGraphicsState. These
+     * stencil settings should be used in place of those on the GrDrawState.
+     * They have been adjusted to account for any interactions between the
+     * GrDrawState's stencil settings and stencil clipping.
+     */
+    void setStencilSettings(const GrStencilSettings& settings) {
+        fStencilSettings = settings;
+    }
+    void disableStencil() { fStencilSettings.setDisabled(); }
 
     // 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
@@ -385,10 +406,6 @@
                                           unsigned int* ref,
                                           unsigned int* mask);
 
-    // stencil settings to clip drawing when stencil clipping is in effect
-    // and the client isn't using the stencil test.
-    static const GrStencilSettings* GetClipStencilSettings();
-
     GrClipMaskManager           fClipMaskManager;
 
     struct GeometryPoolState {
@@ -402,6 +419,15 @@
         return fGeomPoolStateStack.back(); 
     }
 
+    // The state of the scissor is controlled by the clip manager
+    struct ScissorState {
+        bool    fEnabled;
+        GrIRect fRect;
+    } fScissorState;
+
+    // The final stencil settings to use as determined by the clip manager.
+    GrStencilSettings fStencilSettings;
+
     // Derived classes need access to this so they can fill it out in their
     // constructors
     bool    fConfigRenderSupport[kGrPixelConfigCount];
diff --git a/src/gpu/GrStencil.cpp b/src/gpu/GrStencil.cpp
index ab0e78c..8d7534a 100644
--- a/src/gpu/GrStencil.cpp
+++ b/src/gpu/GrStencil.cpp
@@ -220,12 +220,13 @@
     0x0000            // set clip bit
 );
 
-bool GrStencilSettings::GetClipPasses(SkRegion::Op op, 
-                                      bool canBeDirect,
-                                      unsigned int stencilClipMask,
-                                      bool invertedFill,
-                                      int* numPasses,
-                                      GrStencilSettings settings[kMaxStencilClipPasses]) {
+bool GrStencilSettings::GetClipPasses(
+                            SkRegion::Op op, 
+                            bool canBeDirect,
+                            unsigned int stencilClipMask,
+                            bool invertedFill,
+                            int* numPasses,
+                            GrStencilSettings settings[kMaxStencilClipPasses]) {
     if (canBeDirect && !invertedFill) {
         *numPasses = 0;
         switch (op) {
@@ -249,10 +250,12 @@
                 break;
         }
         if (1 == *numPasses) {
-            settings[0].fFrontFuncRef |= stencilClipMask;
-            settings[0].fFrontWriteMask |= stencilClipMask;
-            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
-            settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+            settings[0].fFuncRefs[kFront_Face]   |= stencilClipMask;
+            settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+            settings[0].fFuncRefs[kBack_Face] =
+                settings[0].fFuncRefs[kFront_Face];
+            settings[0].fWriteMasks[kBack_Face] =
+                settings[0].fWriteMasks[kFront_Face];
             return true;
         }
     }
@@ -262,90 +265,111 @@
         // pass to select either the zeros or nonzeros.
         case SkRegion::kReplace_Op:
             *numPasses= 1;
-            settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
-            settings[0].fFrontFuncMask &= ~stencilClipMask;
-            settings[0].fFrontFuncRef |= stencilClipMask;
-            settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
-            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+            settings[0] = invertedFill ? gInvUserToClipReplace :
+                                         gUserToClipReplace;
+            settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+            settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+            settings[0].fFuncMasks[kBack_Face] =
+                settings[0].fFuncMasks[kFront_Face];
+            settings[0].fFuncRefs[kBack_Face] =
+                settings[0].fFuncRefs[kFront_Face];
             break;
         case SkRegion::kIntersect_Op:
             *numPasses = 1;
             settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
-            settings[0].fFrontFuncRef = stencilClipMask;
-            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+            settings[0].fFuncRefs[kFront_Face] = stencilClipMask;
+            settings[0].fFuncRefs[kBack_Face] =
+                settings[0].fFuncRefs[kFront_Face];
             break;
         case SkRegion::kUnion_Op:
             *numPasses = 2;
             if (invertedFill) {
                 settings[0] = gInvUserToClipUnionPass0;
-                settings[0].fFrontFuncMask &= ~stencilClipMask;
-                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
-                settings[0].fFrontFuncRef |= stencilClipMask;
-                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
-                settings[0].fFrontWriteMask |= stencilClipMask;
-                settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+                settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
+                settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[0].fFuncRefs[kBack_Face] =
+                    settings[0].fFuncRefs[kFront_Face];
+                settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+                settings[0].fWriteMasks[kBack_Face] =
+                    settings[0].fWriteMasks[kFront_Face];
 
                 settings[1] = gInvUserToClipUnionPass1;
-                settings[1].fFrontWriteMask &= ~stencilClipMask;
-                settings[1].fBackWriteMask &= settings[1].fFrontWriteMask;
+                settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask;
+                settings[1].fWriteMasks[kBack_Face] &=
+                    settings[1].fWriteMasks[kFront_Face];
 
             } else {
                 settings[0] = gUserToClipUnionPass0;
-                settings[0].fFrontFuncMask &= ~stencilClipMask;
-                settings[0].fFrontFuncRef |= stencilClipMask;
-                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
-                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+                settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
+                settings[0].fFuncRefs[kBack_Face] =
+                    settings[0].fFuncRefs[kFront_Face];
 
                 settings[1] = gUserToClipUnionPass1;
-                settings[1].fFrontFuncRef |= stencilClipMask;
-                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+                settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[1].fFuncRefs[kBack_Face] =
+                    settings[1].fFuncRefs[kFront_Face];
             }
             break;
         case SkRegion::kXOR_Op:
             *numPasses = 2;
             if (invertedFill) {
                 settings[0] = gInvUserToClipXorPass0;
-                settings[0].fFrontFuncMask &= ~stencilClipMask;
-                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+                settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
 
                 settings[1] = gInvUserToClipXorPass1;
-                settings[1].fFrontFuncRef |= stencilClipMask;
-                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+                settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[1].fFuncRefs[kBack_Face] =
+                    settings[1].fFuncRefs[kFront_Face];
             } else {
                 settings[0] = gUserToClipXorPass0;
-                settings[0].fFrontFuncMask &= ~stencilClipMask;
-                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+                settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
 
                 settings[1] = gUserToClipXorPass1;
-                settings[1].fFrontFuncRef |= stencilClipMask;
-                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+                settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[1].fFuncRefs[kBack_Face] =
+                    settings[1].fFuncRefs[kFront_Face];
             }
             break;
         case SkRegion::kDifference_Op:
             *numPasses = 1;
             settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
-            settings[0].fFrontFuncRef |= stencilClipMask;
-            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+            settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+            settings[0].fFuncRefs[kBack_Face] =
+                settings[0].fFuncRefs[kFront_Face];
             break;
         case SkRegion::kReverseDifference_Op:
             if (invertedFill) {
                 *numPasses = 1;
                 settings[0] = gInvUserToClipRDiff;
-                settings[0].fFrontWriteMask |= stencilClipMask;
-                settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+                settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+                settings[0].fWriteMasks[kBack_Face] =
+                    settings[0].fWriteMasks[kFront_Face];
             } else {
                 *numPasses = 2;
                 settings[0] = gUserToClipRDiffPass0;
-                settings[0].fFrontFuncMask &= ~stencilClipMask;
-                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
-                settings[0].fFrontFuncRef |= stencilClipMask;
-                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+                settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
+                settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[0].fFuncRefs[kBack_Face] =
+                    settings[0].fFuncRefs[kFront_Face];
 
                 settings[1] = gUserToClipRDiffPass1;
-                settings[1].fFrontFuncMask |= stencilClipMask;
-                settings[1].fFrontFuncRef |= stencilClipMask;
-                settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
-                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+                settings[1].fFuncMasks[kFront_Face] |= stencilClipMask;
+                settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[1].fFuncMasks[kBack_Face] =
+                    settings[1].fFuncMasks[kFront_Face];
+                settings[1].fFuncRefs[kBack_Face] =
+                    settings[1].fFuncRefs[kFront_Face];
             }
             break;
         default:
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
index bba5aa6..3a7595a 100644
--- a/src/gpu/GrStencil.h
+++ b/src/gpu/GrStencil.h
@@ -103,20 +103,14 @@
  * GrStencilSettings. (We hang our heads in shame.)
  */
 struct GrStencilSettingsStruct {
-    GrStencilOp fFrontPassOp : 8;    // op to perform when front faces pass
-    GrStencilOp fBackPassOp : 8;     // op to perform when back faces pass
-    GrStencilOp fFrontFailOp : 8;    // op to perform when front faces fail
-    GrStencilOp fBackFailOp : 8;     // op to perform when back faces fail
-    GrStencilFunc fFrontFunc : 8;    // test function for front faces
-    GrStencilFunc fBackFunc : 8;     // test function for back faces
-    int fPad0 : 8;
-    int fPad1 : 8;
-    unsigned short fFrontFuncMask;   // mask for front face test
-    unsigned short fBackFuncMask;    // mask for back face test
-    unsigned short fFrontFuncRef;    // reference value for front face test
-    unsigned short fBackFuncRef;     // reference value for back face test
-    unsigned short fFrontWriteMask;  // stencil write mask for front faces
-    unsigned short fBackWriteMask;   // stencil write mask for back faces
+    uint8_t fPassOps[2];     // op to perform when faces pass (GrStencilOp)
+    uint8_t fFailOps[2];     // op to perform when faces fail (GrStencilOp)
+    uint8_t fFuncs[2];       // test function for faces (GrStencilFunc)
+    uint8_t fPad0;
+    uint8_t fPad1;
+    uint16_t fFuncMasks[2];  // mask for face tests
+    uint16_t fFuncRefs[2];   // reference values for face tests
+    uint16_t fWriteMasks[2]; // stencil write masks
     mutable uint32_t fFlags;
 };
 // We rely on this being packed and aligned (memcmp'ed and memcpy'ed)
@@ -125,9 +119,9 @@
                  4*sizeof(uint8_t) + // ops
                  2*sizeof(uint8_t) + // funcs
                  2*sizeof(uint8_t) + // pads
-                 2*sizeof(unsigned short) + // func masks
-                 2*sizeof(unsigned short) + // ref values
-                 2*sizeof(unsigned short) + // write masks
+                 2*sizeof(uint16_t) + // func masks
+                 2*sizeof(uint16_t) + // ref values
+                 2*sizeof(uint16_t) + // write masks
                  sizeof(uint32_t)); // flags
 
 // This macro is used to compute the GrStencilSettingsStructs flags
@@ -175,36 +169,65 @@
 class GrStencilSettings : private GrStencilSettingsStruct {
 
 public:
+    enum Face {
+        kFront_Face = 0,
+        kBack_Face  = 1,
+    };
+
     GrStencilSettings() {
         fPad0 = fPad1 = 0;
         this->setDisabled();
     }
     
-    GrStencilOp frontPassOp() const { return fFrontPassOp; }
-    GrStencilOp backPassOp() const { return fBackPassOp; }
-    GrStencilOp frontFailOp() const { return fFrontFailOp; }
-    GrStencilOp backFailOp() const { return fBackFailOp; }
-    GrStencilFunc frontFunc() const { return fFrontFunc; }
-    GrStencilFunc backFunc() const { return fBackFunc; }
-    unsigned short frontFuncMask() const { return fFrontFuncMask; }
-    unsigned short backFuncMask() const { return fBackFuncMask; }
-    unsigned short frontFuncRef() const { return fFrontFuncRef; }
-    unsigned short backFuncRef() const { return fBackFuncRef; }
-    unsigned short frontWriteMask() const {return fFrontWriteMask; }
-    unsigned short backWriteMask() const { return fBackWriteMask; }
+    GrStencilOp frontPassOp() const { return static_cast<GrStencilOp>(fPassOps[kFront_Face]); }
+    GrStencilOp backPassOp() const  { return static_cast<GrStencilOp>(fPassOps[kBack_Face]); }
+    GrStencilOp frontFailOp() const { return static_cast<GrStencilOp>(fFailOps[kFront_Face]); }
+    GrStencilOp backFailOp() const  { return static_cast<GrStencilOp>(fFailOps[kBack_Face]); }
+    GrStencilFunc frontFunc() const { return static_cast<GrStencilFunc>(fFuncs[kFront_Face]); }
+    GrStencilFunc backFunc() const  { return static_cast<GrStencilFunc>(fFuncs[kBack_Face]); }
+    uint16_t frontFuncMask() const  { return fFuncMasks[kFront_Face]; }
+    uint16_t backFuncMask() const   { return fFuncMasks[kBack_Face]; }
+    uint16_t frontFuncRef() const   { return fFuncRefs[kFront_Face]; }
+    uint16_t backFuncRef() const    { return fFuncRefs[kBack_Face]; }
+    uint16_t frontWriteMask() const { return fWriteMasks[kFront_Face]; }
+    uint16_t backWriteMask() const  { return fWriteMasks[kFront_Face]; }
 
-    void setFrontPassOp(GrStencilOp op) { fFrontPassOp = op; fFlags = 0;}
-    void setBackPassOp(GrStencilOp op) { fBackPassOp = op; fFlags = 0;}
-    void setFrontFailOp(GrStencilOp op) {fFrontFailOp = op; fFlags = 0;}
-    void setBackFailOp(GrStencilOp op) { fBackFailOp = op; fFlags = 0;}
-    void setFrontFunc(GrStencilFunc func) { fFrontFunc = func; fFlags = 0;}
-    void setBackFunc(GrStencilFunc func) { fBackFunc = func; fFlags = 0;}
-    void setFrontFuncMask(unsigned short mask) { fFrontFuncMask = mask; }
-    void setBackFuncMask(unsigned short mask) { fBackFuncMask = mask; }
-    void setFrontFuncRef(unsigned short ref) { fFrontFuncRef = ref; }
-    void setBackFuncRef(unsigned short ref) { fBackFuncRef = ref; }
-    void setFrontWriteMask(unsigned short writeMask) { fFrontWriteMask = writeMask; }
-    void setBackWriteMask(unsigned short writeMask) { fBackWriteMask = writeMask; }
+    GrStencilOp passOp(Face f) const { return static_cast<GrStencilOp>(fPassOps[f]); }
+    GrStencilOp failOp(Face f) const { return static_cast<GrStencilOp>(fFailOps[f]); }
+    GrStencilFunc func(Face f) const { return static_cast<GrStencilFunc>(fFuncs[f]); }
+    uint16_t funcMask(Face f) const  { return fFuncMasks[f]; }
+    uint16_t funcRef(Face f) const   { return fFuncRefs[f]; }
+    uint16_t writeMask(Face f) const { return fWriteMasks[f]; }
+
+    void setFrontPassOp(GrStencilOp op) { fPassOps[kFront_Face] = op; fFlags = 0;}
+    void setBackPassOp(GrStencilOp op)  { fPassOps[kBack_Face]  = op; fFlags = 0;}
+    void setFrontFailOp(GrStencilOp op) { fFailOps[kFront_Face] = op; fFlags = 0;}
+    void setBackFailOp(GrStencilOp op)  { fFailOps[kBack_Face]  = op; fFlags = 0;}
+    void setFrontFunc(GrStencilFunc func) { fFuncs[kFront_Face] = func; fFlags = 0;}
+    void setBackFunc(GrStencilFunc func)  { fFuncs[kBack_Face]  = func; fFlags = 0;}
+    void setFrontFuncMask(unsigned short mask) { fFuncMasks[kFront_Face] = mask; }
+    void setBackFuncMask(unsigned short mask)  { fFuncMasks[kBack_Face]  = mask; }
+    void setFrontFuncRef(unsigned short ref) { fFuncRefs[kFront_Face] = ref; }
+    void setBackFuncRef(unsigned short ref)  { fFuncRefs[kBack_Face]  = ref; }
+    void setFrontWriteMask(unsigned short writeMask) { fWriteMasks[kFront_Face] = writeMask; }
+    void setBackWriteMask(unsigned short writeMask)  { fWriteMasks[kBack_Face]  = writeMask; }
+
+    void setPassOp(Face f, GrStencilOp op) { fPassOps[f] = op; fFlags = 0;}
+    void setFailOp(Face f, GrStencilOp op) { fFailOps[f] = op; fFlags = 0;}
+    void setFunc(Face f, GrStencilFunc func) { fFuncs[f] = func; fFlags = 0;}
+    void setFuncMask(Face f, unsigned short mask) { fFuncMasks[f] = mask; }
+    void setFuncRef(Face f, unsigned short ref) { fFuncRefs[f] = ref; }
+    void setWriteMask(Face f, unsigned short writeMask) { fWriteMasks[f] = writeMask; }
+
+    void copyFrontSettingsToBack() {
+        fPassOps[kBack_Face]    = fPassOps[kFront_Face];
+        fFailOps[kBack_Face]    = fFailOps[kFront_Face];
+        fFuncs[kBack_Face]      = fFuncs[kFront_Face];
+        fFuncMasks[kBack_Face]  = fFuncMasks[kFront_Face];
+        fFuncRefs[kBack_Face]   = fFuncRefs[kFront_Face];
+        fWriteMasks[kBack_Face] = fWriteMasks[kFront_Face];
+        fFlags = 0;
+    }
 
     void setSame(GrStencilOp passOp,
                  GrStencilOp failOp,
@@ -212,18 +235,12 @@
                  unsigned short funcMask,
                  unsigned short funcRef,
                  unsigned short writeMask) {
-        fFrontPassOp        = passOp;
-        fBackPassOp         = passOp;
-        fFrontFailOp        = failOp;
-        fBackFailOp         = failOp;
-        fFrontFunc          = func;
-        fBackFunc           = func;
-        fFrontFuncMask      = funcMask;
-        fBackFuncMask       = funcMask;
-        fFrontFuncRef       = funcRef;
-        fBackFuncRef        = funcRef;
-        fFrontWriteMask     = writeMask;
-        fBackWriteMask      = writeMask;
+        fPassOps[kFront_Face]    = fPassOps[kBack_Face]    = passOp;
+        fFailOps[kFront_Face]    = fFailOps[kBack_Face]    = failOp;
+        fFuncs[kFront_Face]      = fFuncs[kBack_Face]      = func;
+        fFuncMasks[kFront_Face]  = fFuncMasks[kBack_Face]  = funcMask;
+        fFuncRefs[kFront_Face]   = fFuncRefs[kBack_Face]   = funcRef;
+        fWriteMasks[kFront_Face] = fWriteMasks[kBack_Face] = writeMask;
         fFlags = 0;
     }
 
@@ -242,9 +259,9 @@
             return false;
         }
         bool disabled = GR_STENCIL_SETTINGS_IS_DISABLED(
-                            fFrontPassOp, fBackPassOp,
-                            fFrontFailOp, fBackFailOp,
-                            fFrontFunc ,fBackFunc);
+                            fPassOps[kFront_Face], fPassOps[kBack_Face],
+                            fFailOps[kFront_Face], fFailOps[kBack_Face],
+                            fFuncs[kFront_Face],   fFuncs[kBack_Face]);
         fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag;
         return disabled;
     }
@@ -257,16 +274,16 @@
             return false;
         }
         bool writes = GR_STENCIL_SETTINGS_DOES_WRITE(
-                        fFrontPassOp, fBackPassOp,
-                        fFrontFailOp, fBackFailOp,
-                        fFrontFunc, fBackFunc);
+                            fPassOps[kFront_Face], fPassOps[kBack_Face],
+                            fFailOps[kFront_Face], fFailOps[kBack_Face],
+                            fFuncs[kFront_Face],   fFuncs[kBack_Face]);
         fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag;
         return writes;
     }
     
     void invalidate()  {
         // write an illegal value to the first member
-        fFrontPassOp = (GrStencilOp)(uint8_t)-1;
+        fPassOps[0] = (GrStencilOp)(uint8_t)-1;
         fFlags = 0;
     }
 
@@ -339,13 +356,13 @@
     FRONT_REF,        BACK_REF,                                              \
     FRONT_WRITE_MASK, BACK_WRITE_MASK)                                       \
     static const GrStencilSettingsStruct STRUCT_NAME = {                     \
-        (FRONT_PASS_OP),    (BACK_PASS_OP),                                  \
-        (FRONT_FAIL_OP),    (BACK_FAIL_OP),                                  \
-        (FRONT_FUNC),       (BACK_FUNC),                                     \
+       {(FRONT_PASS_OP),    (BACK_PASS_OP)   },                              \
+       {(FRONT_FAIL_OP),    (BACK_FAIL_OP)   },                              \
+       {(FRONT_FUNC),       (BACK_FUNC)      },                              \
         (0),                (0),                                             \
-        (FRONT_MASK),       (BACK_MASK),                                     \
-        (FRONT_REF),        (BACK_REF),                                      \
-        (FRONT_WRITE_MASK), (BACK_WRITE_MASK),                               \
+       {(FRONT_MASK),       (BACK_MASK)      },                              \
+       {(FRONT_REF),        (BACK_REF)       },                              \
+       {(FRONT_WRITE_MASK), (BACK_WRITE_MASK)},                              \
         GR_STENCIL_SETTINGS_DEFAULT_FLAGS(                                   \
             FRONT_PASS_OP, BACK_PASS_OP, FRONT_FAIL_OP, BACK_FAIL_OP,        \
             FRONT_FUNC, BACK_FUNC)                                           \
diff --git a/src/gpu/SkGrFontScaler.cpp b/src/gpu/SkGrFontScaler.cpp
index d2e099b..430b599 100644
--- a/src/gpu/SkGrFontScaler.cpp
+++ b/src/gpu/SkGrFontScaler.cpp
@@ -7,7 +7,7 @@
  */
 
 
-
+#include "GrTemplates.h"
 #include "SkGr.h"
 #include "SkDescriptor.h"
 #include "SkGlyphCache.h"
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 5c1764c..76a7a63 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -9,6 +9,7 @@
 #include "GrGpuGL.h"
 #include "GrGLStencilBuffer.h"
 #include "GrGLPath.h"
+#include "GrTemplates.h"
 #include "GrTypes.h"
 #include "SkTemplates.h"
 
@@ -496,21 +497,16 @@
         fHWBoundTextures[s] = NULL;
     }
 
-    fHWBounds.fScissorRect.invalidate();
-    // set to true to force disableScissor to make a GL call.
-    fHWBounds.fScissorEnabled = true;
-    this->disableScissor();
+    fHWScissorSettings.invalidate();
 
-    fHWBounds.fViewportRect.invalidate();
+    fHWViewport.invalidate();
 
     fHWStencilSettings.invalidate();
-    // This is arbitrary. The above invalidate ensures a full setup of the
-    // stencil on the next draw.
-    fHWStencilClipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
+    fHWStencilTestEnabled = kUnknown_TriState;
 
     fHWGeometryState.fIndexBuffer = NULL;
     fHWGeometryState.fVertexBuffer = NULL;
-    
+
     fHWGeometryState.fArrayPtrsDirty = true;
 
     fHWBoundRenderTarget = NULL;
@@ -1333,7 +1329,7 @@
     return path;
 }
 
-void GrGpuGL::enableScissoring(const GrIRect& rect) {
+void GrGpuGL::flushScissor() {
     const GrDrawState& drawState = this->getDrawState();
     const GrGLRenderTarget* rt =
         static_cast<const GrGLRenderTarget*>(drawState.getRenderTarget());
@@ -1341,28 +1337,31 @@
     GrAssert(NULL != rt);
     const GrGLIRect& vp = rt->getViewport();
 
-    GrGLIRect scissor;
-    scissor.setRelativeTo(vp, rect.fLeft, rect.fTop,
-                          rect.width(), rect.height());
-    if (scissor.contains(vp)) {
-        disableScissor();
-        return;
+    if (fScissorState.fEnabled) {
+        GrGLIRect scissor;
+        scissor.setRelativeTo(vp,
+                              fScissorState.fRect.fLeft,
+                              fScissorState.fRect.fTop,
+                              fScissorState.fRect.width(),
+                              fScissorState.fRect.height());
+        // if the scissor fully contains the viewport then we fall through and
+        // disable the scissor test.
+        if (!scissor.contains(vp)) {
+            if (fHWScissorSettings.fRect != scissor) {
+                scissor.pushToGLScissor(this->glInterface());
+                fHWScissorSettings.fRect = scissor;
+            }
+            if (kYes_TriState != fHWScissorSettings.fEnabled) {
+                GL_CALL(Enable(GR_GL_SCISSOR_TEST));
+                fHWScissorSettings.fEnabled = kYes_TriState;
+            }
+            return;
+        }
     }
-
-    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) {
+    if (kNo_TriState != fHWScissorSettings.fEnabled) {
         GL_CALL(Disable(GR_GL_SCISSOR_TEST));
-        fHWBounds.fScissorEnabled = false;
+        fHWScissorSettings.fEnabled = kNo_TriState;
+        return;
     }
 }
 
@@ -1384,10 +1383,12 @@
         }
     }
     this->flushRenderTarget(rect);
-    if (NULL != rect)
-        this->enableScissoring(*rect);
-    else
-        this->disableScissor();
+    GrAutoTRestore<ScissorState> asr(&fScissorState);
+    fScissorState.fEnabled = (NULL != rect);
+    if (fScissorState.fEnabled) {
+        fScissorState.fRect = *rect;
+    }
+    this->flushScissor();
 
     GrGLfloat r, g, b, a;
     static const GrGLfloat scale255 = 1.f / 255.f;
@@ -1413,7 +1414,9 @@
     
     this->flushRenderTarget(&GrIRect::EmptyIRect());
 
-    this->disableScissor();
+    GrAutoTRestore<ScissorState> asr(&fScissorState);
+    fScissorState.fEnabled = false;
+    this->flushScissor();
 
     GL_CALL(StencilMask(0xffffffff));
     GL_CALL(ClearStencil(0));
@@ -1448,7 +1451,12 @@
         value = 0;
     }
     this->flushRenderTarget(&GrIRect::EmptyIRect());
-    this->enableScissoring(rect);
+
+    GrAutoTRestore<ScissorState> asr(&fScissorState);
+    fScissorState.fEnabled = true;
+    fScissorState.fRect = rect;
+    this->flushScissor();
+
     GL_CALL(StencilMask((uint32_t) clipStencilMask));
     GL_CALL(ClearStencil(value));
     GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
@@ -1625,9 +1633,9 @@
     #endif
         fHWBoundRenderTarget = rt;
         const GrGLIRect& vp = rt->getViewport();
-        if (fHWBounds.fViewportRect != vp) {
+        if (fHWViewport != vp) {
             vp.pushToGLViewport(this->glInterface());
-            fHWBounds.fViewportRect = vp;
+            fHWViewport = vp;
         }
     }
     if (NULL == bound || !bound->isEmpty()) {
@@ -1747,28 +1755,25 @@
         const GrGLIRect& vp = rt->getViewport();
         const GrIRect dirtyRect = rt->getResolveRect();
         GrGLIRect r;
-        r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, 
+        r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
                         dirtyRect.width(), dirtyRect.height());
 
+        GrAutoTRestore<ScissorState> asr;
         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));
+            asr.reset(&fScissorState);
+            fScissorState.fEnabled = true;
+            fScissorState.fRect = dirtyRect;
+            this->flushScissor();
             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->disableScissor();
+                asr.reset(&fScissorState);
+                fScissorState.fEnabled = false;
+                this->flushScissor();
             }
             int right = r.fLeft + r.fWidth;
             int top = r.fBottom + r.fHeight;
@@ -1832,16 +1837,16 @@
 }
 
 void set_gl_stencil(const GrGLInterface* gl,
+                    const GrStencilSettings& settings,
                     GrGLenum glFace,
-                    GrStencilFunc func,
-                    GrStencilOp failOp,
-                    GrStencilOp passOp,
-                    unsigned int ref,
-                    unsigned int mask,
-                    unsigned int writeMask) {
-    GrGLenum glFunc = gr_to_gl_stencil_func(func);
-    GrGLenum glFailOp = gr_to_gl_stencil_op(failOp);
-    GrGLenum glPassOp = gr_to_gl_stencil_op(passOp);
+                    GrStencilSettings::Face grFace) {
+    GrGLenum glFunc = gr_to_gl_stencil_func(settings.func(grFace));
+    GrGLenum glFailOp = gr_to_gl_stencil_op(settings.failOp(grFace));
+    GrGLenum glPassOp = gr_to_gl_stencil_op(settings.passOp(grFace));
+
+    GrGLint ref = settings.funcRef(grFace);
+    GrGLint mask = settings.funcMask(grFace);
+    GrGLint writeMask = settings.writeMask(grFace);
 
     if (GR_GL_FRONT_AND_BACK == glFace) {
         // we call the combined func just in case separate stencil is not
@@ -1858,112 +1863,36 @@
 }
 
 void GrGpuGL::flushStencil() {
-    const GrDrawState& drawState = this->getDrawState();
-
-    // use stencil for clipping if clipping is enabled and the clip
-    // has been written into the stencil.
-    GrClipMaskManager::StencilClipMode clipMode;
-    if (fClipMaskManager.isClipInStencil() &&
-        drawState.isClipState()) {
-        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
-        // We can't be modifying the clip and respecting it at the same time.
-        GrAssert(!drawState.isStateFlagEnabled(kModifyStencilClip_StateBit));
-    } else if (drawState.isStateFlagEnabled(kModifyStencilClip_StateBit)) {
-        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
-    } else {
-        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
-    }
-
-    // The caller may not be using the stencil buffer but we may need to enable
-    // it in order to respect a stencil clip.
-    const GrStencilSettings* settings = &drawState.getStencil();
-    if (settings->isDisabled() &&
-        GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
-        settings = GetClipStencilSettings();
-    }
-
-    // TODO: dynamically attach a stencil buffer
-    int stencilBits = 0;
-    GrStencilBuffer* stencilBuffer = 
-        drawState.getRenderTarget()->getStencilBuffer();
-    if (NULL != stencilBuffer) {
-        stencilBits = stencilBuffer->bits();
-    }
-    GrAssert(stencilBits || settings->isDisabled());
-
-    bool updateStencilSettings = stencilBits > 0 &&
-                                 ((fHWStencilSettings != *settings) ||
-                                  (fHWStencilClipMode != clipMode));
-    if (updateStencilSettings) {
-        if (settings->isDisabled()) {
+    if (fStencilSettings.isDisabled()) {
+        if (kNo_TriState != fHWStencilTestEnabled) {
             GL_CALL(Disable(GR_GL_STENCIL_TEST));
-        } else {
+            fHWStencilTestEnabled = kNo_TriState;
+        }
+    } else {
+        if (kYes_TriState != fHWStencilTestEnabled) {
             GL_CALL(Enable(GR_GL_STENCIL_TEST));
-    #if GR_DEBUG
-            if (!this->getCaps().fStencilWrapOpsSupport) {
-                GrAssert(settings->frontPassOp() != kIncWrap_StencilOp);
-                GrAssert(settings->frontPassOp() != kDecWrap_StencilOp);
-                GrAssert(settings->frontFailOp() != kIncWrap_StencilOp);
-                GrAssert(settings->backFailOp() != kDecWrap_StencilOp);
-                GrAssert(settings->backPassOp() != kIncWrap_StencilOp);
-                GrAssert(settings->backPassOp() != kDecWrap_StencilOp);
-                GrAssert(settings->backFailOp() != kIncWrap_StencilOp);
-                GrAssert(settings->frontFailOp() != kDecWrap_StencilOp);
-            }
-    #endif
-
-            unsigned int frontRef  = settings->frontFuncRef();
-            unsigned int frontMask = settings->frontFuncMask();
-            unsigned int frontWriteMask = settings->frontWriteMask();
-
-            GrStencilFunc frontFunc =
-                fClipMaskManager.adjustStencilParams(settings->frontFunc(),
-                                                     clipMode,
-                                                     stencilBits,
-                                                     &frontRef,
-                                                     &frontMask,
-                                                     &frontWriteMask);
+            fHWStencilTestEnabled = kYes_TriState;
+        }
+    }
+    if (fHWStencilSettings != fStencilSettings) {
+        if (!fStencilSettings.isDisabled()) {
             if (this->getCaps().fTwoSidedStencilSupport) {
-                unsigned int backRef  = settings->backFuncRef();
-                unsigned int backMask = settings->backFuncMask();
-                unsigned int backWriteMask = settings->backWriteMask();
-
-                GrStencilFunc backFunc =
-                    fClipMaskManager.adjustStencilParams(settings->frontFunc(),
-                                                         clipMode,
-                                                         stencilBits,
-                                                         &backRef,
-                                                         &backMask,
-                                                         &backWriteMask);
                 set_gl_stencil(this->glInterface(),
+                               fStencilSettings,
                                GR_GL_FRONT,
-                               frontFunc,
-                               settings->frontFailOp(),
-                               settings->frontPassOp(),
-                               frontRef,
-                               frontMask,
-                               frontWriteMask);
+                               GrStencilSettings::kFront_Face);
                 set_gl_stencil(this->glInterface(),
+                               fStencilSettings,
                                GR_GL_BACK,
-                               backFunc,
-                               settings->backFailOp(),
-                               settings->backPassOp(),
-                               backRef,
-                               backMask,
-                               backWriteMask);
+                               GrStencilSettings::kBack_Face);
             } else {
                 set_gl_stencil(this->glInterface(),
+                               fStencilSettings,
                                GR_GL_FRONT_AND_BACK,
-                               frontFunc,
-                               settings->frontFailOp(),
-                               settings->frontPassOp(),
-                               frontRef,
-                               frontMask,
-                               frontWriteMask);
+                               GrStencilSettings::kFront_Face);
             }
         }
-        fHWStencilSettings = *settings;
-        fHWStencilClipMode = clipMode;
+        fHWStencilSettings = fStencilSettings;
     }
 }
 
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 51e49ec..6220efa 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -108,8 +108,6 @@
                                      uint32_t vertexCount,
                                      uint32_t numVertices) SK_OVERRIDE;
     virtual void onGpuStencilPath(const GrPath&, GrPathFill) SK_OVERRIDE;
-    virtual void enableScissoring(const GrIRect& rect) SK_OVERRIDE;
-    virtual void disableScissor() SK_OVERRIDE;
 
     virtual void clearStencil() SK_OVERRIDE;
     virtual void clearStencilClip(const GrIRect& rect,
@@ -206,6 +204,10 @@
     };
 
     // binds the texture and sets its texture params
+    // This may also perform a downsample on the src texture which may or may
+    // not modify the scissor test and rect. So in flushGraphicsState a
+    // call to flushScissor must occur after all textures have been flushed via
+    // this function.
     void flushBoundTextureAndParams(int stage);
 
     // sets the texture matrix and domain for the currently bound program
@@ -232,6 +234,10 @@
     // flushes dithering, color-mask, and face culling stat
     void flushMiscFixedFunctionState();
 
+    // flushes the scissor. see the note on flushBoundTextureAndParams about
+    // flushing the scissor after that function is called.
+    void flushScissor();
+
     static void DeleteProgram(const GrGLInterface* gl,
                               CachedData* programData);
 
@@ -304,19 +310,24 @@
     GrColor                     fHWConstAttribColor;
     GrColor                     fHWConstAttribCoverage;
 
-    // last scissor / viewport scissor state seen by the GL.
-    struct {
-        bool        fScissorEnabled;
-        GrGLIRect   fScissorRect;
-        GrGLIRect   fViewportRect;
-    } fHWBounds;
-
     enum TriState {
         kNo_TriState,
         kYes_TriState,
         kUnknown_TriState
     };
 
+    // last scissor / viewport scissor state seen by the GL.
+    struct {
+        TriState    fEnabled;
+        GrGLIRect   fRect;
+        void invalidate() {
+            fEnabled = kUnknown_TriState;
+            fRect.invalidate();
+        }
+    } fHWScissorSettings;
+
+    GrGLIRect   fHWViewport;
+
     struct {
         size_t                  fVertexOffset;
         GrVertexLayout          fVertexLayout;
@@ -349,8 +360,8 @@
         }
     } fHWAAState;
 
-    GrClipMaskManager::StencilClipMode     fHWStencilClipMode;
-    GrStencilSettings                      fHWStencilSettings;
+    GrStencilSettings       fHWStencilSettings;
+    TriState                fHWStencilTestEnabled;
 
     GrDrawState::DrawFace   fHWDrawFace;
     TriState                fHWWriteToColor;
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index f8d71ff..3ad3520 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -454,6 +454,7 @@
         }
     }
     this->flushColorMatrix();
+    this->flushScissor();
 
     GrIRect* rect = NULL;
     GrIRect clipBounds;