Revert of Separate user and raw stencil settings (patchset #8 id:140001 of https://codereview.chromium.org/1962243002/ )

Reason for revert:
This seems to be breaking nanobench on the Windows bots with:

Caught exception 3221225477 EXCEPTION_ACCESS_VIOLATION
GrDrawTarget::stencilPath +c7
GrStencilAndCoverPathRenderer::onDrawPath +fd
GrDrawContext::internalDrawPath +509
GrDrawContext::drawPath +223
GrBlurUtils::drawPathWithMaskFilter +250
SkGpuDevice::drawPath +2ea
SkCanvas::onDrawPath +2e3
SkRecordDraw +2e6
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkRecordDraw +2e6
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkRecordDraw +261
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkMultiPictureDraw::draw +bf
SKPBench::drawMPDPicture +1e0
SKPBench::onDraw +34
Benchmark::draw +32
time +92
setup_gpu_bench +6e
nanobench_main +77b

Original issue's description:
> Separate user and raw stencil settings
>
> Adds a new GrUserStencilSettings class that describes in abstract terms
> how a draw will use the stencil (e.g. kAlwaysIfInClip, kSetClipBit,
> etc.). GrPipelineBuilder now only defines the GrUserStencilSettings.
> When the GrPipeline is finalized, the user stencil settings are then
> translated into concrete GrStencilSettings.
>
> At this point, GrClipMaskManager only needs to tell the GrAppliedClip
> whether or not there is a stencil clip. It does not need to modify
> stencil settings and GrPipelineBuilder does not need
> AutoRestoreStencil.
>
> This is one step of the stencil overhaul. In the future it will also
> allow us to clean up the special case handling for nvpr and the
> stateful fClipMode member of GrClipMaskManager.
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1962243002
>
> Committed: https://skia.googlesource.com/skia/+/12dbb3947e1aaf205b4fcf13b40e54e50650eb37

TBR=bsalomon@google.com,cdalton@nvidia.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review-Url: https://codereview.chromium.org/1969693003
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index dc16c2c..48f1c85 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -170,10 +170,10 @@
       '<(skia_src_path)/gpu/GrResourceProvider.h',
       '<(skia_src_path)/gpu/GrShape.cpp',
       '<(skia_src_path)/gpu/GrShape.h',
+      '<(skia_src_path)/gpu/GrStencil.cpp',
+      '<(skia_src_path)/gpu/GrStencil.h',
       '<(skia_src_path)/gpu/GrStencilAttachment.cpp',
       '<(skia_src_path)/gpu/GrStencilAttachment.h',
-      '<(skia_src_path)/gpu/GrStencilSettings.cpp',
-      '<(skia_src_path)/gpu/GrStencilSettings.h',
       '<(skia_src_path)/gpu/GrStyle.cpp',
       '<(skia_src_path)/gpu/GrStyle.h',
       '<(skia_src_path)/gpu/GrTessellator.cpp',
@@ -200,7 +200,6 @@
       '<(skia_src_path)/gpu/GrTextureToYUVPlanes.h',
       '<(skia_src_path)/gpu/GrTextureAccess.cpp',
       '<(skia_src_path)/gpu/GrTRecorder.h',
-      '<(skia_src_path)/gpu/GrUserStencilSettings.h',
       '<(skia_src_path)/gpu/GrXferProcessor.cpp',
       '<(skia_src_path)/gpu/GrYUVProvider.cpp',
       '<(skia_src_path)/gpu/GrYUVProvider.h',
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index c7b88ca..56c0ee6 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -62,7 +62,7 @@
 // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set
 // 'prOut' to the non-SW path renderer that will do the job).
 bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
-                                            bool hasUserStencilSettings,
+                                            bool isStencilDisabled,
                                             const GrRenderTarget* rt,
                                             const SkMatrix& viewMatrix,
                                             const Element* element,
@@ -104,7 +104,7 @@
         canDrawArgs.fPath = &path;
         canDrawArgs.fStyle = &GrStyle::SimpleFill();
         canDrawArgs.fAntiAlias = element->isAA();
-        canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
+        canDrawArgs.fIsStencilDisabled = isStencilDisabled;
         canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
 
         // the 'false' parameter disallows use of the SW path renderer
@@ -124,10 +124,10 @@
                                                    const SkMatrix& viewMatrix,
                                                    const SkClipStack::Element* element) {
     GrPathRenderer* pr;
-    constexpr bool kNeedsStencil = true;
-    constexpr bool kHasUserStencilSettings = false;
+    static const bool kNeedsStencil = true;
+    static const bool kStencilIsDisabled = true;
     PathNeedsSWRenderer(context,
-                        kHasUserStencilSettings,
+                        kStencilIsDisabled,
                         texture->asRenderTarget(),
                         viewMatrix,
                         element,
@@ -179,7 +179,7 @@
         bool needsStencil = invert ||
                             SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op;
 
-        if (PathNeedsSWRenderer(context, pipelineBuilder.hasUserStencilSettings(),
+        if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled(),
                                 rt, translate, element, nullptr, needsStencil)) {
             return true;
         }
@@ -317,11 +317,13 @@
 }
 
 bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
+                                         GrPipelineBuilder::AutoRestoreStencil* ars,
                                          const SkIRect& clipScissor,
                                          const SkRect* devBounds,
                                          GrAppliedClip* out) {
-    SkASSERT(kModifyClip_StencilClipMode != fClipMode); // TODO: Remove fClipMode.
-    fClipMode = kIgnoreClip_StencilClipMode;
+    if (kRespectClip_StencilClipMode == fClipMode) {
+        fClipMode = kIgnoreClip_StencilClipMode;
+    }
 
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
 
@@ -338,11 +340,13 @@
 
     if (scissor->contains(clipSpaceRTIBounds)) {
         // This counts as wide open
+        this->setPipelineBuilderStencil(pipelineBuilder, ars);
         return true;
     }
 
     if (clipSpaceRTIBounds.intersect(*scissor)) {
         out->fScissorState.set(clipSpaceRTIBounds);
+        this->setPipelineBuilderStencil(pipelineBuilder, ars);
         return true;
     }
     return false;
@@ -352,6 +356,7 @@
 // sort out what kind of clip mask needs to be created: alpha, stencil,
 // scissor, or entirely software
 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
+                                      GrPipelineBuilder::AutoRestoreStencil* ars,
                                       const SkRect* devBounds,
                                       GrAppliedClip* out) {
     if (kRespectClip_StencilClipMode == fClipMode) {
@@ -377,6 +382,7 @@
     const GrClip& clip = doDevBoundsClip ? devBoundsClip : pipelineBuilder.clip();
 
     if (clip.isWideOpen(clipSpaceRTIBounds)) {
+        this->setPipelineBuilderStencil(pipelineBuilder, ars);
         return true;
     }
 
@@ -390,7 +396,7 @@
             SkIRect scissor = clip.irect();
             if (scissor.intersect(clipSpaceRTIBounds)) {
                 out->fScissorState.set(scissor);
-                out->fHasStencilClip = kIgnoreClip_StencilClipMode != fClipMode;
+                this->setPipelineBuilderStencil(pipelineBuilder, ars);
                 return true;
             }
             return false;
@@ -418,6 +424,7 @@
             if (elements.isEmpty()) {
                 if (GrReducedClip::kAllIn_InitialState == initialState) {
                     if (clipSpaceIBounds == clipSpaceRTIBounds) {
+                        this->setPipelineBuilderStencil(pipelineBuilder, ars);
                         return true;
                     }
                 } else {
@@ -427,8 +434,6 @@
         } break;
     }
 
-    SkASSERT(kIgnoreClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode.
-
     // An element count of 4 was chosen because of the common pattern in Blink of:
     //   isect RR
     //   diff  RR
@@ -448,7 +453,7 @@
             // color buffer anyway, so we may as well use coverage AA if nothing else in the pipe
             // is multisampled.
             disallowAnalyticAA = pipelineBuilder.isHWAntialias() ||
-                                 pipelineBuilder.hasUserStencilSettings();
+                                 !pipelineBuilder.getStencil().isDisabled();
         }
         const GrFragmentProcessor* clipFP = nullptr;
         if (elements.isEmpty() ||
@@ -461,6 +466,7 @@
                 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
                 out->fScissorState.set(scissorSpaceIBounds);
             }
+            this->setPipelineBuilderStencil(pipelineBuilder, ars);
             out->fClipCoverageFP.reset(clipFP);
             return true;
         }
@@ -502,6 +508,7 @@
             SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
             rtSpaceMaskBounds.offset(-clip.origin());
             out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBounds));
+            this->setPipelineBuilderStencil(pipelineBuilder, ars);
             return true;
         }
         // if alpha clip mask creation fails fall through to the non-AA code paths
@@ -522,14 +529,13 @@
     SkIRect scissorSpaceIBounds(clipSpaceIBounds);
     scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
     out->fScissorState.set(scissorSpaceIBounds);
-    SkASSERT(kRespectClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode.
-    out->fHasStencilClip = true;
+    this->setPipelineBuilderStencil(pipelineBuilder, ars);
     return true;
 }
 
 static bool stencil_element(GrDrawContext* dc,
                             const SkIRect* scissorRect,
-                            const GrUserStencilSettings* ss,
+                            const GrStencilSettings& ss,
                             const SkMatrix& viewMatrix,
                             const SkClipStack::Element* element) {
 
@@ -675,32 +681,28 @@
 
             // draw directly into the result with the stencil set to make the pixels affected
             // by the clip shape be non-zero.
-            static constexpr GrUserStencilSettings kStencilInElement(
-                 GrUserStencilSettings::StaticInit<
-                     0xffff,
-                     GrUserStencilTest::kAlways,
-                     0xffff,
-                     GrUserStencilOp::kReplace,
-                     GrUserStencilOp::kReplace,
-                     0xffff>()
-            );
-            if (!stencil_element(dc.get(), &maskSpaceIBounds, &kStencilInElement,
+            static constexpr GrStencilSettings kStencilInElement(
+                 kReplace_StencilOp,
+                 kReplace_StencilOp,
+                 kAlways_StencilFunc,
+                 0xffff,
+                 0xffff,
+                 0xffff);
+            if (!stencil_element(dc.get(), &maskSpaceIBounds, kStencilInElement,
                                  translate, element)) {
                 texture->resourcePriv().removeUniqueKey();
                 return nullptr;
             }
 
             // Draw to the exterior pixels (those with a zero stencil value).
-            static constexpr GrUserStencilSettings kDrawOutsideElement(
-                 GrUserStencilSettings::StaticInit<
-                     0x0000,
-                     GrUserStencilTest::kEqual,
-                     0xffff,
-                     GrUserStencilOp::kZero,
-                     GrUserStencilOp::kZero,
-                     0xffff>()
-            );
-            if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, &kDrawOutsideElement,
+            static constexpr GrStencilSettings kDrawOutsideElement(
+                 kZero_StencilOp,
+                 kZero_StencilOp,
+                 kEqual_StencilFunc,
+                 0xffff,
+                 0x0000,
+                 0xffff);
+            if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, kDrawOutsideElement,
                                                           op, !invert, false,
                                                           translate,
                                                           SkRect::Make(clipSpaceIBounds))) {
@@ -751,6 +753,10 @@
         stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
         GrClip clip(stencilSpaceIBounds);
 
+        int clipBit = stencilAttachment->bits();
+        SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
+        clipBit = (1 << (clipBit-1));
+
         fDrawTarget->cmmAccess().clearStencilClip(stencilSpaceIBounds,
             GrReducedClip::kAllIn_InitialState == initialState, rt);
 
@@ -792,7 +798,7 @@
                     clipPath.toggleInverseFillType();
                 }
 
-                SkASSERT(!pipelineBuilder.hasUserStencilSettings());
+                SkASSERT(pipelineBuilder.getStencil().isDisabled());
 
                 GrPathRenderer::CanDrawPathArgs canDrawArgs;
                 canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
@@ -800,7 +806,7 @@
                 canDrawArgs.fPath = &clipPath;
                 canDrawArgs.fStyle = &GrStyle::SimpleFill();
                 canDrawArgs.fAntiAlias = false;
-                canDrawArgs.fHasUserStencilSettings = pipelineBuilder.hasUserStencilSettings();
+                canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled();
                 canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
 
                 pr = this->getContext()->drawingManager()->getPathRenderer(canDrawArgs, false,
@@ -811,36 +817,40 @@
                 }
             }
 
+            int passes;
+            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
+
             bool canRenderDirectToStencil =
                 GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
-            bool drawDirectToClip; // Given the renderer, the element,
-                                   // fill rule, and set operation should
-                                   // we render the element directly to
-                                   // stencil bit used for clipping.
-            GrUserStencilSettings const* const* stencilPasses =
-                GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted,
-                                                 &drawDirectToClip);
+            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 (!drawDirectToClip) {
-                static constexpr GrUserStencilSettings kDrawToStencil(
-                     GrUserStencilSettings::StaticInit<
-                         0x0000,
-                         GrUserStencilTest::kAlways,
-                         0xffff,
-                         GrUserStencilOp::kIncMaybeClamp,
-                         GrUserStencilOp::kIncMaybeClamp,
-                         0xffff>()
-                );
+            if (!canDrawDirectToClip) {
+                static constexpr GrStencilSettings kDrawToStencil(
+                     kIncClamp_StencilOp,
+                     kIncClamp_StencilOp,
+                     kAlways_StencilFunc,
+                     0xffff,
+                     0x0000,
+                     0xffff);
                 if (Element::kRect_Type == element->getType()) {
-                    pipelineBuilder.setUserStencil(&kDrawToStencil);
+                    *pipelineBuilder.stencil() = kDrawToStencil;
 
                     draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix,
                                      element->getRect());
                 } else {
                     if (!clipPath.isEmpty()) {
                         if (canRenderDirectToStencil) {
-                            pipelineBuilder.setUserStencil(&kDrawToStencil);
+                            *pipelineBuilder.stencil() = kDrawToStencil;
 
                             GrPathRenderer::DrawPathArgs args;
                             args.fTarget = fDrawTarget;
@@ -869,10 +879,10 @@
             // now we modify the clip bit by rendering either the clip
             // element directly or a bounding rect of the entire clip.
             fClipMode = kModifyClip_StencilClipMode;
-            for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
-                pipelineBuilder.setUserStencil(*pass);
+            for (int p = 0; p < passes; ++p) {
+                *pipelineBuilder.stencil() = stencilSettings[p];
 
-                if (drawDirectToClip) {
+                if (canDrawDirectToClip) {
                     if (Element::kRect_Type == element->getType()) {
                         draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix,
                                          element->getRect());
@@ -902,6 +912,165 @@
     return true;
 }
 
+// mapping of clip-respecting stencil funcs to normal stencil funcs
+// mapping depends on whether stencil-clipping is in effect.
+static const GrStencilFunc
+    gSpecialToBasicStencilFunc[2][kClipStencilFuncCnt] = {
+    {// Stencil-Clipping is DISABLED,  we are effectively always inside the clip
+        // In the Clip Funcs
+        kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
+        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
+        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
+        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
+        // Special in the clip func that forces user's ref to be 0.
+        kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
+                                      // make ref 0 and do normal nequal.
+    },
+    {// Stencil-Clipping is ENABLED
+        // In the Clip Funcs
+        kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
+                                      // eq stencil clip bit, mask
+                                      // out user bits.
+
+        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
+                                      // add stencil bit to mask and ref
+
+        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
+        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
+                                      // for both of these we can add
+                                      // the clip bit to the mask and
+                                      // ref and compare as normal
+        // Special in the clip func that forces user's ref to be 0.
+        kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
+                                      // make ref have only the clip bit set
+                                      // and make comparison be less
+                                      // 10..0 < 1..user_bits..
+    }
+};
+
+void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipelineBuilder,
+                                                  GrPipelineBuilder::AutoRestoreStencil* ars) {
+    // 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.
+
+    // use stencil for clipping if clipping is enabled and the clip
+    // has been written into the stencil.
+    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 (pipelineBuilder.getStencil().isDisabled()) {
+        if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) {
+            static constexpr GrStencilSettings kBasicApplyClipSettings(
+                kKeep_StencilOp,
+                kKeep_StencilOp,
+                kAlwaysIfInClip_StencilFunc,
+                0x0000,
+                0x0000,
+                0x0000);
+            settings = kBasicApplyClipSettings;
+        } else {
+            return;
+        }
+    } else {
+        settings = pipelineBuilder.getStencil();
+    }
+
+    int stencilBits = 0;
+    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
+    GrStencilAttachment* stencilAttachment = this->resourceProvider()->attachStencilAttachment(rt);
+    if (stencilAttachment) {
+        stencilBits = stencilAttachment->bits();
+    }
+
+    SkASSERT(this->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp());
+    SkASSERT(this->caps()->twoSidedStencilSupport() || !settings.isTwoSided());
+    this->adjustStencilParams(&settings, fClipMode, stencilBits);
+    ars->set(&pipelineBuilder);
+    ars->setStencil(settings);
+}
+
+void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
+                                            StencilClipMode mode,
+                                            int stencilBitCnt) {
+    SkASSERT(stencilBitCnt > 0);
+
+    if (kModifyClip_StencilClipMode == mode) {
+        // 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;
+
+    GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
+    bool twoSided = this->caps()->twoSidedStencilSupport();
+
+    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);
+
+        SkASSERT((unsigned) func < kStencilFuncCnt);
+
+        writeMask &= userBits;
+
+        if (func >= kBasicStencilFuncCnt) {
+            int respectClip = kRespectClip_StencilClipMode == mode;
+            if (respectClip) {
+                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:
+                        SkFAIL("Unknown stencil func");
+                }
+            } else {
+                funcMask &= userBits;
+                funcRef &= userBits;
+            }
+            const GrStencilFunc* table =
+                gSpecialToBasicStencilFunc[respectClip];
+            func = table[func - kBasicStencilFuncCnt];
+            SkASSERT(func >= 0 && func < kBasicStencilFuncCnt);
+        } else {
+            funcMask &= userBits;
+            funcRef &= 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;
+        }
+    }
+    if (!twoSided) {
+        settings->copyFrontSettingsToBack();
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
                                                      int32_t elementsGenID,
@@ -979,3 +1148,13 @@
 
     return result;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stencilAttachment,
+                                                GrStencilSettings* settings) {
+    if (stencilAttachment) {
+        int stencilBits = stencilAttachment->bits();
+        this->adjustStencilParams(settings, fClipMode, stencilBits);
+    }
+}
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 096dafd..ef0c2be 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -9,6 +9,7 @@
 
 #include "GrPipelineBuilder.h"
 #include "GrReducedClip.h"
+#include "GrStencil.h"
 #include "GrTexture.h"
 #include "SkClipStack.h"
 #include "SkDeque.h"
@@ -32,15 +33,13 @@
  */
 class GrAppliedClip : public SkNoncopyable {
 public:
-    GrAppliedClip() : fHasStencilClip(false) {}
+    GrAppliedClip() {}
     const GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP; }
     const GrScissorState& scissorState() const { return fScissorState; }
-    bool hasStencilClip() const { return fHasStencilClip; }
 
 private:
     SkAutoTUnref<const GrFragmentProcessor> fClipCoverageFP;
     GrScissorState                          fScissorState;
-    bool                                    fHasStencilClip;
     friend class GrClipMaskManager;
 
     typedef SkNoncopyable INHERITED;
@@ -61,23 +60,30 @@
     /**
      * 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. devBounds is optional but can help optimize
-     * clipping.
+     * then the draw can be skipped. The AutoRestoreEffects is initialized by
+     * the manager when it must install additional effects to implement the
+     * clip. devBounds is optional but can help optimize clipping.
      */
-    bool setupClipping(const GrPipelineBuilder&, const SkRect* devBounds, GrAppliedClip*);
+    bool setupClipping(const GrPipelineBuilder&,
+                       GrPipelineBuilder::AutoRestoreStencil*,
+                       const SkRect* devBounds,
+                       GrAppliedClip*);
 
     bool setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
+                          GrPipelineBuilder::AutoRestoreStencil* ars,
                           const SkIRect& scissor,
                           const SkRect* devBounds,
                           GrAppliedClip* out);
 
+    void adjustPathStencilParams(const GrStencilAttachment*, GrStencilSettings*);
+
 private:
     inline GrContext* getContext();
     inline const GrCaps* caps() const;
     inline GrResourceProvider* resourceProvider();
 
     static bool PathNeedsSWRenderer(GrContext* context,
-                                    bool hasUserStencilSettings,
+                                    bool isStencilDisabled,
                                     const GrRenderTarget* rt,
                                     const SkMatrix& viewMatrix,
                                     const SkClipStack::Element* element,
@@ -144,6 +150,21 @@
                              const SkVector& clipToMaskOffset,
                              const GrReducedClip::ElementList& elements);
 
+    /**
+     * Called prior to return control back the GrGpu in setupClipping. It updates the
+     * GrPipelineBuilder with stencil settings that account for stencil-based clipping.
+     */
+    void setPipelineBuilderStencil(const GrPipelineBuilder&,
+                                   GrPipelineBuilder::AutoRestoreStencil*);
+
+    /**
+     * Adjusts the stencil settings to account for interaction with stencil
+     * clipping.
+     */
+    void adjustStencilParams(GrStencilSettings* settings,
+                             StencilClipMode mode,
+                             int stencilBitCnt);
+
     GrTexture* createCachedMask(int width, int height, const GrUniqueKey& key, bool renderTarget);
 
     static const int kMaxAnalyticElements = 4;
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index 7f5cdc7..a7c7f6a 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -375,7 +375,7 @@
 }
 
 bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
-                                           const GrUserStencilSettings* ss,
+                                           const GrStencilSettings& ss,
                                            SkRegion::Op op,
                                            bool invert,
                                            bool doAA,
@@ -397,7 +397,7 @@
         GrPipelineBuilder pipelineBuilder(paint,
                                           fDrawContext->accessRenderTarget(),
                                           GrClip::WideOpen());
-        pipelineBuilder.setUserStencil(ss);
+        pipelineBuilder.setStencil(ss);
 
         fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, batch, scissorRect);
         return true;
@@ -855,7 +855,7 @@
 }
 
 bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
-                                           const GrUserStencilSettings* ss,
+                                           const GrStencilSettings& ss,
                                            SkRegion::Op op,
                                            bool invert,
                                            bool doAA,
@@ -880,7 +880,7 @@
     // aa. If we have some future driver-mojo path AA that can do the right
     // thing WRT to the blend then we'll need some query on the PR.
     bool useCoverageAA = doAA && !fDrawContext->fRenderTarget->isUnifiedMultisampled();
-    bool hasUserStencilSettings = (&GrUserStencilSettings::kUnused != ss);
+    bool isStencilDisabled = true;
     bool isStencilBufferMSAA = fDrawContext->fRenderTarget->isStencilBufferMultisampled();
 
     const GrPathRendererChain::DrawType type =
@@ -893,7 +893,7 @@
     canDrawArgs.fPath = &path;
     canDrawArgs.fStyle = &GrStyle::SimpleFill();
     canDrawArgs.fAntiAlias = useCoverageAA;
-    canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
+    canDrawArgs.fIsStencilDisabled = isStencilDisabled;
     canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
 
     // Don't allow the SW renderer
@@ -913,7 +913,7 @@
     }
 
     GrPipelineBuilder pipelineBuilder(paint, fDrawContext->accessRenderTarget(), clip);
-    pipelineBuilder.setUserStencil(ss);
+    pipelineBuilder.setStencil(ss);
 
     GrPathRenderer::DrawPathArgs args;
     args.fTarget = fDrawContext->getDrawTarget();
@@ -939,7 +939,7 @@
     SkASSERT(!origPath.isEmpty());
 
     bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get());
-    constexpr bool kHasUserStencilSettings = false;
+    const bool isStencilDisabled = true;
     bool isStencilBufferMSAA = fRenderTarget->isStencilBufferMultisampled();
 
     const GrPathRendererChain::DrawType type =
@@ -955,7 +955,7 @@
     canDrawArgs.fPath = &origPath;
     canDrawArgs.fStyle = &origStyle;
     canDrawArgs.fAntiAlias = useCoverageAA;
-    canDrawArgs.fHasUserStencilSettings = kHasUserStencilSettings;
+    canDrawArgs.fIsStencilDisabled = isStencilDisabled;
     canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
 
     // Try a 1st time without applying any of the style to the geometry (and barring sw)
diff --git a/src/gpu/GrDrawContextPriv.h b/src/gpu/GrDrawContextPriv.h
index 973315b..4482e35 100644
--- a/src/gpu/GrDrawContextPriv.h
+++ b/src/gpu/GrDrawContextPriv.h
@@ -10,7 +10,7 @@
 
 #include "GrDrawContext.h"
 
-struct GrUserStencilSettings;
+class GrStencilSettings;
 
 /** Class that adds methods to GrDrawContext that are only intended for use internal to Skia.
     This class is purely a privileged window into GrDrawContext. It should never have additional
@@ -18,7 +18,7 @@
 class GrDrawContextPriv {
 public:
     bool drawAndStencilRect(const SkIRect* scissorRect,
-                            const GrUserStencilSettings*,
+                            const GrStencilSettings&,
                             SkRegion::Op op,
                             bool invert,
                             bool doAA,
@@ -26,7 +26,7 @@
                             const SkRect&);
 
     bool drawAndStencilPath(const SkIRect* scissorRect,
-                            const GrUserStencilSettings*,
+                            const GrStencilSettings&,
                             SkRegion::Op op,
                             bool invert,
                             bool doAA,
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index f824c81..0f180dc 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -16,7 +16,6 @@
 #include "GrRenderTarget.h"
 #include "GrResourceProvider.h"
 #include "GrRenderTargetPriv.h"
-#include "GrStencilAttachment.h"
 #include "GrSurfacePriv.h"
 #include "GrTexture.h"
 #include "gl/GrGLRenderTarget.h"
@@ -236,16 +235,17 @@
                              GrDrawBatch* batch,
                              const SkIRect* scissorRect) {
     // Setup clip
+    GrPipelineBuilder::AutoRestoreStencil ars;
     GrAppliedClip clip;
 
     if (scissorRect) {
         SkASSERT(GrClip::kWideOpen_ClipType == pipelineBuilder.clip().clipType());
-        if (!fClipMaskManager->setupScissorClip(pipelineBuilder, *scissorRect,
+        if (!fClipMaskManager->setupScissorClip(pipelineBuilder, &ars, *scissorRect,
                                                 &batch->bounds(), &clip)) {
             return;
         }
     } else {
-        if (!fClipMaskManager->setupClipping(pipelineBuilder, &batch->bounds(), &clip)) {
+        if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
             return;
         }
     }
@@ -257,8 +257,7 @@
     }
 
     GrPipeline::CreateArgs args;
-    if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(),
-                                          clip.hasStencilClip(), batch)) {
+    if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
         return;
     }
 
@@ -270,36 +269,34 @@
     this->recordBatch(batch);
 }
 
-inline static const GrUserStencilSettings& get_path_stencil_settings_for_fill(
-        GrPathRendering::FillType fill) {
-    static constexpr GrUserStencilSettings kWindingStencilSettings(
-        GrUserStencilSettings::StaticInit<
-            0xffff,
-            GrUserStencilTest::kAlwaysIfInClip,
-            0xffff,
-            GrUserStencilOp::kIncMaybeClamp, // TODO: Use wrap ops for NVPR.
-            GrUserStencilOp::kIncMaybeClamp,
-            0xffff>()
+void GrDrawTarget::getPathStencilSettingsForFilltype(GrPathRendering::FillType fill,
+                                                     const GrStencilAttachment* sb,
+                                                     GrStencilSettings* outStencilSettings) {
+    static constexpr GrStencilSettings kWindingStencilSettings(
+        kIncClamp_StencilOp,
+        kIncClamp_StencilOp,
+        kAlwaysIfInClip_StencilFunc,
+        0xFFFF, 0xFFFF, 0xFFFF
     );
 
-    static constexpr GrUserStencilSettings kEvenOddStencilSettings(
-        GrUserStencilSettings::StaticInit<
-            0xffff,
-            GrUserStencilTest::kAlwaysIfInClip,
-            0xffff,
-            GrUserStencilOp::kInvert,
-            GrUserStencilOp::kInvert,
-            0xffff>()
+    static constexpr GrStencilSettings kEvenODdStencilSettings(
+        kInvert_StencilOp,
+        kInvert_StencilOp,
+        kAlwaysIfInClip_StencilFunc,
+        0xFFFF, 0xFFFF, 0xFFFF
     );
 
     switch (fill) {
         default:
             SkFAIL("Unexpected path fill.");
         case GrPathRendering::kWinding_FillType:
-            return kWindingStencilSettings;
+            *outStencilSettings = kWindingStencilSettings;
+            break;
         case GrPathRendering::kEvenOdd_FillType:
-            return kEvenOddStencilSettings;
+            *outStencilSettings = kEvenODdStencilSettings;
+            break;
     }
+    fClipMaskManager->adjustPathStencilParams(sb, outStencilSettings);
 }
 
 void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
@@ -311,8 +308,9 @@
     SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
 
     // Setup clip
+    GrPipelineBuilder::AutoRestoreStencil ars;
     GrAppliedClip clip;
-    if (!fClipMaskManager->setupClipping(pipelineBuilder, nullptr, &clip)) {
+    if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, nullptr, &clip)) {
         return;
     }
 
@@ -322,16 +320,15 @@
         arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
     }
 
+    // set stencil settings for path
+    GrStencilSettings stencilSettings;
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
-    GrStencilAttachment* stencilAttachment = rt->renderTargetPriv().getStencilAttachment();
-    SkASSERT(stencilAttachment)
+    GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
+    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
 
     GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
                                                 pipelineBuilder.isHWAntialias(),
-                                                get_path_stencil_settings_for_fill(fill),
-                                                clip.hasStencilClip(),
-                                                stencilAttachment->bits(),
-                                                clip.scissorState(),
+                                                stencilSettings, clip.scissorState(),
                                                 pipelineBuilder.getRenderTarget(),
                                                 path);
     this->recordBatch(batch);
@@ -346,8 +343,9 @@
     // batches.
     SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
 
+    GrPipelineBuilder::AutoRestoreStencil ars;
     GrAppliedClip clip;
-    if (!fClipMaskManager->setupClipping(pipelineBuilder, &batch->bounds(), &clip)) {
+    if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
         return;
     }
 
@@ -358,16 +356,14 @@
     }
 
     // Ensure the render target has a stencil buffer and get the stencil settings.
+    GrStencilSettings stencilSettings;
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
     GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
-    // TODO: Move this step into GrDrawPathPath::onPrepare().
-    batch->setStencilSettings(get_path_stencil_settings_for_fill(batch->fillType()),
-                              clip.hasStencilClip(),
-                              sb->bits());
+    this->getPathStencilSettingsForFilltype(batch->fillType(), sb, &stencilSettings);
+    batch->setStencilSettings(stencilSettings);
 
     GrPipeline::CreateArgs args;
-    if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(),
-                                          clip.hasStencilClip(), batch)) {
+    if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
         return;
     }
 
@@ -551,20 +547,11 @@
 
 bool GrDrawTarget::installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
                                               const GrScissorState* scissor,
-                                              bool hasStencilClip,
                                               GrDrawBatch* batch) {
     GrPipeline::CreateArgs args;
     args.fPipelineBuilder = pipelineBuilder;
     args.fCaps = this->caps();
     args.fScissor = scissor;
-    if (pipelineBuilder->hasUserStencilSettings() || hasStencilClip) {
-        GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
-        GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
-        args.fNumStencilBits = sb->bits();
-    } else {
-        args.fNumStencilBits = 0;
-    }
-    args.fHasStencilClip = hasStencilClip;
     batch->getPipelineOptimizations(&args.fOpts);
     GrScissorState finalScissor;
     if (args.fOpts.fOverrides.fUsePLSDstRead) {
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 907fc1f..c863b45 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -223,7 +223,6 @@
     void forwardCombine();
     bool installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
                                     const GrScissorState* scissor,
-                                    bool hasStencilClip,
                                     GrDrawBatch* batch);
 
     // Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required
@@ -234,6 +233,11 @@
         GrXferProcessor::DstTexture*,
         const SkRect& batchBounds);
 
+    // Check to see if this set of draw commands has been sent out
+    void getPathStencilSettingsForFilltype(GrPathRendering::FillType,
+                                           const GrStencilAttachment*,
+                                           GrStencilSettings*);
+
     void addDependency(GrDrawTarget* dependedOn);
 
     // Used only by CMM.
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 63a56dd..e38b913 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -10,6 +10,7 @@
 
 #include "GrPipelineBuilder.h"
 #include "GrProgramDesc.h"
+#include "GrStencil.h"
 #include "GrSwizzle.h"
 #include "GrAllocator.h"
 #include "GrTextureParamsAdjuster.h"
@@ -33,7 +34,6 @@
 class GrPrimitiveProcessor;
 class GrRenderTarget;
 class GrStencilAttachment;
-class GrStencilSettings;
 class GrSurface;
 class GrTexture;
 
@@ -485,6 +485,17 @@
     virtual void resetShaderCacheForTesting() const {}
 
 protected:
+    // Functions used to map clip-respecting stencil tests into normal
+    // stencil funcs supported by GPUs.
+    static GrStencilFunc ConvertStencilFunc(bool stencilInClip,
+                                            GrStencilFunc func);
+    static void ConvertStencilFuncAndMask(GrStencilFunc func,
+                                          bool clipInStencil,
+                                          unsigned int clipBit,
+                                          unsigned int userBits,
+                                          unsigned int* ref,
+                                          unsigned int* mask);
+
     static void ElevateDrawPreference(GrGpu::DrawPreference* preference,
                                       GrGpu::DrawPreference elevation) {
         GR_STATIC_ASSERT(GrGpu::kCallerPrefersDraw_DrawPreference > GrGpu::kNoDraw_DrawPreference);
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index a7609db..3bc0230 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -9,6 +9,7 @@
 #define GrPathRenderer_DEFINED
 
 #include "GrDrawTarget.h"
+#include "GrStencil.h"
 #include "GrStyle.h"
 
 #include "SkDrawProcs.h"
@@ -81,7 +82,7 @@
         bool                        fAntiAlias;
 
         // These next two are only used by GrStencilAndCoverPathRenderer
-        bool                        fHasUserStencilSettings;
+        bool                        fIsStencilDisabled;
         bool                        fIsStencilBufferMSAA;
 
         void validate() const {
@@ -154,11 +155,11 @@
         canArgs.fStyle = args.fStyle;
         canArgs.fAntiAlias = args.fAntiAlias;
 
-        canArgs.fHasUserStencilSettings = args.fPipelineBuilder->hasUserStencilSettings();
+        canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
         canArgs.fIsStencilBufferMSAA =
                           args.fPipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
         SkASSERT(this->canDrawPath(canArgs));
-        if (args.fPipelineBuilder->hasUserStencilSettings()) {
+        if (!args.fPipelineBuilder->getStencil().isDisabled()) {
             SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath));
             SkASSERT(args.fStyle->isSimpleFill());
         }
@@ -259,16 +260,14 @@
      * kStencilOnly in onGetStencilSupport().
      */
     virtual void onStencilPath(const StencilPathArgs& args) {
-        static constexpr GrUserStencilSettings kIncrementStencil(
-            GrUserStencilSettings::StaticInit<
-                 0xffff,
-                 GrUserStencilTest::kAlways,
-                 0xffff,
-                 GrUserStencilOp::kReplace,
-                 GrUserStencilOp::kReplace,
-                 0xffff>()
-        );
-        args.fPipelineBuilder->setUserStencil(&kIncrementStencil);
+        static constexpr GrStencilSettings kIncrementStencil(
+             kReplace_StencilOp,
+             kReplace_StencilOp,
+             kAlways_StencilFunc,
+             0xffff,
+             0xffff,
+             0xffff);
+        args.fPipelineBuilder->setStencil(kIncrementStencil);
         args.fPipelineBuilder->setDisableColorXPFactory();
         DrawPathArgs drawArgs;
         drawArgs.fTarget = args.fTarget;
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 761a876..8d384ef 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -20,35 +20,9 @@
                                  GrXPOverridesForBatch* overrides) {
     const GrPipelineBuilder& builder = *args.fPipelineBuilder;
 
-    GrPipeline* pipeline = new (memory) GrPipeline;
-    pipeline->fRenderTarget.reset(builder.fRenderTarget.get());
-    SkASSERT(pipeline->fRenderTarget);
-    pipeline->fScissorState = *args.fScissor;
-    if (builder.hasUserStencilSettings() || args.fHasStencilClip) {
-        SkASSERT(args.fNumStencilBits);
-        pipeline->fStencilSettings.reset(*builder.getUserStencil(), args.fHasStencilClip,
-                                         args.fNumStencilBits);
-        SkASSERT(!pipeline->fStencilSettings.usesWrapOp() || args.fCaps->stencilWrapOpsSupport());
-    }
-    pipeline->fDrawFace = builder.getDrawFace();
-
-    pipeline->fFlags = 0;
-    if (builder.isHWAntialias()) {
-        pipeline->fFlags |= kHWAA_Flag;
-    }
-    if (builder.snapVerticesToPixelCenters()) {
-        pipeline->fFlags |= kSnapVertices_Flag;
-    }
-    if (builder.getDisableOutputConversionToSRGB()) {
-        pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag;
-    }
-    if (builder.getAllowSRGBInputs()) {
-        pipeline->fFlags |= kAllowSRGBInputs_Flag;
-    }
-
     // Create XferProcessor from DS's XPFactory
     bool hasMixedSamples = builder.getRenderTarget()->hasMixedSamples() &&
-                           (builder.isHWAntialias() || !pipeline->fStencilSettings.isDisabled());
+                           (builder.isHWAntialias() || !builder.getStencil().isDisabled());
     const GrXPFactory* xpFactory = builder.getXPFactory();
     SkAutoTUnref<GrXferProcessor> xferProcessor;
     if (xpFactory) {
@@ -57,7 +31,6 @@
                                                            &args.fDstTexture,
                                                            *args.fCaps));
         if (!xferProcessor) {
-            pipeline->~GrPipeline();
             return nullptr;
         }
     } else {
@@ -78,7 +51,7 @@
     const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() :
                                                        &GrPorterDuffXPFactory::SimpleSrcOverXP();
     optFlags = xpForOpts->getOptimizations(args.fOpts,
-                                           pipeline->fStencilSettings.doesWrite(),
+                                           builder.getStencil().doesWrite(),
                                            &overrideColor,
                                            *args.fCaps);
 
@@ -86,7 +59,6 @@
     // so we must check the draw type. In cases where we will skip drawing we simply return a
     // null GrPipeline.
     if (GrXferProcessor::kSkipDraw_OptFlag & optFlags) {
-        pipeline->~GrPipeline();
         return nullptr;
     }
 
@@ -95,8 +67,29 @@
         overrideColor = GrColor_ILLEGAL;
     }
 
+    GrPipeline* pipeline = new (memory) GrPipeline;
     pipeline->fXferProcessor.reset(xferProcessor);
 
+    pipeline->fRenderTarget.reset(builder.fRenderTarget.get());
+    SkASSERT(pipeline->fRenderTarget);
+    pipeline->fScissorState = *args.fScissor;
+    pipeline->fStencilSettings = builder.getStencil();
+    pipeline->fDrawFace = builder.getDrawFace();
+
+    pipeline->fFlags = 0;
+    if (builder.isHWAntialias()) {
+        pipeline->fFlags |= kHWAA_Flag;
+    }
+    if (builder.snapVerticesToPixelCenters()) {
+        pipeline->fFlags |= kSnapVertices_Flag;
+    }
+    if (builder.getDisableOutputConversionToSRGB()) {
+        pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag;
+    }
+    if (builder.getAllowSRGBInputs()) {
+        pipeline->fFlags |= kAllowSRGBInputs_Flag;
+    }
+
     int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex();
 
     // TODO: Once we can handle single or four channel input into coverage GrFragmentProcessors
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index ff1905b..f64b875 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -15,7 +15,7 @@
 #include "GrPendingProgramElement.h"
 #include "GrPrimitiveProcessor.h"
 #include "GrProgramDesc.h"
-#include "GrStencilSettings.h"
+#include "GrStencil.h"
 #include "GrTypesPriv.h"
 #include "SkMatrix.h"
 #include "SkRefCnt.h"
@@ -51,8 +51,6 @@
         const GrCaps*               fCaps;
         GrPipelineOptimizations     fOpts;
         const GrScissorState*       fScissor;
-        int                         fNumStencilBits;
-        bool                        fHasStencilClip;
         GrXferProcessor::DstTexture fDstTexture;
     };
 
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index 4731cbb..1fd568e 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -16,14 +16,11 @@
 #include "effects/GrPorterDuffXferProcessor.h"
 
 GrPipelineBuilder::GrPipelineBuilder()
-    : fFlags(0x0),
-      fUserStencilSettings(&GrUserStencilSettings::kUnused),
-      fDrawFace(kBoth_DrawFace) {
+    : fFlags(0x0), fDrawFace(kBoth_DrawFace) {
     SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
 }
 
-GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, const GrClip& clip)
-    : GrPipelineBuilder() {
+GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, const GrClip& clip) {
     SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
 
     for (int i = 0; i < paint.numColorFragmentProcessors(); ++i) {
@@ -38,6 +35,11 @@
 
     this->setRenderTarget(rt);
 
+    // These have no equivalent in GrPaint, set them to defaults
+    fDrawFace = kBoth_DrawFace;
+    fStencilSettings.setDisabled();
+    fFlags = 0;
+
     fClip = clip;
 
     this->setState(GrPipelineBuilder::kHWAntialias_Flag,
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 18f817b..2f78fc5 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -14,7 +14,7 @@
 #include "GrGpuResourceRef.h"
 #include "GrProcOptInfo.h"
 #include "GrRenderTarget.h"
-#include "GrUserStencilSettings.h"
+#include "GrStencil.h"
 #include "GrXferProcessor.h"
 #include "SkMatrix.h"
 #include "effects/GrCoverageSetOpXP.h"
@@ -199,20 +199,57 @@
     /// @name Stencil
     ////
 
-    bool hasUserStencilSettings() const {
-        return &GrUserStencilSettings::kUnused != fUserStencilSettings;
-    }
-    const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; }
+    const GrStencilSettings& getStencil() const { return fStencilSettings; }
 
     /**
-     * Sets the user stencil settings for the next draw.
-     * This class only stores pointers to stencil settings objects.
-     * The caller guarantees the pointer will remain valid until it
-     * changes or goes out of scope.
+     * Sets the stencil settings to use for the next draw.
+     * Changing the clip has the side-effect of possibly zeroing
+     * out the client settable stencil bits. So multipass algorithms
+     * using stencil should not change the clip between passes.
      * @param settings  the stencil settings to use.
      */
-    void setUserStencil(const GrUserStencilSettings* settings) { fUserStencilSettings = settings; }
-    void disableUserStencil() { fUserStencilSettings = &GrUserStencilSettings::kUnused; }
+    void setStencil(const GrStencilSettings& settings) { fStencilSettings = settings; }
+
+    GrStencilSettings* stencil() { return &fStencilSettings; }
+
+    /**
+     * AutoRestoreStencil
+     *
+     * This simple struct saves and restores the stencil settings
+     * This class can transiently modify its "const" GrPipelineBuilder object but will restore it
+     * when done - so it is notionally "const" correct.
+     */
+    class AutoRestoreStencil : public ::SkNoncopyable {
+    public:
+        AutoRestoreStencil() : fPipelineBuilder(nullptr) {}
+
+        AutoRestoreStencil(const GrPipelineBuilder& ds) : fPipelineBuilder(nullptr) { this->set(&ds); }
+
+        ~AutoRestoreStencil() { this->set(nullptr); }
+
+        void set(const GrPipelineBuilder* ds) {
+            if (fPipelineBuilder) {
+                fPipelineBuilder->setStencil(fStencilSettings);
+            }
+            fPipelineBuilder = const_cast<GrPipelineBuilder*>(ds);
+            if (ds) {
+                fStencilSettings = ds->getStencil();
+            }
+        }
+
+        bool isSet() const { return SkToBool(fPipelineBuilder); }
+
+        void setStencil(const GrStencilSettings& settings) {
+            SkASSERT(this->isSet());
+            fPipelineBuilder->setStencil(settings);
+        }
+
+    private:
+        // notionally const (as marginalia)
+        GrPipelineBuilder*  fPipelineBuilder;
+        GrStencilSettings   fStencilSettings;
+    };
+
 
     /// @}
 
@@ -334,7 +371,7 @@
 
     SkAutoTUnref<GrRenderTarget>            fRenderTarget;
     uint32_t                                fFlags;
-    const GrUserStencilSettings*            fUserStencilSettings;
+    GrStencilSettings                       fStencilSettings;
     DrawFace                                fDrawFace;
     mutable SkAutoTUnref<const GrXPFactory> fXPFactory;
     FragmentProcessorArray                  fColorFragmentProcessors;
diff --git a/src/gpu/GrStencil.cpp b/src/gpu/GrStencil.cpp
new file mode 100644
index 0000000..94559ab
--- /dev/null
+++ b/src/gpu/GrStencil.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrStencil.h"
+
+#include "GrProcessor.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Stencil Rules for Merging user stencil space into clip
+
+// We can't include the clip bit in the ref or mask values because the division
+// between user and clip bits in the stencil depends on the number of stencil
+// bits in the runtime. Comments below indicate what the code should do to
+// incorporate the clip bit into these settings.
+
+///////
+// Replace
+
+// set the ref to be the clip bit, but mask it out for the test
+static constexpr GrStencilSettings gUserToClipReplace(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kLess_StencilFunc,
+    0xffff,           // unset clip bit
+    0x0000,           // set clip bit
+    0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipReplace(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,           // unset clip bit
+    0x0000,           // set clip bit
+    0xffff);
+
+///////
+// Intersect
+static constexpr GrStencilSettings gUserToClipIsect(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kLess_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipIsect(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0xffff);
+
+///////
+// Difference
+static constexpr GrStencilSettings gUserToClipDiff(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipDiff(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kLess_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0xffff);
+
+///////
+// Union
+
+// first pass makes all the passing cases >= just clip bit set.
+static constexpr GrStencilSettings gUserToClipUnionPass0(
+    kReplace_StencilOp,
+    kKeep_StencilOp,
+    kLEqual_StencilFunc,
+    0xffff,
+    0x0001,           // set clip bit
+    0xffff);
+
+// second pass allows anything greater than just clip bit set to pass
+static constexpr GrStencilSettings gUserToClipUnionPass1(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kLEqual_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0xffff);
+
+// first pass finds zeros in the user bits and if found sets
+// the clip bit to 1
+static constexpr GrStencilSettings gInvUserToClipUnionPass0(
+    kReplace_StencilOp,
+    kKeep_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0x0000            // set clip bit
+);
+
+// second pass zeros the user bits
+static constexpr GrStencilSettings gInvUserToClipUnionPass1(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kLess_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff            // unset clip bit
+);
+
+///////
+// Xor
+static constexpr GrStencilSettings gUserToClipXorPass0(
+    kInvert_StencilOp,
+    kKeep_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,           // unset clip bit
+    0x0000,
+    0xffff);
+
+static constexpr GrStencilSettings gUserToClipXorPass1(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kGreater_StencilFunc,
+    0xffff,
+    0x0000,          // set clip bit
+    0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipXorPass0(
+    kInvert_StencilOp,
+    kKeep_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,           // unset clip bit
+    0x0000,
+    0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipXorPass1(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kLess_StencilFunc,
+    0xffff,
+    0x0000,          // set clip bit
+    0xffff);
+
+///////
+// Reverse Diff
+static constexpr GrStencilSettings gUserToClipRDiffPass0(
+    kInvert_StencilOp,
+    kZero_StencilOp,
+    kLess_StencilFunc,
+    0xffff,         // unset clip bit
+    0x0000,         // set clip bit
+    0xffff);
+
+static constexpr GrStencilSettings gUserToClipRDiffPass1(
+    kReplace_StencilOp,
+    kZero_StencilOp,
+    kEqual_StencilFunc,
+    0x0000,          // set clip bit
+    0x0000,          // set clip bit
+    0xffff);
+
+// We are looking for stencil values that are all zero. The first pass sets the
+// clip bit if the stencil is all zeros. The second pass clears the user bits.
+static constexpr GrStencilSettings gInvUserToClipRDiffPass0(
+    kInvert_StencilOp,
+    kZero_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,
+    0x0000,
+    0x0000           // set clip bit
+);
+
+static constexpr GrStencilSettings gInvUserToClipRDiffPass1(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kAlways_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff           // unset clip bit
+);
+
+///////
+// Direct to Stencil
+
+// We can render a clip element directly without first writing to the client
+// portion of the clip when the fill is not inverse and the set operation will
+// only modify the in/out status of samples covered by the clip element.
+
+// this one only works if used right after stencil clip was cleared.
+// Our clip mask creation code doesn't allow midstream replace ops.
+static constexpr GrStencilSettings gReplaceClip(
+    kReplace_StencilOp,
+    kReplace_StencilOp,
+    kAlways_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0x0000            // set clipBit
+);
+
+static constexpr GrStencilSettings gUnionClip(
+    kReplace_StencilOp,
+    kReplace_StencilOp,
+    kAlways_StencilFunc,
+    0xffff,
+    0x0000,           // set clip bit
+    0x0000            // set clip bit
+);
+
+static constexpr GrStencilSettings gXorClip(
+    kInvert_StencilOp,
+    kInvert_StencilOp,
+    kAlways_StencilFunc,
+    0xffff,
+    0x0000,
+    0x0000            // set clip bit
+);
+
+static constexpr GrStencilSettings gDiffClip(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kAlways_StencilFunc,
+    0xffff,
+    0x0000,
+    0x0000            // set clip bit
+);
+
+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) {
+            case SkRegion::kReplace_Op:
+                *numPasses = 1;
+                settings[0] = gReplaceClip;
+                break;
+            case SkRegion::kUnion_Op:
+                *numPasses = 1;
+                settings[0] = gUnionClip;
+                break;
+            case SkRegion::kXOR_Op:
+                *numPasses = 1;
+                settings[0] = gXorClip;
+                break;
+            case SkRegion::kDifference_Op:
+                *numPasses = 1;
+                settings[0] = gDiffClip;
+                break;
+            default: // suppress warning
+                break;
+        }
+        if (1 == *numPasses) {
+            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;
+        }
+    }
+    switch (op) {
+        // if we make the path renderer go to stencil we always give it a
+        // non-inverted fill and we use the stencil rules on the client->clipbit
+        // pass to select either the zeros or nonzeros.
+        case SkRegion::kReplace_Op:
+            *numPasses= 1;
+            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].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].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].fWriteMasks[kFront_Face] &= ~stencilClipMask;
+                settings[1].fWriteMasks[kBack_Face] &=
+                    settings[1].fWriteMasks[kFront_Face];
+
+            } else {
+                settings[0] = gUserToClipUnionPass0;
+                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].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].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
+
+                settings[1] = gInvUserToClipXorPass1;
+                settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+                settings[1].fFuncRefs[kBack_Face] =
+                    settings[1].fFuncRefs[kFront_Face];
+            } else {
+                settings[0] = gUserToClipXorPass0;
+                settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+                settings[0].fFuncMasks[kBack_Face] =
+                    settings[0].fFuncMasks[kFront_Face];
+
+                settings[1] = gUserToClipXorPass1;
+                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].fFuncRefs[kFront_Face] |= stencilClipMask;
+            settings[0].fFuncRefs[kBack_Face] =
+                settings[0].fFuncRefs[kFront_Face];
+            break;
+        case SkRegion::kReverseDifference_Op:
+            if (invertedFill) {
+                *numPasses = 2;
+                settings[0] = gInvUserToClipRDiffPass0;
+                settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+                settings[0].fWriteMasks[kBack_Face] =
+                    settings[0].fWriteMasks[kFront_Face];
+                settings[1] = gInvUserToClipRDiffPass1;
+                settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask;
+                settings[1].fWriteMasks[kBack_Face] =
+                    settings[1].fWriteMasks[kFront_Face];
+            } else {
+                *numPasses = 2;
+                settings[0] = gUserToClipRDiffPass0;
+                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].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:
+            SkFAIL("Unknown set op");
+    }
+    return false;
+}
+
+void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
+    static const int kCount = sizeof(GrStencilSettings) / sizeof(uint32_t);
+    GR_STATIC_ASSERT(0 == sizeof(GrStencilSettings) % sizeof(uint32_t));
+    uint32_t* key = b->add32n(kCount);
+    memcpy(key, this, sizeof(GrStencilSettings));
+}
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
new file mode 100644
index 0000000..075eb1e
--- /dev/null
+++ b/src/gpu/GrStencil.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrStencil_DEFINED
+#define GrStencil_DEFINED
+
+#include "GrTypes.h"
+#include "SkRegion.h"
+
+class GrProcessorKeyBuilder;
+
+/**
+ * Gr uses the stencil buffer to implement complex clipping inside the
+ * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
+ * bits available for other uses by external code (clients). Client code can
+ * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
+ * provided by clients that overlap the bits used to implement clipping.
+ *
+ * When code outside the GrDrawTarget class uses the stencil buffer the contract
+ * is as follows:
+ *
+ * > Normal stencil funcs allow the client to pass / fail regardless of the
+ *   reserved clip bits.
+ * > Additional functions allow a test against the clip along with a limited
+ *   set of tests against the client bits.
+ * > Client can assume all client bits are zero initially.
+ * > Client must ensure that after all its passes are finished it has only
+ *   written to the color buffer in the region inside the clip. Furthermore, it
+ *   must zero all client bits that were modifed (both inside and outside the
+ *   clip).
+ */
+
+/**
+ * Determines which pixels pass / fail the stencil test.
+ * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
+ */
+enum GrStencilFunc {
+    kAlways_StencilFunc = 0,
+    kNever_StencilFunc,
+    kGreater_StencilFunc,
+    kGEqual_StencilFunc,
+    kLess_StencilFunc,
+    kLEqual_StencilFunc,
+    kEqual_StencilFunc,
+    kNotEqual_StencilFunc,
+
+    // Gr stores the current clip in the
+    // stencil buffer in the high bits that
+    // are not directly accessible modifiable
+    // via the GrDrawTarget interface. The below
+    // stencil funcs test against the current
+    // clip in addition to the GrDrawTarget
+    // client's stencil bits.
+
+    // pass if inside the clip
+    kAlwaysIfInClip_StencilFunc,
+    kEqualIfInClip_StencilFunc,
+    kLessIfInClip_StencilFunc,
+    kLEqualIfInClip_StencilFunc,
+    kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
+
+    kLast_StencilFunc = kNonZeroIfInClip_StencilFunc
+};
+
+static const int kStencilFuncCnt = kLast_StencilFunc + 1;
+static const int kClipStencilFuncCnt =
+    kNonZeroIfInClip_StencilFunc - kAlwaysIfInClip_StencilFunc + 1;
+static const int kBasicStencilFuncCnt = kStencilFuncCnt - kClipStencilFuncCnt;
+
+/**
+ * Operations to perform based on whether stencil test passed failed.
+ */
+enum GrStencilOp {
+    kKeep_StencilOp = 0,    // preserve existing stencil value
+    kReplace_StencilOp,     // replace with reference value from stencl test
+    kIncWrap_StencilOp,     // increment and wrap at max
+    kIncClamp_StencilOp,    // increment and clamp at max
+    kDecWrap_StencilOp,     // decrement and wrap at 0
+    kDecClamp_StencilOp,    // decrement and clamp at 0
+    kZero_StencilOp,        // zero stencil bits
+    kInvert_StencilOp,      // invert stencil bits
+    kLast_StencilOp = kInvert_StencilOp
+};
+static const int kStencilOpCnt = kLast_StencilOp + 1;
+
+/**
+ * Class representing stencil state.
+ */
+class GrStencilSettings {
+public:
+    enum Face {
+        kFront_Face = 0,
+        kBack_Face  = 1,
+    };
+
+    constexpr GrStencilSettings(GrStencilOp passOp,
+                                GrStencilOp failOp,
+                                GrStencilFunc func,
+                                unsigned short funcMask,
+                                unsigned short funcRef,
+                                unsigned short writeMask)
+        : fPassOps{(uint8_t)passOp, (uint8_t)passOp}
+        , fFailOps{(uint8_t)failOp, (uint8_t)failOp}
+        , fFuncs{(uint8_t)func, (uint8_t)func}
+        , fPad0(0)
+        , fPad1(0)
+        , fFuncMasks{funcMask, funcMask}
+        , fFuncRefs{funcRef, funcRef}
+        , fWriteMasks{writeMask, writeMask}
+        , fFlags(ComputeFlags(passOp,    passOp,
+                              failOp,    failOp,
+                              func,      func,
+                              writeMask, writeMask)) {
+    }
+
+    constexpr GrStencilSettings(GrStencilOp frontPassOp,  GrStencilOp backPassOp,
+                                GrStencilOp frontFailOp,  GrStencilOp backFailOp,
+                                GrStencilFunc frontFunc,  GrStencilFunc backFunc,
+                                uint16_t frontFuncMask,   uint16_t backFuncMask,
+                                uint16_t frontFuncRef,    uint16_t backFuncRef,
+                                uint16_t frontWriteMask,  uint16_t backWriteMask)
+        : fPassOps{(uint8_t)frontPassOp, (uint8_t)backPassOp}
+        , fFailOps{(uint8_t)frontFailOp, (uint8_t)backFailOp}
+        , fFuncs{(uint8_t)frontFunc, (uint8_t)backFunc}
+        , fPad0(0)
+        , fPad1(0)
+        , fFuncMasks{frontFuncMask, backFuncMask}
+        , fFuncRefs{frontFuncRef, backFuncRef}
+        , fWriteMasks{frontWriteMask, backWriteMask}
+        , fFlags(ComputeFlags(frontPassOp,    backPassOp,
+                              frontFailOp,    backFailOp,
+                              frontFunc,      backFunc,
+                              frontWriteMask, backWriteMask)) {
+    }
+
+    GrStencilSettings() {
+        fPad0 = fPad1 = 0;
+        this->setDisabled();
+    }
+
+    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 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 setDisabled() {
+        memset(this, 0, sizeof(*this));
+        GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+        GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+        fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag;
+    }
+
+    bool isTwoSided() const {
+        return fPassOps[kFront_Face]    != fPassOps[kBack_Face]   ||
+               fFailOps[kFront_Face]    != fFailOps[kBack_Face]   ||
+               fFuncs[kFront_Face]      != fFuncs[kBack_Face]     ||
+               fFuncMasks[kFront_Face]  != fFuncMasks[kBack_Face] ||
+               fFuncRefs[kFront_Face]   != fFuncRefs[kBack_Face]  ||
+               fWriteMasks[kFront_Face] != fWriteMasks[kBack_Face];
+    }
+
+    bool usesWrapOp() const {
+        return kIncWrap_StencilOp == fPassOps[kFront_Face] ||
+               kDecWrap_StencilOp == fPassOps[kFront_Face] ||
+               kIncWrap_StencilOp == fPassOps[kBack_Face]  ||
+               kDecWrap_StencilOp == fPassOps[kBack_Face]  ||
+               kIncWrap_StencilOp == fFailOps[kFront_Face] ||
+               kDecWrap_StencilOp == fFailOps[kFront_Face] ||
+               kIncWrap_StencilOp == fFailOps[kBack_Face]  ||
+               kDecWrap_StencilOp == fFailOps[kBack_Face];
+    }
+
+    bool isDisabled() const {
+        if (fFlags & kIsDisabled_StencilFlag) {
+            return true;
+        }
+        if (fFlags & kNotDisabled_StencilFlag) {
+            return false;
+        }
+        bool disabled = this->computeIsDisabled();
+        fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag;
+        return disabled;
+    }
+
+    bool doesWrite() const {
+        if (fFlags & kDoesWrite_StencilFlag) {
+            return true;
+        }
+        if (fFlags & kDoesNotWrite_StencilFlag) {
+            return false;
+        }
+        bool writes = this->computeDoesWrite();
+        fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag;
+        return writes;
+    }
+
+    void invalidate()  {
+        // write an illegal value to the first member
+        fPassOps[0] = kStencilOpCnt;
+        fFlags = 0;
+    }
+
+    bool isValid() const { return fPassOps[0] < kStencilOpCnt; }
+
+    void genKey(GrProcessorKeyBuilder* b) const;
+
+    bool operator==(const GrStencilSettings& s) const {
+        static const size_t gCompareSize = sizeof(GrStencilSettings) -
+                                           sizeof(fFlags);
+        SkASSERT((const char*)&fFlags + sizeof(fFlags) ==
+                 (const char*)this + sizeof(GrStencilSettings));
+        if (this->isDisabled() & s.isDisabled()) { // using & not &&
+            return true;
+        }
+        return 0 == memcmp(this, &s, gCompareSize);
+    }
+
+    bool operator!=(const GrStencilSettings& s) const {
+        return !(*this == s);
+    }
+
+    GrStencilSettings& operator=(const GrStencilSettings& s) {
+        memcpy(this, &s, sizeof(GrStencilSettings));
+        return *this;
+    }
+
+private:
+    friend class GrClipMaskManager;
+
+    enum {
+        kMaxStencilClipPasses = 2  // maximum number of passes to add a clip
+                                   // element to the stencil buffer.
+    };
+
+    /**
+     * Given a thing to draw into the stencil clip, a fill type, and a set op
+     * this function determines:
+     *      1. Whether the thing can be draw directly to the stencil clip or
+     *      needs to be drawn to the client portion of the stencil first.
+     *      2. How many passes are needed.
+     *      3. What those passes are.
+     *      4. The fill rule that should actually be used to render (will
+     *         always be non-inverted).
+     *
+     * @param op                the set op to combine this element with the
+     *                          existing clip
+     * @param stencilClipMask   mask with just the stencil bit used for clipping
+     *                          enabled.
+     * @param invertedFill      is this path inverted
+     * @param numPasses         out: the number of passes needed to add the
+     *                               element to the clip.
+     * @param settings          out: the stencil settings to use for each pass
+     *
+     * @return true if the clip element's geometry can be drawn directly to the
+     *         stencil clip bit. Will only be true if canBeDirect is true.
+     *         numPasses will be 1 if return value is true.
+     */
+    static bool GetClipPasses(SkRegion::Op op,
+                              bool canBeDirect,
+                              unsigned int stencilClipMask,
+                              bool invertedFill,
+                              int* numPasses,
+                              GrStencilSettings settings[kMaxStencilClipPasses]);
+
+    constexpr static bool IsDisabled(GrStencilOp frontPassOp,  GrStencilOp backPassOp,
+                                     GrStencilOp frontFailOp,  GrStencilOp backFailOp,
+                                     GrStencilFunc frontFunc,  GrStencilFunc backFunc) {
+        return (((frontPassOp == kKeep_StencilOp && frontFailOp == kKeep_StencilOp)) &&
+                ((backPassOp  == kKeep_StencilOp &&  backFailOp == kKeep_StencilOp))  &&
+                frontFunc   == kAlways_StencilFunc &&
+                backFunc   == kAlways_StencilFunc);
+    }
+
+    constexpr static bool DoesWrite(GrStencilOp frontPassOp,  GrStencilOp backPassOp,
+                                    GrStencilOp frontFailOp,  GrStencilOp backFailOp,
+                                    GrStencilFunc frontFunc,  GrStencilFunc backFunc,
+                                    uint16_t frontWriteMask,  uint16_t backWriteMask) {
+        return (0 != (frontWriteMask | backWriteMask)) &&
+                // Can we write due to a front face passing the stencil test?
+               ((frontFunc != kNever_StencilFunc  && frontPassOp != kKeep_StencilOp) ||
+                // Can we write due to a back face passing the stencil test?
+                (backFunc  != kNever_StencilFunc  && backPassOp  != kKeep_StencilOp) ||
+                // Can we write due to a front face failing the stencil test?
+                (frontFunc != kAlways_StencilFunc && frontFailOp != kKeep_StencilOp) ||
+                // Can we write due to a back face failing the stencil test?
+                (backFunc  != kAlways_StencilFunc && backFailOp  != kKeep_StencilOp));
+    }
+
+    constexpr static uint32_t ComputeFlags(GrStencilOp frontPassOp,  GrStencilOp backPassOp,
+                                           GrStencilOp frontFailOp,  GrStencilOp backFailOp,
+                                           GrStencilFunc frontFunc,  GrStencilFunc backFunc,
+                                           uint16_t frontWriteMask,  uint16_t backWriteMask) {
+        return (IsDisabled(frontPassOp, backPassOp, frontFailOp, backFailOp,
+                           frontFunc, backFunc)
+                    ? kIsDisabled_StencilFlag
+                    : kNotDisabled_StencilFlag) |
+               (DoesWrite(frontPassOp, backPassOp, frontFailOp, backFailOp,
+                          frontFunc, backFunc, frontWriteMask, backWriteMask)
+                    ? kDoesWrite_StencilFlag
+                    : kDoesNotWrite_StencilFlag);
+    }
+
+    bool computeIsDisabled() const {
+        return IsDisabled((GrStencilOp) fPassOps[kFront_Face], (GrStencilOp) fPassOps[kBack_Face],
+                          (GrStencilOp) fFailOps[kFront_Face], (GrStencilOp) fFailOps[kBack_Face],
+                          (GrStencilFunc) fFuncs[kFront_Face], (GrStencilFunc) fFuncs[kBack_Face]);
+    }
+    bool computeDoesWrite() const {
+        return DoesWrite((GrStencilOp)fPassOps[kFront_Face], (GrStencilOp)fPassOps[kBack_Face],
+                         (GrStencilOp)fFailOps[kFront_Face], (GrStencilOp)fFailOps[kBack_Face],
+                         (GrStencilFunc)fFuncs[kFront_Face], (GrStencilFunc)fFuncs[kBack_Face],
+                         fWriteMasks[kFront_Face],           fWriteMasks[kBack_Face]);
+    }
+
+    enum GrStencilFlags {
+        kIsDisabled_StencilFlag      = 0x1,
+        kNotDisabled_StencilFlag     = 0x2,
+        kDoesWrite_StencilFlag       = 0x4,
+        kDoesNotWrite_StencilFlag    = 0x8,
+    };
+
+    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)
+GR_STATIC_ASSERT(sizeof(GrStencilSettings) % 4 == 0);
+GR_STATIC_ASSERT(sizeof(GrStencilSettings) ==
+                 4*sizeof(uint8_t) + // ops
+                 2*sizeof(uint8_t) + // funcs
+                 2*sizeof(uint8_t) + // pads
+                 2*sizeof(uint16_t) + // func masks
+                 2*sizeof(uint16_t) + // ref values
+                 2*sizeof(uint16_t) + // write masks
+                 sizeof(uint32_t)); // flags
+
+#endif
diff --git a/src/gpu/GrStencilSettings.cpp b/src/gpu/GrStencilSettings.cpp
deleted file mode 100644
index ae8b03b..0000000
--- a/src/gpu/GrStencilSettings.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "GrStencilSettings.h"
-
-#include "GrProcessor.h"
-
-constexpr const GrUserStencilSettings gUnused(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kKeep,
-        GrUserStencilOp::kKeep,
-        0x0000>()
-);
-
-GR_STATIC_ASSERT(kAll_StencilFlags == (gUnused.fFrontFlags[0] & gUnused.fBackFlags[0]));
-
-const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
-
-void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
-                              int numStencilBits) {
-    uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
-    if (frontFlags & kSingleSided_StencilFlag) {
-        fFlags = frontFlags;
-        if (!this->isDisabled()) {
-            fFront.reset(user.fFront, hasStencilClip, numStencilBits);
-        }
-        return;
-    }
-
-    uint16_t backFlags = user.fBackFlags[hasStencilClip];
-    fFlags = frontFlags & backFlags;
-    if (this->isDisabled()) {
-        return;
-    }
-    if (!(frontFlags & kDisabled_StencilFlag)) {
-        fFront.reset(user.fFront, hasStencilClip, numStencilBits);
-    } else {
-        fFront.setDisabled();
-    }
-    if (!(backFlags & kDisabled_StencilFlag)) {
-        fBack.reset(user.fBack, hasStencilClip, numStencilBits);
-    } else {
-        fBack.setDisabled();
-    }
-}
-
-void GrStencilSettings::reset(const GrStencilSettings& that) {
-    fFlags = that.fFlags;
-    if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
-        return;
-    }
-    if (!this->isTwoSided()) {
-        memcpy(&fFront, &that.fFront, sizeof(Face));
-    } else {
-        memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
-        GR_STATIC_ASSERT(sizeof(Face) ==
-                         offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
-    }
-}
-
-bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
-    if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
-        // At least one is invalid and/or disabled.
-        if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
-            return false; // We never allow invalid stencils to be equal.
-        }
-        // They're only equal if both are disabled.
-        return kDisabled_StencilFlag & (fFlags & that.fFlags);
-    }
-    if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
-        return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
-    } else {
-        return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face));
-        GR_STATIC_ASSERT(sizeof(Face) ==
-                         offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
-    }
-    // memcmp relies on GrStencilSettings::Face being tightly packed.
-    GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
-    GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
-    GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
-    GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
-    GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
-    GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
-    GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
-    GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
-    GR_STATIC_ASSERT(10 == sizeof(Face));
-}
-
-static constexpr GrStencilTest gUserStencilTestToRaw[kGrUserStencilTestCount] = {
-    // Tests that respect the clip.
-    GrStencilTest::kAlways,  // kAlwaysIfInClip (This is only for when there is not a stencil clip).
-    GrStencilTest::kEqual,   // kEqualIfInClip.
-    GrStencilTest::kLess,    // kLessIfInClip.
-    GrStencilTest::kLEqual,  // kLEqualIfInClip.
-
-    // Tests that ignore the clip.
-    GrStencilTest::kAlways,
-    GrStencilTest::kNever,
-    GrStencilTest::kGreater,
-    GrStencilTest::kGEqual,
-    GrStencilTest::kLess,
-    GrStencilTest::kLEqual,
-    GrStencilTest::kEqual,
-    GrStencilTest::kNotEqual
-};
-
-GR_STATIC_ASSERT(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
-GR_STATIC_ASSERT(1 == (int)GrUserStencilTest::kEqualIfInClip);
-GR_STATIC_ASSERT(2 == (int)GrUserStencilTest::kLessIfInClip);
-GR_STATIC_ASSERT(3 == (int)GrUserStencilTest::kLEqualIfInClip);
-GR_STATIC_ASSERT(4 == (int)GrUserStencilTest::kAlways);
-GR_STATIC_ASSERT(5 == (int)GrUserStencilTest::kNever);
-GR_STATIC_ASSERT(6 == (int)GrUserStencilTest::kGreater);
-GR_STATIC_ASSERT(7 == (int)GrUserStencilTest::kGEqual);
-GR_STATIC_ASSERT(8 == (int)GrUserStencilTest::kLess);
-GR_STATIC_ASSERT(9 == (int)GrUserStencilTest::kLEqual);
-GR_STATIC_ASSERT(10 == (int)GrUserStencilTest::kEqual);
-GR_STATIC_ASSERT(11 == (int)GrUserStencilTest::kNotEqual);
-
-static constexpr GrStencilOp gUserStencilOpToRaw[kGrUserStencilOpCount] = {
-    GrStencilOp::kKeep,
-
-    // Ops that only modify user bits.
-    GrStencilOp::kZero,
-    GrStencilOp::kReplace,
-    GrStencilOp::kInvert,
-    GrStencilOp::kIncWrap,
-    GrStencilOp::kDecWrap,
-    GrStencilOp::kIncClamp,  // kIncMaybeClamp.
-    GrStencilOp::kDecClamp,  // kDecMaybeClamp.
-
-    // Ops that only modify the clip bit.
-    GrStencilOp::kZero,      // kZeroClipBit.
-    GrStencilOp::kReplace,   // kSetClipBit.
-    GrStencilOp::kInvert,    // kInvertClipBit.
-
-    // Ops that modify clip and user bits.
-    GrStencilOp::kReplace,   // kSetClipAndReplaceUserBits.
-    GrStencilOp::kZero       // kZeroClipAndUserBits.
-};
-
-GR_STATIC_ASSERT(0 == (int)GrUserStencilOp::kKeep);
-GR_STATIC_ASSERT(1 == (int)GrUserStencilOp::kZero);
-GR_STATIC_ASSERT(2 == (int)GrUserStencilOp::kReplace);
-GR_STATIC_ASSERT(3 == (int)GrUserStencilOp::kInvert);
-GR_STATIC_ASSERT(4 == (int)GrUserStencilOp::kIncWrap);
-GR_STATIC_ASSERT(5 == (int)GrUserStencilOp::kDecWrap);
-GR_STATIC_ASSERT(6 == (int)GrUserStencilOp::kIncMaybeClamp);
-GR_STATIC_ASSERT(7 == (int)GrUserStencilOp::kDecMaybeClamp);
-GR_STATIC_ASSERT(8 == (int)GrUserStencilOp::kZeroClipBit);
-GR_STATIC_ASSERT(9 == (int)GrUserStencilOp::kSetClipBit);
-GR_STATIC_ASSERT(10 == (int)GrUserStencilOp::kInvertClipBit);
-GR_STATIC_ASSERT(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
-GR_STATIC_ASSERT(12 == (int)GrUserStencilOp::kZeroClipAndUserBits);
-
-void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
-                                    int numStencilBits) {
-    SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
-    SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
-    SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
-    SkASSERT(numStencilBits <= 16);
-    int clipBit = 1 << (numStencilBits - 1);
-    int userMask = clipBit - 1;
-
-    GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
-    SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(user.fPassOp, user.fFailOp);)
-    if (maxOp <= kLastUserOnlyStencilOp) {
-        // Ops that only modify user bits.
-        fWriteMask = user.fWriteMask & userMask;
-        SkASSERT(otherOp <= kLastUserOnlyStencilOp);
-    } else if (maxOp <= kLastClipOnlyStencilOp) {
-        // Ops that only modify the clip bit.
-        fWriteMask = clipBit;
-        SkASSERT(GrUserStencilOp::kKeep == otherOp ||
-                 (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
-    } else {
-        // Ops that modify both clip and user bits.
-        fWriteMask = clipBit | (user.fWriteMask & userMask);
-        SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
-    }
-
-    fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
-    fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];
-
-    if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
-        // Ignore the clip.
-        fTestMask = user.fTestMask & userMask;
-        fTest = gUserStencilTestToRaw[(int)user.fTest];
-    } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
-        // Respect the clip.
-        fTestMask = clipBit | (user.fTestMask & userMask);
-        fTest = gUserStencilTestToRaw[(int)user.fTest];
-    } else {
-        // Test only for clip.
-        fTestMask = clipBit;
-        fTest = GrStencilTest::kEqual;
-    }
-
-    fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
-}
-
-void GrStencilSettings::Face::setDisabled() {
-    memset(this, 0, sizeof(*this));
-    GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
-    GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Stencil Rules for Merging user stencil space into clip
-//
-
-///////
-// Replace
-static constexpr GrUserStencilSettings gUserToClipReplace(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kNotEqual,
-        0xffff,
-        GrUserStencilOp::kSetClipAndReplaceUserBits,
-        GrUserStencilOp::kZeroClipAndUserBits,
-        0xffff>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipReplace(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqual,
-        0xffff,
-        GrUserStencilOp::kSetClipAndReplaceUserBits,
-        GrUserStencilOp::kZeroClipAndUserBits,
-        0xffff>()
-);
-
-///////
-// Intersect
-static constexpr GrUserStencilSettings gUserToClipIsect(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits".
-        0xffff,
-        GrUserStencilOp::kSetClipAndReplaceUserBits,
-        GrUserStencilOp::kZeroClipAndUserBits,
-        0xffff>()
-);
-
-///////
-// Difference
-static constexpr GrUserStencilSettings gUserToClipDiff(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqualIfInClip,
-        0xffff,
-        GrUserStencilOp::kSetClipAndReplaceUserBits,
-        GrUserStencilOp::kZeroClipAndUserBits,
-        0xffff>()
-);
-
-///////
-// Union
-static constexpr GrUserStencilSettings gUserToClipUnion(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kNotEqual,
-        0xffff,
-        GrUserStencilOp::kSetClipAndReplaceUserBits,
-        GrUserStencilOp::kKeep,
-        0xffff>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits.
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqual,
-        0xffff,
-        GrUserStencilOp::kSetClipBit,
-        GrUserStencilOp::kKeep,
-        0x0000>()
-);
-
-///////
-// Xor
-static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits.
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kNotEqual,
-        0xffff,
-        GrUserStencilOp::kInvertClipBit,
-        GrUserStencilOp::kKeep,
-        0x0000>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits.
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqual,
-        0xffff,
-        GrUserStencilOp::kInvertClipBit,
-        GrUserStencilOp::kKeep,
-        0x0000>()
-);
-
-///////
-// Reverse Diff
-static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits.
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kNotEqual,
-        0xffff,
-        GrUserStencilOp::kInvertClipBit,
-        GrUserStencilOp::kZeroClipBit,
-        0x0000>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits.
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqual,
-        0xffff,
-        GrUserStencilOp::kInvertClipBit,
-        GrUserStencilOp::kZeroClipBit,
-        0x0000>()
-);
-
-///////
-// Second pass to clear user bits (only needed sometimes)
-static constexpr GrUserStencilSettings gZeroUserBits(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kNotEqual,
-        0xffff,
-        GrUserStencilOp::kZero,
-        GrUserStencilOp::kKeep,
-        0xffff>()
-);
-
-static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = {
-    {  /* Normal fill. */
-        {&gUserToClipDiff,           nullptr,         nullptr},  // kDifference_Op.
-        {&gUserToClipIsect,          nullptr,         nullptr},  // kIntersect_Op.
-        {&gUserToClipUnion,          nullptr,         nullptr},  // kUnion_Op.
-        {&gUserToClipXorPass0,       &gZeroUserBits,  nullptr},  // kXOR_Op.
-        {&gUserToClipRDiffPass0,     &gZeroUserBits,  nullptr},  // kReverseDifference_Op.
-        {&gUserToClipReplace,        nullptr,         nullptr}   // kReplace_Op.
-
-    }, /* Inverse fill. */ {
-        {&gUserToClipIsect,          nullptr,         nullptr},  // ~diff (aka isect).
-        {&gUserToClipDiff,           nullptr,         nullptr},  // ~isect (aka diff).
-        {&gInvUserToClipUnionPass0,  &gZeroUserBits,  nullptr},  // ~union.
-        {&gInvUserToClipXorPass0,    &gZeroUserBits,  nullptr},  // ~xor.
-        {&gInvUserToClipRDiffPass0,  &gZeroUserBits,  nullptr},  // ~reverse diff.
-        {&gInvUserToClipReplace,     nullptr,         nullptr}   // ~replace.
-    }
-};
-
-GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
-GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
-GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
-GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
-GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
-GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
-
-///////
-// Direct to Stencil
-
-// We can render a clip element directly without first writing to the client
-// portion of the clip when the fill is not inverse and the set operation will
-// only modify the in/out status of samples covered by the clip element.
-
-// this one only works if used right after stencil clip was cleared.
-// Our clip mask creation code doesn't allow midstream replace ops.
-static constexpr GrUserStencilSettings gReplaceClip(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kAlways,
-        0xffff,
-        GrUserStencilOp::kSetClipBit,
-        GrUserStencilOp::kSetClipBit,
-        0x0000>()
-);
-
-static constexpr GrUserStencilSettings gUnionClip(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kKeep,
-        GrUserStencilOp::kSetClipBit,
-        0x0000>()
-);
-
-static constexpr GrUserStencilSettings gXorClip(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kAlways,
-        0xffff,
-        GrUserStencilOp::kInvertClipBit,
-        GrUserStencilOp::kInvertClipBit,
-        0x0000>()
-);
-
-static constexpr GrUserStencilSettings gDiffClip(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kZeroClipBit,
-        GrUserStencilOp::kKeep,
-        0x0000>()
-);
-
-static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = {
-    {&gDiffClip,     nullptr},  // kDifference_Op.
-    {nullptr,        nullptr},  // kIntersect_Op.
-    {&gUnionClip,    nullptr},  // kUnion_Op.
-    {&gXorClip,      nullptr},  // kXOR_Op.
-    {nullptr,        nullptr},  // kReverseDifference_Op.
-    {&gReplaceClip,  nullptr}   // kReplace_Op.
-};
-
-GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
-GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
-GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
-GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
-GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
-GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
-
-GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
-                                                                     bool canBeDirect,
-                                                                     bool invertedFill,
-                                                                     bool* drawDirectToClip) {
-    SkASSERT((unsigned)op <= SkRegion::kLastOp);
-    if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
-        GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
-        if (directPass[0]) {
-            *drawDirectToClip = true;
-            return directPass;
-        }
-    }
-    *drawDirectToClip = false;
-    return gUserToClipTable[invertedFill][op];
-}
-
-void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
-    b->add32(fFlags);
-    if (this->isDisabled()) {
-        return;
-    }
-    if (!this->isTwoSided()) {
-        constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
-        GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
-        uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
-        memcpy(key, &fFront, sizeof(Face));
-        key[kCount16] = 0;
-        GR_STATIC_ASSERT(1 == kCount16 % 2);
-    } else {
-        constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
-        GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
-        uint32_t* key = b->add32n(kCount32);
-        memcpy(key, &fFront, 2 * sizeof(Face));
-        GR_STATIC_ASSERT(sizeof(Face) ==
-                         offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
-    }
-    // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
-    GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
-    GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
-    GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
-    GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
-    GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
-    GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
-    GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
-    GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
-    GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
-    GR_STATIC_ASSERT(10 == sizeof(Face));
-}
diff --git a/src/gpu/GrStencilSettings.h b/src/gpu/GrStencilSettings.h
deleted file mode 100644
index 15a8cac..0000000
--- a/src/gpu/GrStencilSettings.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef GrStencilSettings_DEFINED
-#define GrStencilSettings_DEFINED
-
-#include "GrUserStencilSettings.h"
-#include "SkRegion.h"
-
-class GrProcessorKeyBuilder;
-
-enum class GrStencilTest : uint16_t {
-    kAlways,
-    kNever,
-    kGreater,
-    kGEqual,
-    kLess,
-    kLEqual,
-    kEqual,
-    kNotEqual
-};
-static constexpr int kGrStencilTestCount = 1 + (int)GrStencilTest::kNotEqual;
-
-enum class GrStencilOp : uint8_t {
-    kKeep,
-    kZero,
-    kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
-    kInvert,
-    kIncWrap,
-    kDecWrap,
-    // NOTE: clamping occurs before the write mask. So if the MSB is zero and masked out, stencil
-    // values will still wrap when using clamping ops.
-    kIncClamp,
-    kDecClamp
-};
-static constexpr int kGrStencilOpCount = 1 + (int)GrStencilOp::kDecClamp;
-
-/**
- * This class defines concrete stencil settings that map directly to the underlying hardware. It
- * is deduced from user stencil settings, stencil clip status, and the number of bits in the
- * target stencil buffer.
- */
-class GrStencilSettings {
-public:
-    GrStencilSettings() { this->setDisabled(); }
-    GrStencilSettings(const GrUserStencilSettings& user, bool hasStencilClip, int numStencilBits) {
-        this->reset(user, hasStencilClip, numStencilBits);
-    }
-    GrStencilSettings(const GrStencilSettings& that) { this->reset(that); }
-    GrStencilSettings& operator=(const GrStencilSettings& that) { this->reset(that); return *this; }
-
-    void invalidate() { fFlags |= kInvalid_PrivateFlag; }
-    void setDisabled() { fFlags = kAll_StencilFlags; }
-    void reset(const GrUserStencilSettings&, bool hasStencilClip, int numStencilBits);
-    void reset(const GrStencilSettings&);
-
-    bool isValid() const { return !(fFlags & kInvalid_PrivateFlag); }
-    bool isDisabled() const { SkASSERT(this->isValid()); return fFlags & kDisabled_StencilFlag; }
-    bool doesWrite() const { SkASSERT(this->isValid());
-                             return !(fFlags & kNoModifyStencil_StencilFlag); }
-    bool isTwoSided() const { SkASSERT(this->isValid());
-                              return !(fFlags & kSingleSided_StencilFlag); }
-    bool usesWrapOp() const { SkASSERT(this->isValid());
-                              return !(fFlags & kNoWrapOps_StencilFlag); }
-
-    void genKey(GrProcessorKeyBuilder* b) const;
-
-    bool operator!=(const GrStencilSettings& that) const { return !(*this == that); }
-    bool operator==(const GrStencilSettings&) const;
-
-    struct Face : public GrTStencilFaceSettings<GrStencilTest, GrStencilOp> {
-        void reset(const GrUserStencilSettings::Face&, bool useStencilClip, int numStencilBits);
-        void setDisabled();
-    };
-
-    const Face& front() const { SkASSERT(!this->isDisabled()); return fFront; }
-    const Face& back() const { SkASSERT(this->isTwoSided()); return fBack; }
-
-    /**
-     * Given a thing to draw into the stencil clip, a fill type, and a set op
-     * this function determines:
-     *      1. Whether the thing can be draw directly to the stencil clip or
-     *      needs to be drawn to the client portion of the stencil first.
-     *      2. How many passes are needed.
-     *      3. What those passes are.
-     *
-     * @param op                the set op to combine this element with the existing clip
-     * @param canBeDirect       can the caller draw this element directly (without using stencil)?
-     * @param invertedFill      is this path inverted
-     * @param drawDirectToClip  out: true if caller should draw the element directly, false if it
-     *                          should draw it into the user stencil bits first.
-     *
-     * @return a null-terminated array of settings for stencil passes.
-     *
-     *         If drawDirectToClip is false, the caller must first draw the element into the user
-     *         stencil bits, and then cover the clip area with multiple passes using the returned
-     *         stencil settings.
-     *
-     *         If drawDirectToClip is true, the returned array will only have one pass and the
-     *         caller should use those stencil settings while drawing the element directly.
-     */
-    static GrUserStencilSettings const* const* GetClipPasses(SkRegion::Op op,
-                                                             bool canBeDirect,
-                                                             bool invertedFill,
-                                                             bool* drawDirectToClip);
-
-private:
-    // Internal flag for backends to optionally mark their tracked stencil state as invalid.
-    enum { kInvalid_PrivateFlag = (kLast_StencilFlag << 1) };
-
-    uint32_t   fFlags;
-    Face       fFront;
-    Face       fBack;
-};
-
-#endif
diff --git a/src/gpu/GrUserStencilSettings.h b/src/gpu/GrUserStencilSettings.h
deleted file mode 100644
index a07a083..0000000
--- a/src/gpu/GrUserStencilSettings.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef GrUserStencilSettings_DEFINED
-#define GrUserStencilSettings_DEFINED
-
-#include "GrTypes.h"
-
-/**
- * Gr uses the stencil buffer to implement complex clipping inside the
- * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
- * bits available for other uses by external code (user bits). Client code can
- * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
- * provided by clients that fall outside the user range.
- *
- * When code outside the GrDrawTarget class uses the stencil buffer the contract
- * is as follows:
- *
- * > Normal stencil funcs allow the client to pass / fail regardless of the
- *   reserved clip bits.
- * > Additional functions allow a test against the clip along with a limited
- *   set of tests against the user bits.
- * > Client can assume all user bits are zero initially.
- * > Client must ensure that after all its passes are finished it has only
- *   written to the color buffer in the region inside the clip. Furthermore, it
- *   must zero all user bits that were modifed (both inside and outside the
- *   clip).
- */
-
-enum GrStencilFlags {
-    kDisabled_StencilFlag         = 0x1,
-    kNoModifyStencil_StencilFlag  = 0x2,
-    kNoWrapOps_StencilFlag        = 0x4,
-    kSingleSided_StencilFlag      = 0x8,
-
-    kLast_StencilFlag = kSingleSided_StencilFlag,
-    kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1)
-};
-
-template<typename TTest, typename TOp> struct GrTStencilFaceSettings {
-    uint16_t   fRef;        // Reference value for stencil test and ops.
-    TTest      fTest;       // Stencil test function, where fRef is on the left side.
-    uint16_t   fTestMask;   // Bitwise "and" to perform on fRef and stencil values before testing.
-                            // (e.g. (fRef & fTestMask) < (stencil & fTestMask))
-    TOp        fPassOp;     // Op to perform when the test passes.
-    TOp        fFailOp;     // Op to perform when the test fails.
-    uint16_t   fWriteMask;  // Indicates which bits in the stencil buffer should be updated.
-                            // (e.g. stencil = (newValue & fWriteMask) | (stencil & ~fWriteMask))
-};
-
-enum class GrUserStencilTest : uint16_t {
-    // Tests that respect the clip bit. If a stencil clip is not in effect, the "IfInClip" is
-    // ignored and these only act on user bits.
-    kAlwaysIfInClip,
-    kEqualIfInClip,
-    kLessIfInClip,
-    kLEqualIfInClip,
-
-    // Tests that ignore the clip bit. The client is responsible to ensure no color write occurs
-    // outside the clip if it is in use.
-    kAlways,
-    kNever,
-    kGreater,
-    kGEqual,
-    kLess,
-    kLEqual,
-    kEqual,
-    kNotEqual
-};
-constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip;
-constexpr static int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual;
-
-enum class GrUserStencilOp : uint8_t {
-    kKeep,
-
-    // Ops that only modify user bits. These must not be paired with ops that modify the clip bit.
-    kZero,
-    kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
-    kInvert,
-    kIncWrap,
-    kDecWrap,
-    // These two should only be used if wrap ops are not supported, or if the math is guaranteed
-    // to not overflow. The user bits may or may not clamp, depending on the state of non-user bits.
-    kIncMaybeClamp,
-    kDecMaybeClamp,
-
-    // Ops that only modify the clip bit. These must not be paired with ops that modify user bits.
-    kZeroClipBit,
-    kSetClipBit,
-    kInvertClipBit,
-
-    // Ops that modify both clip and user bits. These can only be paired with kKeep or each other.
-    kSetClipAndReplaceUserBits,
-    kZeroClipAndUserBits
-};
-constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp;
-constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit;
-constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits;
-
-/**
- * This struct is a compile-time constant representation of user stencil settings. It describes in
- * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime to define a
- * draw's stencil settings, and is later translated into concrete settings when the pipeline is
- * finalized.
- */
-struct GrUserStencilSettings {
-    typedef GrTStencilFaceSettings<GrUserStencilTest, GrUserStencilOp> Face;
-
-    template<GrUserStencilTest, GrUserStencilOp PassOp, GrUserStencilOp FailOp> struct Attrs;
-
-    // Unfortunately, this is the only way to pass template arguments to a constructor.
-    template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
-             GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> struct Init {};
-
-    template<uint16_t FtRef,            uint16_t BkRef,
-             GrUserStencilTest FtTest,  GrUserStencilTest BkTest,
-             uint16_t FtTestMask,       uint16_t BkTestMask,
-             GrUserStencilOp FtPassOp,  GrUserStencilOp BkPassOp,
-             GrUserStencilOp FtFailOp,  GrUserStencilOp BkFailOp,
-             uint16_t FtWriteMask,      uint16_t BkWriteMask> struct InitSeparate {};
-
-    template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
-             GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask>
-    constexpr static Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask> StaticInit() {
-        return Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>();
-    }
-
-    template<uint16_t FtRef,            uint16_t BkRef,
-             GrUserStencilTest FtTest,  GrUserStencilTest BkTest,
-             uint16_t FtTestMask,       uint16_t BkTestMask,
-             GrUserStencilOp FtPassOp,  GrUserStencilOp BkPassOp,
-             GrUserStencilOp FtFailOp,  GrUserStencilOp BkFailOp,
-             uint16_t FtWriteMask,      uint16_t BkWriteMask>
-    constexpr static InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
-                                  FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask,
-                                  BkWriteMask> StaticInitSeparate() {
-        return InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
-                            FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>();
-    }
-
-    // We construct with template arguments in order to enforce that the struct be compile-time
-    // constant and to make use of static asserts.
-    template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
-             GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask,
-             typename Attrs = Attrs<Test, PassOp, FailOp> >
-    constexpr explicit GrUserStencilSettings(
-            const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&)
-        : fFrontFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
-                      (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
-        , fFront{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
-                 Attrs::EffectiveWriteMask(WriteMask)}
-        , fBackFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
-                     (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
-        , fBack{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
-                Attrs::EffectiveWriteMask(WriteMask)} {
-    }
-
-    template<uint16_t FtRef,            uint16_t BkRef,
-             GrUserStencilTest FtTest,  GrUserStencilTest BkTest,
-             uint16_t FtTestMask,       uint16_t BkTestMask,
-             GrUserStencilOp FtPassOp,  GrUserStencilOp BkPassOp,
-             GrUserStencilOp FtFailOp,  GrUserStencilOp BkFailOp,
-             uint16_t FtWriteMask,      uint16_t BkWriteMask,
-             typename FtAttrs = Attrs<FtTest, FtPassOp, FtFailOp>,
-             typename BkAttrs = Attrs<BkTest, BkPassOp, BkFailOp> >
-    constexpr explicit GrUserStencilSettings(
-            const InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
-                               FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>&)
-        : fFrontFlags{FtAttrs::Flags(false), FtAttrs::Flags(true)}
-        , fFront{FtRef, FtTest, FtAttrs::EffectiveTestMask(FtTestMask), FtPassOp, FtFailOp,
-                 FtAttrs::EffectiveWriteMask(FtWriteMask)}
-        , fBackFlags{BkAttrs::Flags(false), BkAttrs::Flags(true)}
-        , fBack{BkRef, BkTest, BkAttrs::EffectiveTestMask(BkTestMask), BkPassOp, BkFailOp,
-                BkAttrs::EffectiveWriteMask(BkWriteMask)} {}
-
-    // This struct can only be constructed with static initializers.
-    GrUserStencilSettings() = delete;
-    GrUserStencilSettings(const GrUserStencilSettings&) = delete;
-
-    const uint16_t   fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip].
-    const Face       fFront;
-    const uint16_t   fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip].
-    const Face       fBack;
-
-    static const GrUserStencilSettings& kUnused;
-};
-
-template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
-struct GrUserStencilSettings::Attrs {
-    // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
-    GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
-                     (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
-    // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
-    GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
-                     (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
-
-    constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
-        return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
-                GrUserStencilTest::kAlways == Test;
-    }
-    constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
-        return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
-                (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
-    }
-    constexpr static bool IsDisabled(bool hasStencilClip) {
-        return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
-    }
-    constexpr static bool UsesWrapOps() {
-        return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
-               GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
-    }
-    constexpr static bool TestIgnoresRef() {
-        return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
-                GrUserStencilTest::kNever == Test);
-    }
-    constexpr static uint16_t Flags(bool hasStencilClip) {
-        return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
-               (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
-               (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
-    }
-    constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
-        return TestIgnoresRef() ? 0 : testMask;
-    }
-    constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) {
-        // We don't modify the mask differently when hasStencilClip=false because either the entire
-        // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the
-        // effective mask stays the same either way.
-        return DoesNotModifyStencil(true) ? 0 : writeMask;
-    }
-};
-
-#endif
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index 747be2d..9994b26 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -443,11 +443,11 @@
     // face culling doesn't make sense here
     SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
 
-    int                          passCount = 0;
-    const GrUserStencilSettings* passes[3];
-    GrPipelineBuilder::DrawFace  drawFace[3];
-    bool                         reverse = false;
-    bool                         lastPassIsBounds;
+    int                         passCount = 0;
+    const GrStencilSettings*    passes[3];
+    GrPipelineBuilder::DrawFace drawFace[3];
+    bool                        reverse = false;
+    bool                        lastPassIsBounds;
 
     if (isHairline) {
         passCount = 1;
@@ -544,7 +544,7 @@
     for (int p = 0; p < passCount; ++p) {
         pipelineBuilder->setDrawFace(drawFace[p]);
         if (passes[p]) {
-            pipelineBuilder->setUserStencil(passes[p]);
+            *pipelineBuilder->stencil() = *passes[p];
         }
 
         if (lastPassIsBounds && (p == passCount-1)) {
diff --git a/src/gpu/batches/GrDrawPathBatch.h b/src/gpu/batches/GrDrawPathBatch.h
index 55fe31a..d29d046 100644
--- a/src/gpu/batches/GrDrawPathBatch.h
+++ b/src/gpu/batches/GrDrawPathBatch.h
@@ -28,10 +28,7 @@
 
     GrPathRendering::FillType fillType() const { return fFillType; }
 
-    void setStencilSettings(const GrUserStencilSettings& stencil, bool hasStencilClip,
-                            int numStencilBits) {
-        fStencilSettings.reset(stencil, hasStencilClip, numStencilBits);
-    }
+    void setStencilSettings(const GrStencilSettings& stencil) { fStencilSettings = stencil; }
 
 protected:
     GrDrawPathBatchBase(uint32_t classID, const SkMatrix& viewMatrix, GrColor initialColor,
diff --git a/src/gpu/batches/GrMSAAPathRenderer.cpp b/src/gpu/batches/GrMSAAPathRenderer.cpp
index 8b1319b..6e0076c 100644
--- a/src/gpu/batches/GrMSAAPathRenderer.cpp
+++ b/src/gpu/batches/GrMSAAPathRenderer.cpp
@@ -578,11 +578,11 @@
     // face culling doesn't make sense here
     SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
 
-    int                          passCount = 0;
-    const GrUserStencilSettings* passes[3];
-    GrPipelineBuilder::DrawFace  drawFace[3];
-    bool                         reverse = false;
-    bool                         lastPassIsBounds;
+    int                         passCount = 0;
+    const GrStencilSettings*    passes[3];
+    GrPipelineBuilder::DrawFace drawFace[3];
+    bool                        reverse = false;
+    bool                        lastPassIsBounds;
 
     if (single_pass_path(path)) {
         passCount = 1;
@@ -647,7 +647,7 @@
     for (int p = 0; p < passCount; ++p) {
         pipelineBuilder->setDrawFace(drawFace[p]);
         if (passes[p]) {
-            pipelineBuilder->setUserStencil(passes[p]);
+            *pipelineBuilder->stencil() = *passes[p];
         }
 
         if (lastPassIsBounds && (p == passCount-1)) {
diff --git a/src/gpu/batches/GrPathStencilSettings.h b/src/gpu/batches/GrPathStencilSettings.h
index f37d1b2..dd930a0d 100644
--- a/src/gpu/batches/GrPathStencilSettings.h
+++ b/src/gpu/batches/GrPathStencilSettings.h
@@ -8,44 +8,36 @@
 #ifndef GrPathStencilSettings_DEFINED
 #define GrPathStencilSettings_DEFINED
 
-#include "GrUserStencilSettings.h"
-
 ////////////////////////////////////////////////////////////////////////////////
 // Stencil rules for paths
 
 ////// Even/Odd
 
-static constexpr GrUserStencilSettings gEOStencilPass(
-    GrUserStencilSettings::StaticInit<
-        0xffff,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kInvert,
-        GrUserStencilOp::kKeep,
-        0xffff>()
-);
+static constexpr GrStencilSettings gEOStencilPass(
+    kInvert_StencilOp,
+    kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,
+    0xffff,
+    0xffff,
+    0xffff);
 
 // ok not to check clip b/c stencil pass only wrote inside clip
-static constexpr GrUserStencilSettings gEOColorPass(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kNotEqual,
-        0xffff,
-        GrUserStencilOp::kZero,
-        GrUserStencilOp::kZero,
-        0xffff>()
-);
+static constexpr GrStencilSettings gEOColorPass(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kNotEqual_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff);
 
 // have to check clip b/c outside clip will always be zero.
-static constexpr GrUserStencilSettings gInvEOColorPass(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqualIfInClip,
-        0xffff,
-        GrUserStencilOp::kZero,
-        GrUserStencilOp::kZero,
-        0xffff>()
-);
+static constexpr GrStencilSettings gInvEOColorPass(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kEqualIfInClip_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff);
 
 ////// Winding
 
@@ -53,108 +45,90 @@
 // when we don't have wrap incr and decr we use the stencil test to simulate
 // them.
 
-static constexpr GrUserStencilSettings gWindStencilSeparateWithWrap(
-    GrUserStencilSettings::StaticInitSeparate<
-        0xffff,                                0xffff,
-        GrUserStencilTest::kAlwaysIfInClip,    GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,                                0xffff,
-        GrUserStencilOp::kIncWrap,             GrUserStencilOp::kDecWrap,
-        GrUserStencilOp::kKeep,                GrUserStencilOp::kKeep,
-        0xffff,                                0xffff>()
-);
+static constexpr GrStencilSettings gWindStencilSeparateWithWrap(
+    kIncWrap_StencilOp,             kDecWrap_StencilOp,
+    kKeep_StencilOp,                kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
+    0xffff,                         0xffff,
+    0xffff,                         0xffff,
+    0xffff,                         0xffff);
 
 // if inc'ing the max value, invert to make 0
 // if dec'ing zero invert to make all ones.
 // we can't avoid touching the stencil on both passing and
 // failing, so we can't resctrict ourselves to the clip.
-static constexpr GrUserStencilSettings gWindStencilSeparateNoWrap(
-    GrUserStencilSettings::StaticInitSeparate<
-        0xffff,                                0x0000,
-        GrUserStencilTest::kEqual,             GrUserStencilTest::kEqual,
-        0xffff,                                0xffff,
-        GrUserStencilOp::kInvert,              GrUserStencilOp::kInvert,
-        GrUserStencilOp::kIncMaybeClamp,       GrUserStencilOp::kDecMaybeClamp,
-        0xffff,                                0xffff>()
-);
+static constexpr GrStencilSettings gWindStencilSeparateNoWrap(
+    kInvert_StencilOp,              kInvert_StencilOp,
+    kIncClamp_StencilOp,            kDecClamp_StencilOp,
+    kEqual_StencilFunc,             kEqual_StencilFunc,
+    0xffff,                         0xffff,
+    0xffff,                         0x0000,
+    0xffff,                         0xffff);
 
 // When there are no separate faces we do two passes to setup the winding rule
 // stencil. First we draw the front faces and inc, then we draw the back faces
 // and dec. These are same as the above two split into the incrementing and
 // decrementing passes.
-static constexpr GrUserStencilSettings gWindSingleStencilWithWrapInc(
-    GrUserStencilSettings::StaticInit<
-        0xffff,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kIncWrap,
-        GrUserStencilOp::kKeep,
-        0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilWithWrapInc(
+    kIncWrap_StencilOp,
+    kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,
+    0xffff,
+    0xffff,
+    0xffff);
 
-static constexpr GrUserStencilSettings gWindSingleStencilWithWrapDec(
-    GrUserStencilSettings::StaticInit<
-        0xffff,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kDecWrap,
-        GrUserStencilOp::kKeep,
-        0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilWithWrapDec(
+    kDecWrap_StencilOp,
+    kKeep_StencilOp,
+    kAlwaysIfInClip_StencilFunc,
+    0xffff,
+    0xffff,
+    0xffff);
 
-static constexpr GrUserStencilSettings gWindSingleStencilNoWrapInc(
-    GrUserStencilSettings::StaticInit<
-        0xffff,
-        GrUserStencilTest::kEqual,
-        0xffff,
-        GrUserStencilOp::kInvert,
-        GrUserStencilOp::kIncMaybeClamp,
-        0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilNoWrapInc(
+    kInvert_StencilOp,
+    kIncClamp_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,
+    0xffff,
+    0xffff);
 
-static constexpr GrUserStencilSettings gWindSingleStencilNoWrapDec(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqual,
-        0xffff,
-        GrUserStencilOp::kInvert,
-        GrUserStencilOp::kDecMaybeClamp,
-        0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilNoWrapDec(
+    kInvert_StencilOp,
+    kDecClamp_StencilOp,
+    kEqual_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff);
 
 // Color passes are the same whether we use the two-sided stencil or two passes
 
-static constexpr GrUserStencilSettings gWindColorPass(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kLessIfInClip, // "0 < stencil" is equivalent to "0 != stencil".
-        0xffff,
-        GrUserStencilOp::kZero,
-        GrUserStencilOp::kZero,
-        0xffff>()
-);
+static constexpr GrStencilSettings gWindColorPass(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kNonZeroIfInClip_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff);
 
-static constexpr GrUserStencilSettings gInvWindColorPass(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kEqualIfInClip,
-        0xffff,
-        GrUserStencilOp::kZero,
-        GrUserStencilOp::kZero,
-        0xffff>()
-);
+static constexpr GrStencilSettings gInvWindColorPass(
+    kZero_StencilOp,
+    kZero_StencilOp,
+    kEqualIfInClip_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff);
 
 ////// Normal render to stencil
 
 // Sometimes the default path renderer can draw a path directly to the stencil
 // buffer without having to first resolve the interior / exterior.
-static constexpr GrUserStencilSettings gDirectToStencil(
-    GrUserStencilSettings::StaticInit<
-        0x0000,
-        GrUserStencilTest::kAlwaysIfInClip,
-        0xffff,
-        GrUserStencilOp::kZero,
-        GrUserStencilOp::kIncMaybeClamp,
-        0xffff>()
-);
+static constexpr GrStencilSettings gDirectToStencil(
+    kZero_StencilOp,
+    kIncClamp_StencilOp,
+    kAlwaysIfInClip_StencilFunc,
+    0xffff,
+    0x0000,
+    0xffff);
 
 #endif
diff --git a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
index 1309ded..ddba1c8 100644
--- a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
@@ -36,7 +36,7 @@
     if (args.fStyle->hasNonDashPathEffect() || args.fStyle->strokeRec().isHairlineStyle()) {
         return false;
     }
-    if (args.fHasUserStencilSettings) {
+    if (!args.fIsStencilDisabled) {
         return false;
     }
     if (args.fAntiAlias) {
@@ -80,7 +80,7 @@
     GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
     const SkMatrix& viewMatrix = *args.fViewMatrix;
 
-    SkASSERT(!pipelineBuilder->hasUserStencilSettings());
+    SkASSERT(pipelineBuilder->getStencil().isDisabled());
 
     if (args.fAntiAlias) {
         SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
@@ -90,21 +90,18 @@
     SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStyle));
 
     if (path.isInverseFillType()) {
-        static constexpr GrUserStencilSettings kInvertedCoverPass(
-            GrUserStencilSettings::StaticInit<
-                0x0000,
-                // We know our rect will hit pixels outside the clip and the user bits will be 0
-                // outside the clip. So we can't just fill where the user bits are 0. We also need
-                // to check that the clip bit is set.
-                GrUserStencilTest::kEqualIfInClip,
-                0xffff,
-                GrUserStencilOp::kKeep,
-                GrUserStencilOp::kZero,
-                0xffff>()
-        );
+        static constexpr GrStencilSettings kInvertedStencilPass(
+            kKeep_StencilOp,
+            kZero_StencilOp,
+            // We know our rect will hit pixels outside the clip and the user bits will be 0
+            // outside the clip. So we can't just fill where the user bits are 0. We also need to
+            // check that the clip bit is set.
+            kEqualIfInClip_StencilFunc,
+            0xffff,
+            0x0000,
+            0xffff);
 
-
-        pipelineBuilder->setUserStencil(&kInvertedCoverPass);
+        pipelineBuilder->setStencil(kInvertedStencilPass);
 
         // fake inverse with a stencil and cover
         args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
@@ -136,22 +133,20 @@
                                                     &invert));
         args.fTarget->drawBatch(*pipelineBuilder, batch);
     } else {
-        static constexpr GrUserStencilSettings kCoverPass(
-            GrUserStencilSettings::StaticInit<
-                0x0000,
-                GrUserStencilTest::kNotEqual,
-                0xffff,
-                GrUserStencilOp::kZero,
-                GrUserStencilOp::kKeep,
-                0xffff>()
-        );
+        static constexpr GrStencilSettings kStencilPass(
+            kZero_StencilOp,
+            kKeep_StencilOp,
+            kNotEqual_StencilFunc,
+            0xffff,
+            0x0000,
+            0xffff);
 
-        pipelineBuilder->setUserStencil(&kCoverPass);
+        pipelineBuilder->setStencil(kStencilPass);
         SkAutoTUnref<GrDrawPathBatchBase> batch(
                 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
         args.fTarget->drawPathBatch(*pipelineBuilder, batch);
     }
 
-    pipelineBuilder->disableUserStencil();
+    pipelineBuilder->stencil()->setDisabled();
     return true;
 }
diff --git a/src/gpu/batches/GrStencilPathBatch.h b/src/gpu/batches/GrStencilPathBatch.h
index 8477822..33189c2 100644
--- a/src/gpu/batches/GrStencilPathBatch.h
+++ b/src/gpu/batches/GrStencilPathBatch.h
@@ -21,14 +21,11 @@
 
     static GrBatch* Create(const SkMatrix& viewMatrix,
                            bool useHWAA,
-                           const GrUserStencilSettings& userStencil,
-                           bool hasStencilClip,
-                           int numStencilBits,
+                           const GrStencilSettings& stencil,
                            const GrScissorState& scissor,
                            GrRenderTarget* renderTarget,
                            const GrPath* path) {
-        return new GrStencilPathBatch(viewMatrix, useHWAA, userStencil, hasStencilClip,
-                                      numStencilBits, scissor, renderTarget, path);
+        return new GrStencilPathBatch(viewMatrix, useHWAA, stencil, scissor, renderTarget, path);
     }
 
     const char* name() const override { return "StencilPath"; }
@@ -45,16 +42,14 @@
 private:
     GrStencilPathBatch(const SkMatrix& viewMatrix,
                        bool useHWAA,
-                       const GrUserStencilSettings& userStencil,
-                       bool hasStencilClip,
-                       int numStencilBits,
+                       const GrStencilSettings& stencil,
                        const GrScissorState& scissor,
                        GrRenderTarget* renderTarget,
                        const GrPath* path)
     : INHERITED(ClassID())
     , fViewMatrix(viewMatrix)
     , fUseHWAA(useHWAA)
-    , fStencil(userStencil, hasStencilClip, numStencilBits)
+    , fStencil(stencil)
     , fScissor(scissor)
     , fRenderTarget(renderTarget)
     , fPath(path) {
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 6b03df3..004a4a9 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2874,38 +2874,40 @@
 
 
 GrGLenum gr_to_gl_stencil_op(GrStencilOp op) {
-    static const GrGLenum gTable[kGrStencilOpCount] = {
-        GR_GL_KEEP,        // kKeep
-        GR_GL_ZERO,        // kZero
-        GR_GL_REPLACE,     // kReplace
-        GR_GL_INVERT,      // kInvert
-        GR_GL_INCR_WRAP,   // kIncWrap
-        GR_GL_DECR_WRAP,   // kDecWrap
-        GR_GL_INCR,        // kIncClamp
-        GR_GL_DECR,        // kDecClamp
+    static const GrGLenum gTable[] = {
+        GR_GL_KEEP,        // kKeep_StencilOp
+        GR_GL_REPLACE,     // kReplace_StencilOp
+        GR_GL_INCR_WRAP,   // kIncWrap_StencilOp
+        GR_GL_INCR,        // kIncClamp_StencilOp
+        GR_GL_DECR_WRAP,   // kDecWrap_StencilOp
+        GR_GL_DECR,        // kDecClamp_StencilOp
+        GR_GL_ZERO,        // kZero_StencilOp
+        GR_GL_INVERT,      // kInvert_StencilOp
     };
-    GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
-    GR_STATIC_ASSERT(1 == (int)GrStencilOp::kZero);
-    GR_STATIC_ASSERT(2 == (int)GrStencilOp::kReplace);
-    GR_STATIC_ASSERT(3 == (int)GrStencilOp::kInvert);
-    GR_STATIC_ASSERT(4 == (int)GrStencilOp::kIncWrap);
-    GR_STATIC_ASSERT(5 == (int)GrStencilOp::kDecWrap);
-    GR_STATIC_ASSERT(6 == (int)GrStencilOp::kIncClamp);
-    GR_STATIC_ASSERT(7 == (int)GrStencilOp::kDecClamp);
-    SkASSERT(op < (GrStencilOp)kGrStencilOpCount);
-    return gTable[(int)op];
+    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kStencilOpCnt);
+    GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+    GR_STATIC_ASSERT(1 == kReplace_StencilOp);
+    GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
+    GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
+    GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
+    GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
+    GR_STATIC_ASSERT(6 == kZero_StencilOp);
+    GR_STATIC_ASSERT(7 == kInvert_StencilOp);
+    SkASSERT((unsigned) op < kStencilOpCnt);
+    return gTable[op];
 }
 
 void set_gl_stencil(const GrGLInterface* gl,
-                    const GrStencilSettings::Face& face,
-                    GrGLenum glFace) {
-    GrGLenum glFunc = GrToGLStencilFunc(face.fTest);
-    GrGLenum glFailOp = gr_to_gl_stencil_op(face.fFailOp);
-    GrGLenum glPassOp = gr_to_gl_stencil_op(face.fPassOp);
+                    const GrStencilSettings& settings,
+                    GrGLenum glFace,
+                    GrStencilSettings::Face grFace) {
+    GrGLenum glFunc = GrToGLStencilFunc(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 = face.fRef;
-    GrGLint mask = face.fTestMask;
-    GrGLint writeMask = face.fWriteMask;
+    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
@@ -2935,18 +2937,20 @@
             }
         }
         if (!stencilSettings.isDisabled()) {
-            if (stencilSettings.isTwoSided()) {
-                SkASSERT(this->caps()->twoSidedStencilSupport());
+            if (this->caps()->twoSidedStencilSupport()) {
                 set_gl_stencil(this->glInterface(),
-                               stencilSettings.front(),
-                               GR_GL_FRONT);
+                               stencilSettings,
+                               GR_GL_FRONT,
+                               GrStencilSettings::kFront_Face);
                 set_gl_stencil(this->glInterface(),
-                               stencilSettings.back(),
-                               GR_GL_BACK);
+                               stencilSettings,
+                               GR_GL_BACK,
+                               GrStencilSettings::kBack_Face);
             } else {
                 set_gl_stencil(this->glInterface(),
-                               stencilSettings.front(),
-                               GR_GL_FRONT_AND_BACK);
+                               stencilSettings,
+                               GR_GL_FRONT_AND_BACK,
+                               GrStencilSettings::kFront_Face);
             }
         }
         fHWStencilSettings = stencilSettings;
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 66648d8..5616f9d 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -70,9 +70,9 @@
         default:
             SkFAIL("Unexpected path fill.");
             /* fallthrough */;
-        case GrStencilOp::kIncClamp:
+        case kIncClamp_StencilOp:
             return GR_GL_COUNT_UP;
-        case GrStencilOp::kInvert:
+        case kInvert_StencilOp:
             return GR_GL_INVERT;
     }
 }
@@ -133,9 +133,9 @@
     this->flushPathStencilSettings(*args.fStencil);
     SkASSERT(!fHWPathStencilSettings.isTwoSided());
 
-    GrGLenum fillMode =
-        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
-    GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
+    GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
+        fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
 
     if (glPath->shouldFill()) {
         GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
@@ -157,9 +157,9 @@
     this->flushPathStencilSettings(stencil);
     SkASSERT(!fHWPathStencilSettings.isTwoSided());
 
-    GrGLenum fillMode =
-        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
-    GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
+    GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
+        fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
 
     if (glPath->shouldStroke()) {
         if (glPath->shouldFill()) {
@@ -191,8 +191,10 @@
     const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
 
     GrGLenum fillMode =
-        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
-    GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
+        gr_stencil_op_to_gl_path_rendering_fill_mode(
+            fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask =
+        fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
 
     if (glPathRange->shouldStroke()) {
         if (glPathRange->shouldFill()) {
@@ -320,15 +322,16 @@
         SkASSERT(stencilSettings.isValid());
         // Just the func, ref, and mask is set here. The op and write mask are params to the call
         // that draws the path to the SB (glStencilFillPath)
-        uint16_t ref = stencilSettings.front().fRef;
-        GrStencilTest test = stencilSettings.front().fTest;
-        uint16_t testMask = stencilSettings.front().fTestMask;
+        const GrStencilSettings::Face kFront_Face = GrStencilSettings::kFront_Face;
+        GrStencilFunc func = stencilSettings.func(kFront_Face);
+        uint16_t funcRef = stencilSettings.funcRef(kFront_Face);
+        uint16_t funcMask = stencilSettings.funcMask(kFront_Face);
 
         if (!fHWPathStencilSettings.isValid() ||
-            ref != fHWPathStencilSettings.front().fRef ||
-            test != fHWPathStencilSettings.front().fTest ||
-            testMask != fHWPathStencilSettings.front().fTestMask) {
-            GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
+            func != fHWPathStencilSettings.func(kFront_Face) ||
+            funcRef != fHWPathStencilSettings.funcRef(kFront_Face) ||
+            funcMask != fHWPathStencilSettings.funcMask(kFront_Face)) {
+            GL_CALL(PathStencilFunc(GrToGLStencilFunc(func), funcRef, funcMask));
         }
         fHWPathStencilSettings = stencilSettings;
     }
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index 40f72cc..8fb699d 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -10,12 +10,12 @@
 
 #include "SkRefCnt.h"
 #include "GrPathRendering.h"
+#include "GrStencil.h"
 #include "gl/GrGLTypes.h"
 #include "glsl/GrGLSLUtil.h"
 
 class GrGLNameAllocator;
 class GrGLGpu;
-class GrStencilSettings;
 class GrStyle;
 
 /**
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index ecc587b..46b58f1 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -334,26 +334,27 @@
     return GrGLGetRendererFromString((const char*) v);
 }
 
-GrGLenum GrToGLStencilFunc(GrStencilTest test) {
-    static const GrGLenum gTable[kGrStencilTestCount] = {
-        GR_GL_ALWAYS,           // kAlways
-        GR_GL_NEVER,            // kNever
-        GR_GL_GREATER,          // kGreater
-        GR_GL_GEQUAL,           // kGEqual
-        GR_GL_LESS,             // kLess
-        GR_GL_LEQUAL,           // kLEqual
-        GR_GL_EQUAL,            // kEqual
-        GR_GL_NOTEQUAL,         // kNotEqual
+GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc) {
+    static const GrGLenum gTable[] = {
+        GR_GL_ALWAYS,           // kAlways_StencilFunc
+        GR_GL_NEVER,            // kNever_StencilFunc
+        GR_GL_GREATER,          // kGreater_StencilFunc
+        GR_GL_GEQUAL,           // kGEqual_StencilFunc
+        GR_GL_LESS,             // kLess_StencilFunc
+        GR_GL_LEQUAL,           // kLEqual_StencilFunc,
+        GR_GL_EQUAL,            // kEqual_StencilFunc,
+        GR_GL_NOTEQUAL,         // kNotEqual_StencilFunc,
     };
-    GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
-    GR_STATIC_ASSERT(1 == (int)GrStencilTest::kNever);
-    GR_STATIC_ASSERT(2 == (int)GrStencilTest::kGreater);
-    GR_STATIC_ASSERT(3 == (int)GrStencilTest::kGEqual);
-    GR_STATIC_ASSERT(4 == (int)GrStencilTest::kLess);
-    GR_STATIC_ASSERT(5 == (int)GrStencilTest::kLEqual);
-    GR_STATIC_ASSERT(6 == (int)GrStencilTest::kEqual);
-    GR_STATIC_ASSERT(7 == (int)GrStencilTest::kNotEqual);
-    SkASSERT(test < (GrStencilTest)kGrStencilTestCount);
+    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCnt);
+    GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+    GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+    GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+    GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+    GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+    GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+    GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+    GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+    SkASSERT((unsigned) basicFunc < kBasicStencilFuncCnt);
 
-    return gTable[(int)test];
+    return gTable[basicFunc];
 }
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index 98f738b..c30ee93 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -10,7 +10,7 @@
 
 #include "gl/GrGLInterface.h"
 #include "GrGLDefines.h"
-#include "GrStencilSettings.h"
+#include "GrStencil.h"
 
 class SkMatrix;
 
@@ -205,7 +205,7 @@
 // call glGetError without doing a redundant error check or logging.
 #define GR_GL_GET_ERROR(IFACE) (IFACE)->fFunctions.fGetError()
 
-GrGLenum GrToGLStencilFunc(GrStencilTest test);
+GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc);
 
 
 #endif
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index bce0716..cc01884 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -610,17 +610,15 @@
     if (fInstanceData->count()) {
         pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());
 
-        static constexpr GrUserStencilSettings kCoverPass(
-            GrUserStencilSettings::StaticInit<
-                0x0000,
-                GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
-                0xffff,
-                GrUserStencilOp::kZero,
-                GrUserStencilOp::kKeep,
-                0xffff>()
-        );
+        static constexpr GrStencilSettings kStencilPass(
+             kZero_StencilOp,
+             kKeep_StencilOp,
+             kNotEqual_StencilFunc,
+             0xffff,
+             0x0000,
+             0xffff);
 
-        pipelineBuilder->setUserStencil(&kCoverPass);
+        *pipelineBuilder->stencil() = kStencilPass;
 
         SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
         if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
diff --git a/src/gpu/vk/GrVkPipeline.cpp b/src/gpu/vk/GrVkPipeline.cpp
index 8227e12..2a9c6e2 100644
--- a/src/gpu/vk/GrVkPipeline.cpp
+++ b/src/gpu/vk/GrVkPipeline.cpp
@@ -100,51 +100,51 @@
 
 VkStencilOp stencil_op_to_vk_stencil_op(GrStencilOp op) {
     static const VkStencilOp gTable[] = {
-        VK_STENCIL_OP_KEEP,                 // kKeep
-        VK_STENCIL_OP_ZERO,                 // kZero
-        VK_STENCIL_OP_REPLACE,              // kReplace
-        VK_STENCIL_OP_INVERT,               // kInvert
-        VK_STENCIL_OP_INCREMENT_AND_WRAP,   // kIncWrap
-        VK_STENCIL_OP_DECREMENT_AND_WRAP,   // kDecWrap
-        VK_STENCIL_OP_INCREMENT_AND_CLAMP,  // kIncClamp
-        VK_STENCIL_OP_DECREMENT_AND_CLAMP,  // kDecClamp
+        VK_STENCIL_OP_KEEP,                 // kKeep_StencilOp
+        VK_STENCIL_OP_REPLACE,              // kReplace_StencilOp
+        VK_STENCIL_OP_INCREMENT_AND_WRAP,   // kIncWrap_StencilOp
+        VK_STENCIL_OP_INCREMENT_AND_CLAMP,  // kIncClamp_StencilOp
+        VK_STENCIL_OP_DECREMENT_AND_WRAP,   // kDecWrap_StencilOp
+        VK_STENCIL_OP_DECREMENT_AND_CLAMP,  // kDecClamp_StencilOp
+        VK_STENCIL_OP_ZERO,                 // kZero_StencilOp
+        VK_STENCIL_OP_INVERT,               // kInvert_StencilOp
     };
-    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kGrStencilOpCount);
-    GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
-    GR_STATIC_ASSERT(1 == (int)GrStencilOp::kZero);
-    GR_STATIC_ASSERT(2 == (int)GrStencilOp::kReplace);
-    GR_STATIC_ASSERT(3 == (int)GrStencilOp::kInvert);
-    GR_STATIC_ASSERT(4 == (int)GrStencilOp::kIncWrap);
-    GR_STATIC_ASSERT(5 == (int)GrStencilOp::kDecWrap);
-    GR_STATIC_ASSERT(6 == (int)GrStencilOp::kIncClamp);
-    GR_STATIC_ASSERT(7 == (int)GrStencilOp::kDecClamp);
-    SkASSERT(op < (GrStencilOp)kGrStencilOpCount);
-    return gTable[(int)op];
+    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kStencilOpCnt);
+    GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+    GR_STATIC_ASSERT(1 == kReplace_StencilOp);
+    GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
+    GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
+    GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
+    GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
+    GR_STATIC_ASSERT(6 == kZero_StencilOp);
+    GR_STATIC_ASSERT(7 == kInvert_StencilOp);
+    SkASSERT((unsigned)op < kStencilOpCnt);
+    return gTable[op];
 }
 
-VkCompareOp stencil_func_to_vk_compare_op(GrStencilTest test) {
+VkCompareOp stencil_func_to_vk_compare_op(GrStencilFunc basicFunc) {
     static const VkCompareOp gTable[] = {
-        VK_COMPARE_OP_ALWAYS,              // kAlways
-        VK_COMPARE_OP_NEVER,               // kNever
-        VK_COMPARE_OP_GREATER,             // kGreater
-        VK_COMPARE_OP_GREATER_OR_EQUAL,    // kGEqual
-        VK_COMPARE_OP_LESS,                // kLess
-        VK_COMPARE_OP_LESS_OR_EQUAL,       // kLEqual
-        VK_COMPARE_OP_EQUAL,               // kEqual
-        VK_COMPARE_OP_NOT_EQUAL,           // kNotEqual
+        VK_COMPARE_OP_ALWAYS,              // kAlways_StencilFunc
+        VK_COMPARE_OP_NEVER,               // kNever_StencilFunc
+        VK_COMPARE_OP_GREATER,             // kGreater_StencilFunc
+        VK_COMPARE_OP_GREATER_OR_EQUAL,    // kGEqual_StencilFunc
+        VK_COMPARE_OP_LESS,                // kLess_StencilFunc
+        VK_COMPARE_OP_LESS_OR_EQUAL,       // kLEqual_StencilFunc,
+        VK_COMPARE_OP_EQUAL,               // kEqual_StencilFunc,
+        VK_COMPARE_OP_NOT_EQUAL,           // kNotEqual_StencilFunc,
     };
-    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kGrStencilTestCount);
-    GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
-    GR_STATIC_ASSERT(1 == (int)GrStencilTest::kNever);
-    GR_STATIC_ASSERT(2 == (int)GrStencilTest::kGreater);
-    GR_STATIC_ASSERT(3 == (int)GrStencilTest::kGEqual);
-    GR_STATIC_ASSERT(4 == (int)GrStencilTest::kLess);
-    GR_STATIC_ASSERT(5 == (int)GrStencilTest::kLEqual);
-    GR_STATIC_ASSERT(6 == (int)GrStencilTest::kEqual);
-    GR_STATIC_ASSERT(7 == (int)GrStencilTest::kNotEqual);
-    SkASSERT(test < (GrStencilTest)kGrStencilTestCount);
+    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCnt);
+    GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+    GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+    GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+    GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+    GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+    GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+    GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+    GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+    SkASSERT((unsigned)basicFunc < kBasicStencilFuncCnt);
 
-    return gTable[(int)test];
+    return gTable[basicFunc];
 }
 
 void setup_depth_stencil_state(const GrVkGpu* gpu,
@@ -162,28 +162,24 @@
     stencilInfo->stencilTestEnable = !stencilSettings.isDisabled();
     if (!stencilSettings.isDisabled()) {
         // Set front face
-        const GrStencilSettings::Face& front = stencilSettings.front();
-        stencilInfo->front.failOp = stencil_op_to_vk_stencil_op(front.fFailOp);
-        stencilInfo->front.passOp = stencil_op_to_vk_stencil_op(front.fPassOp);
+        GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
+        stencilInfo->front.failOp = stencil_op_to_vk_stencil_op(stencilSettings.failOp(face));
+        stencilInfo->front.passOp = stencil_op_to_vk_stencil_op(stencilSettings.passOp(face));
         stencilInfo->front.depthFailOp = stencilInfo->front.failOp;
-        stencilInfo->front.compareOp = stencil_func_to_vk_compare_op(front.fTest);
-        stencilInfo->front.compareMask = front.fTestMask;
-        stencilInfo->front.writeMask = front.fWriteMask;
-        stencilInfo->front.reference = front.fRef;
+        stencilInfo->front.compareOp = stencil_func_to_vk_compare_op(stencilSettings.func(face));
+        stencilInfo->front.compareMask = stencilSettings.funcMask(face);
+        stencilInfo->front.writeMask = stencilSettings.writeMask(face);
+        stencilInfo->front.reference = stencilSettings.funcRef(face);
 
         // Set back face
-        if (!stencilSettings.isTwoSided()) {
-            stencilInfo->back = stencilInfo->front;
-        } else {
-            const GrStencilSettings::Face& back = stencilSettings.back();
-            stencilInfo->back.failOp = stencil_op_to_vk_stencil_op(back.fFailOp);
-            stencilInfo->back.passOp = stencil_op_to_vk_stencil_op(back.fPassOp);
-            stencilInfo->back.depthFailOp = stencilInfo->front.failOp;
-            stencilInfo->back.compareOp = stencil_func_to_vk_compare_op(back.fTest);
-            stencilInfo->back.compareMask = back.fTestMask;
-            stencilInfo->back.writeMask = back.fWriteMask;
-            stencilInfo->back.reference = back.fRef;
-        }
+        face = GrStencilSettings::kBack_Face;
+        stencilInfo->back.failOp = stencil_op_to_vk_stencil_op(stencilSettings.failOp(face));
+        stencilInfo->back.passOp = stencil_op_to_vk_stencil_op(stencilSettings.passOp(face));
+        stencilInfo->back.depthFailOp = stencilInfo->front.failOp;
+        stencilInfo->back.compareOp = stencil_func_to_vk_compare_op(stencilSettings.func(face));
+        stencilInfo->back.compareMask = stencilSettings.funcMask(face);
+        stencilInfo->back.writeMask = stencilSettings.writeMask(face);
+        stencilInfo->back.reference = stencilSettings.funcRef(face);
     }
     stencilInfo->minDepthBounds = 0.0f;
     stencilInfo->maxDepthBounds = 1.0f;
diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h
index d0b0f56..b7f954c 100644
--- a/src/gpu/vk/GrVkPipelineState.h
+++ b/src/gpu/vk/GrVkPipelineState.h
@@ -9,7 +9,6 @@
 #ifndef GrVkPipelineState_DEFINED
 #define GrVkPipelineState_DEFINED
 
-#include "GrStencilSettings.h"
 #include "GrVkImage.h"
 #include "GrVkProgramDesc.h"
 #include "GrVkPipelineStateDataManager.h"
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 3cbc76c..c5d61d8 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -277,29 +277,25 @@
 
 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
 static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
-    static constexpr GrUserStencilSettings kDoesWriteStencil(
-        GrUserStencilSettings::StaticInit<
-            0xffff,
-            GrUserStencilTest::kAlways,
-            0xffff,
-            GrUserStencilOp::kReplace,
-            GrUserStencilOp::kReplace,
-            0xffff>()
-    );
-    static constexpr GrUserStencilSettings kDoesNotWriteStencil(
-        GrUserStencilSettings::StaticInit<
-            0xffff,
-            GrUserStencilTest::kNever,
-            0xffff,
-            GrUserStencilOp::kKeep,
-            GrUserStencilOp::kKeep,
-            0xffff>()
-    );
+    static constexpr GrStencilSettings kDoesWriteStencil(
+         kReplace_StencilOp,
+         kReplace_StencilOp,
+         kAlways_StencilFunc,
+         0xffff,
+         0xffff,
+         0xffff);
+    static constexpr GrStencilSettings kDoesNotWriteStencil(
+         kKeep_StencilOp,
+         kKeep_StencilOp,
+         kNever_StencilFunc,
+         0xffff,
+         0xffff,
+         0xffff);
 
     if (random->nextBool()) {
-        pipelineBuilder->setUserStencil(&kDoesWriteStencil);
+        pipelineBuilder->setStencil(kDoesWriteStencil);
     } else {
-        pipelineBuilder->setUserStencil(&kDoesNotWriteStencil);
+        pipelineBuilder->setStencil(kDoesNotWriteStencil);
     }
 }