Move user stencil settings from GrPipeline to GrProgramInfo

Bug: skia:10419
Change-Id: If11d28f6d9348ba0011825f719123c09f0103603
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319481
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/gm/tessellation.cpp b/gm/tessellation.cpp
index 34c58cc..4e300aa 100644
--- a/gm/tessellation.cpp
+++ b/gm/tessellation.cpp
@@ -345,8 +345,9 @@
 
         GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
                                   state->proxy()->backendFormat(), state->writeView()->origin(),
-                                  &pipeline, shader.get(), GrPrimitiveType::kPatches,
-                                  tessellationPatchVertexCount, state->renderPassBarriers());
+                                  &pipeline, &GrUserStencilSettings::kUnused, shader.get(),
+                                  GrPrimitiveType::kPatches, tessellationPatchVertexCount,
+                                  state->renderPassBarriers());
 
         state->bindPipeline(programInfo, SkRect::MakeIWH(kWidth, kHeight));
         state->bindBuffers(nullptr, nullptr, std::move(fVertexBuffer));
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index 89434d4..2201b65 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -35,7 +35,8 @@
 }
 
 void GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp(
-        const GrOp* op, const SkRect& chainBounds, const GrPipeline* pipeline) {
+        const GrOp* op, const SkRect& chainBounds, const GrPipeline* pipeline,
+        const GrUserStencilSettings* userStencilSettings) {
     SkASSERT(this->opsRenderPass());
 
     while (fCurrDraw != fDraws.end() && fCurrDraw->fOp == op) {
@@ -51,6 +52,7 @@
                                   this->proxy()->backendFormat(),
                                   this->writeView()->origin(),
                                   pipeline,
+                                  userStencilSettings,
                                   fCurrDraw->fGeometryProcessor,
                                   fCurrDraw->fPrimitiveType,
                                   0,
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h
index f833ef2..84d0bc9 100644
--- a/src/gpu/GrOpFlushState.h
+++ b/src/gpu/GrOpFlushState.h
@@ -46,7 +46,7 @@
 
     /** Called as ops are executed. Must be called in the same order as the ops were prepared. */
     void executeDrawsAndUploadsForMeshDrawOp(const GrOp* op, const SkRect& chainBounds,
-                                             const GrPipeline*);
+                                             const GrPipeline*, const GrUserStencilSettings*);
 
     GrOpsRenderPass* opsRenderPass() { return fOpsRenderPass; }
     void setOpsRenderPass(GrOpsRenderPass* renderPass) { fOpsRenderPass = renderPass; }
diff --git a/src/gpu/GrOpsRenderPass.cpp b/src/gpu/GrOpsRenderPass.cpp
index cd329de..4dde2cc 100644
--- a/src/gpu/GrOpsRenderPass.cpp
+++ b/src/gpu/GrOpsRenderPass.cpp
@@ -77,8 +77,8 @@
          SkASSERT(this->gpu()->caps()->wireframeSupport());
     }
     if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
-        programInfo.pipeline().isStencilEnabled()) {
-        const GrUserStencilSettings* stencil = programInfo.pipeline().getUserStencil();
+        programInfo.isStencilEnabled()) {
+        const GrUserStencilSettings* stencil = programInfo.userStencilSettings();
         if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
             SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
             SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index a16ee31..39e3f06 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -28,7 +28,6 @@
     }
 
     fWindowRectsState = hardClip.windowRectsState();
-    this->setUserStencil(args.fUserStencil);
 
     fXferProcessor = std::move(xferProcessor);
 
@@ -74,8 +73,7 @@
 GrPipeline::GrPipeline(GrScissorTest scissorTest,
                        sk_sp<const GrXferProcessor> xp,
                        const GrSwizzle& writeSwizzle,
-                       InputFlags inputFlags,
-                       const GrUserStencilSettings* userStencil)
+                       InputFlags inputFlags)
         : fWindowRectsState()
         , fFlags((Flags)inputFlags)
         , fXferProcessor(std::move(xp))
@@ -83,7 +81,6 @@
     if (GrScissorTest::kEnabled == scissorTest) {
         fFlags |= Flags::kScissorTestEnabled;
     }
-    this->setUserStencil(userStencil);
 }
 
 void GrPipeline::genKey(GrProcessorKeyBuilder* b, const GrCaps& caps) const {
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 43f278d..fcc35d2 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -67,7 +67,6 @@
 
     struct InitArgs {
         InputFlags fInputFlags = InputFlags::kNone;
-        const GrUserStencilSettings* fUserStencil = &GrUserStencilSettings::kUnused;
         const GrCaps* fCaps = nullptr;
         GrXferProcessor::DstProxyView fDstProxyView;
         GrSwizzle fWriteSwizzle;
@@ -81,19 +80,16 @@
     GrPipeline(GrScissorTest scissor,
                SkBlendMode blend,
                const GrSwizzle& writeSwizzle,
-               InputFlags flags = InputFlags::kNone,
-               const GrUserStencilSettings* stencil = &GrUserStencilSettings::kUnused)
+               InputFlags flags = InputFlags::kNone)
             : GrPipeline(scissor,
                          GrPorterDuffXPFactory::MakeNoCoverageXP(blend),
                          writeSwizzle,
-                         flags,
-                         stencil) {}
+                         flags) {}
 
     GrPipeline(GrScissorTest,
                sk_sp<const GrXferProcessor>,
                const GrSwizzle& writeSwizzle,
-               InputFlags = InputFlags::kNone,
-               const GrUserStencilSettings* = &GrUserStencilSettings::kUnused);
+               InputFlags = InputFlags::kNone);
 
     GrPipeline(const InitArgs& args, sk_sp<const GrXferProcessor>, const GrAppliedHardClip&);
     GrPipeline(const InitArgs&, GrProcessorSet&&, GrAppliedClip&&);
@@ -167,14 +163,6 @@
 
     /// @}
 
-    const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; }
-    void setUserStencil(const GrUserStencilSettings* stencil) {
-        fUserStencilSettings = stencil;
-        if (!fUserStencilSettings->isDisabled(fFlags & Flags::kHasStencilClip)) {
-            fFlags |= Flags::kStencilEnabled;
-        }
-    }
-
     bool isScissorTestEnabled() const {
         return SkToBool(fFlags & Flags::kScissorTestEnabled);
     }
@@ -190,9 +178,6 @@
     bool hasStencilClip() const {
         return SkToBool(fFlags & Flags::kHasStencilClip);
     }
-    bool isStencilEnabled() const {
-        return SkToBool(fFlags & Flags::kStencilEnabled);
-    }
 #ifdef SK_DEBUG
     bool allProxiesInstantiated() const {
         for (int i = 0; i < fFragmentProcessors.count(); ++i) {
@@ -223,8 +208,7 @@
     /** This is a continuation of the public "InputFlags" enum. */
     enum class Flags : uint8_t {
         kHasStencilClip = (kLastInputFlag << 1),
-        kStencilEnabled = (kLastInputFlag << 2),
-        kScissorTestEnabled = (kLastInputFlag << 3),
+        kScissorTestEnabled = (kLastInputFlag << 2),
     };
 
     GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags);
@@ -241,7 +225,6 @@
     // GrDstSampleType).
     GrDstSampleType fDstSampleType = GrDstSampleType::kNone;
     GrWindowRectsState fWindowRectsState;
-    const GrUserStencilSettings* fUserStencilSettings;
     Flags fFlags;
     sk_sp<const GrXferProcessor> fXferProcessor;
     FragmentProcessorArray fFragmentProcessors;
diff --git a/src/gpu/GrProgramInfo.cpp b/src/gpu/GrProgramInfo.cpp
index 9256fff..85f5121 100644
--- a/src/gpu/GrProgramInfo.cpp
+++ b/src/gpu/GrProgramInfo.cpp
@@ -12,10 +12,8 @@
 GrStencilSettings GrProgramInfo::nonGLStencilSettings() const {
     GrStencilSettings stencil;
 
-    if (this->pipeline().isStencilEnabled()) {
-        stencil.reset(*this->pipeline().getUserStencil(),
-                      this->pipeline().hasStencilClip(),
-                      8);
+    if (this->isStencilEnabled()) {
+        stencil.reset(*fUserStencilSettings, this->pipeline().hasStencilClip(), 8);
     }
 
     return stencil;
diff --git a/src/gpu/GrProgramInfo.h b/src/gpu/GrProgramInfo.h
index cbcce48..be0f77d 100644
--- a/src/gpu/GrProgramInfo.h
+++ b/src/gpu/GrProgramInfo.h
@@ -21,20 +21,22 @@
                   const GrBackendFormat& backendFormat,
                   GrSurfaceOrigin origin,
                   const GrPipeline* pipeline,
+                  const GrUserStencilSettings* userStencilSettings,
                   const GrPrimitiveProcessor* primProc,
                   GrPrimitiveType primitiveType,
                   uint8_t tessellationPatchVertexCount,
                   GrXferBarrierFlags renderPassXferBarriers)
             : fNumSamples(numSamples)
             , fNumStencilSamples(numStencilSamples)
-            , fIsMixedSampled(pipeline->isStencilEnabled() && numStencilSamples > numSamples)
             , fBackendFormat(backendFormat)
             , fOrigin(origin)
             , fPipeline(pipeline)
+            , fUserStencilSettings(userStencilSettings)
             , fPrimProc(primProc)
             , fPrimitiveType(primitiveType)
             , fTessellationPatchVertexCount(tessellationPatchVertexCount)
-            , fRenderPassXferBarriers(renderPassXferBarriers) {
+            , fRenderPassXferBarriers(renderPassXferBarriers)
+            , fIsMixedSampled(this->isStencilEnabled() && numStencilSamples > numSamples) {
         SkASSERT(this->numRasterSamples() > 0);
         SkASSERT((GrPrimitiveType::kPatches == fPrimitiveType) ==
                  (fTessellationPatchVertexCount > 0));
@@ -51,10 +53,13 @@
 
     int numSamples() const { return fNumSamples; }
     int numStencilSamples() const { return fNumStencilSamples; }
-    bool isStencilEnabled() const { return fPipeline->isStencilEnabled(); }
-
+    bool isStencilEnabled() const {
+        return fUserStencilSettings != &GrUserStencilSettings::kUnused ||
+               fPipeline->hasStencilClip();
+    }
+    const GrUserStencilSettings* userStencilSettings() const { return fUserStencilSettings; }
     int numRasterSamples() const {
-        return fPipeline->isStencilEnabled() ? fNumStencilSamples : fNumSamples;
+        return this->isStencilEnabled() ? fNumStencilSamples : fNumSamples;
     }
     bool isMixedSampled() const { return fIsMixedSampled; }
     // The backend format of the destination render target [proxy]
@@ -97,15 +102,16 @@
 private:
     const int                             fNumSamples;
     const int                             fNumStencilSamples;
-    const bool                            fIsMixedSampled;
     const GrBackendFormat                 fBackendFormat;
     const GrSurfaceOrigin                 fOrigin;
     const GrPipeline*                     fPipeline;
+    const GrUserStencilSettings*          fUserStencilSettings;
     const GrPrimitiveProcessor*           fPrimProc;
     GrProcessor::CustomFeatures           fRequestedFeatures;
     GrPrimitiveType                       fPrimitiveType;
     uint8_t                               fTessellationPatchVertexCount;  // GrPrimType::kPatches.
     GrXferBarrierFlags                    fRenderPassXferBarriers;
+    const bool                            fIsMixedSampled;
 };
 
 #endif
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index 782cc23..5c382e2 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -196,11 +196,12 @@
 }
 
 void GrCCCoverageProcessor::bindPipeline(GrOpFlushState* flushState, const GrPipeline& pipeline,
-                                         const SkRect& drawBounds) const {
+                                         const SkRect& drawBounds,
+                                         const GrUserStencilSettings* stencil) const {
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->writeView()->origin(), &pipeline, this,
+                              flushState->writeView()->origin(), &pipeline, stencil, this,
                               this->primType(), 0, flushState->renderPassBarriers());
     flushState->bindPipeline(programInfo, drawBounds);
 }
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index c7a9639..8b4821f 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -111,7 +111,8 @@
     // subpassIdx of each PrimitiveType, it calls reset/bind*/drawInstances.
     virtual int numSubpasses() const = 0;
     virtual void reset(PrimitiveType, int subpassIdx, GrResourceProvider*) = 0;
-    void bindPipeline(GrOpFlushState*, const GrPipeline&, const SkRect& drawBounds) const;
+    void bindPipeline(GrOpFlushState*, const GrPipeline&, const SkRect& drawBounds,
+                      const GrUserStencilSettings* = &GrUserStencilSettings::kUnused) const;
     virtual void bindBuffers(GrOpsRenderPass*, sk_sp<const GrBuffer> instanceBuffer) const = 0;
     virtual void drawInstances(GrOpsRenderPass*, int instanceCount, int baseInstance) const = 0;
 
diff --git a/src/gpu/ccpr/GrCCFiller.cpp b/src/gpu/ccpr/GrCCFiller.cpp
index 783be74..27250cc 100644
--- a/src/gpu/ccpr/GrCCFiller.cpp
+++ b/src/gpu/ccpr/GrCCFiller.cpp
@@ -472,7 +472,7 @@
 
 void GrCCFiller::drawFills(
         GrOpFlushState* flushState, GrCCCoverageProcessor* proc, const GrPipeline& pipeline,
-        BatchID batchID, const SkIRect& drawBounds) const {
+        BatchID batchID, const SkIRect& drawBounds, const GrUserStencilSettings* stencil) const {
     using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
 
     SkASSERT(fInstanceBuffer.hasGpuBuffer());
@@ -485,7 +485,7 @@
     if (batchTotalCounts.fTriangles) {
         for (int i = 0; i < numSubpasses; ++i) {
             proc->reset(PrimitiveType::kTriangles, i, rp);
-            this->drawPrimitives(flushState, *proc, pipeline, batchID,
+            this->drawPrimitives(flushState, *proc, pipeline, stencil, batchID,
                                  &PrimitiveTallies::fTriangles, drawBounds);
         }
     }
@@ -494,7 +494,7 @@
         SkASSERT(Algorithm::kStencilWindingCount != fAlgorithm);
         for (int i = 0; i < numSubpasses; ++i) {
             proc->reset(PrimitiveType::kWeightedTriangles, i, rp);
-            this->drawPrimitives(flushState, *proc, pipeline, batchID,
+            this->drawPrimitives(flushState, *proc, pipeline, stencil, batchID,
                                  &PrimitiveTallies::fWeightedTriangles, drawBounds);
         }
     }
@@ -502,7 +502,7 @@
     if (batchTotalCounts.fQuadratics) {
         for (int i = 0; i < numSubpasses; ++i) {
             proc->reset(PrimitiveType::kQuadratics, i, rp);
-            this->drawPrimitives(flushState, *proc, pipeline, batchID,
+            this->drawPrimitives(flushState, *proc, pipeline, stencil, batchID,
                                  &PrimitiveTallies::fQuadratics, drawBounds);
         }
     }
@@ -510,27 +510,28 @@
     if (batchTotalCounts.fCubics) {
         for (int i = 0; i < numSubpasses; ++i) {
             proc->reset(PrimitiveType::kCubics, i, rp);
-            this->drawPrimitives(flushState, *proc, pipeline, batchID, &PrimitiveTallies::fCubics,
-                                 drawBounds);
+            this->drawPrimitives(flushState, *proc, pipeline, stencil, batchID,
+                                 &PrimitiveTallies::fCubics, drawBounds);
         }
     }
 
     if (batchTotalCounts.fConics) {
         for (int i = 0; i < numSubpasses; ++i) {
             proc->reset(PrimitiveType::kConics, i, rp);
-            this->drawPrimitives(flushState, *proc, pipeline, batchID, &PrimitiveTallies::fConics,
-                                 drawBounds);
+            this->drawPrimitives(flushState, *proc, pipeline, stencil, batchID,
+                                 &PrimitiveTallies::fConics, drawBounds);
         }
     }
 }
 
 void GrCCFiller::drawPrimitives(
         GrOpFlushState* flushState, const GrCCCoverageProcessor& proc, const GrPipeline& pipeline,
-        BatchID batchID, int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const {
+        const GrUserStencilSettings* stencil, BatchID batchID, int PrimitiveTallies::*instanceType,
+        const SkIRect& drawBounds) const {
     SkASSERT(pipeline.isScissorTestEnabled());
 
     GrOpsRenderPass* renderPass = flushState->opsRenderPass();
-    proc.bindPipeline(flushState, pipeline, SkRect::Make(drawBounds));
+    proc.bindPipeline(flushState, pipeline, SkRect::Make(drawBounds), stencil);
     proc.bindBuffers(renderPass, fInstanceBuffer.gpuBuffer());
 
     SkASSERT(batchID > 0);
diff --git a/src/gpu/ccpr/GrCCFiller.h b/src/gpu/ccpr/GrCCFiller.h
index f90bc85..b27ea7b 100644
--- a/src/gpu/ccpr/GrCCFiller.h
+++ b/src/gpu/ccpr/GrCCFiller.h
@@ -51,7 +51,8 @@
 
     // Called after prepareToDraw(). Draws the given batch of path fills.
     void drawFills(GrOpFlushState*, GrCCCoverageProcessor*, const GrPipeline&, BatchID,
-                   const SkIRect& drawBounds) const;
+                   const SkIRect& drawBounds,
+                   const GrUserStencilSettings* = &GrUserStencilSettings::kUnused) const;
 
 private:
     static constexpr int kNumScissorModes = 2;
@@ -107,7 +108,8 @@
             GrCCCoverageProcessor::TriPointInstance::Ordering,
             GrCCCoverageProcessor::TriPointInstance*, GrCCCoverageProcessor::QuadPointInstance*,
             GrCCFillGeometry::PrimitiveTallies*);
-    void drawPrimitives(GrOpFlushState*, const GrCCCoverageProcessor&, const GrPipeline&, BatchID,
+    void drawPrimitives(GrOpFlushState*, const GrCCCoverageProcessor&, const GrPipeline&,
+                        const GrUserStencilSettings*, BatchID,
                         int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const;
 
     const Algorithm fAlgorithm;
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index d381274..fcae131 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -147,7 +147,7 @@
     GrRenderTargetProxy* rtProxy = flushState->proxy();
     GrProgramInfo programInfo(rtProxy->numSamples(), rtProxy->numStencilSamples(),
                               rtProxy->backendFormat(), flushState->writeView()->origin(),
-                              &pipeline, this, primitiveType, 0,
+                              &pipeline, &GrUserStencilSettings::kUnused, this, primitiveType, 0,
                               flushState->renderPassBarriers());
 
     flushState->bindPipelineAndScissorClip(programInfo, bounds);
diff --git a/src/gpu/ccpr/GrCCStroker.cpp b/src/gpu/ccpr/GrCCStroker.cpp
index a6b00f8..debb8d4 100644
--- a/src/gpu/ccpr/GrCCStroker.cpp
+++ b/src/gpu/ccpr/GrCCStroker.cpp
@@ -729,9 +729,9 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->writeView()->origin(), &pipeline, &processor,
-                              GrPrimitiveType::kTriangleStrip, 0,
-                              flushState->renderPassBarriers());
+                              flushState->writeView()->origin(), &pipeline,
+                              &GrUserStencilSettings::kUnused, &processor,
+                              GrPrimitiveType::kTriangleStrip, 0, flushState->renderPassBarriers());
 
     flushState->bindPipeline(programInfo, SkRect::Make(drawBounds));
     flushState->bindBuffers(nullptr, fInstanceBuffer, nullptr);
diff --git a/src/gpu/ccpr/GrStencilAtlasOp.cpp b/src/gpu/ccpr/GrStencilAtlasOp.cpp
index bee43b0..ba6c88e 100644
--- a/src/gpu/ccpr/GrStencilAtlasOp.cpp
+++ b/src/gpu/ccpr/GrStencilAtlasOp.cpp
@@ -142,15 +142,12 @@
 
     GrPipeline pipeline(GrScissorTest::kEnabled, GrDisableColorXPFactory::MakeXferProcessor(),
                         flushState->drawOpArgs().writeSwizzle(),
-                        GrPipeline::InputFlags::kHWAntialias, &kIncrDecrStencil);
+                        GrPipeline::InputFlags::kHWAntialias);
 
     GrSampleMaskProcessor sampleMaskProc;
 
     fResources->filler().drawFills(
-            flushState, &sampleMaskProc, pipeline, fFillBatchID, drawBoundsRect);
-
-    fResources->stroker().drawStrokes(
-            flushState, &sampleMaskProc, fStrokeBatchID, drawBoundsRect);
+            flushState, &sampleMaskProc, pipeline, fFillBatchID, drawBoundsRect, &kIncrDecrStencil);
 
     // We resolve the stencil coverage to alpha by drawing pixel-aligned boxes. Fine raster is
     // not necessary, and will even cause artifacts if using mixed samples.
@@ -161,12 +158,10 @@
     StencilResolveProcessor primProc;
 
     if (!flushState->caps().twoSidedStencilRefsAndMasksMustMatch()) {
-        if (flushState->caps().discardStencilValuesAfterRenderPass()) {
-            resolvePipeline.setUserStencil(&kResolveStencilCoverage);
-        } else {
-            resolvePipeline.setUserStencil(&kResolveStencilCoverageAndReset);
-        }
-        this->drawResolve(flushState, resolvePipeline, primProc, drawBoundsRect);
+        const GrUserStencilSettings* stencil =
+                (flushState->caps().discardStencilValuesAfterRenderPass()) ?
+                &kResolveStencilCoverage : &kResolveStencilCoverageAndReset;
+        this->drawResolve(flushState, resolvePipeline, stencil, primProc, drawBoundsRect);
         return;
     }
 
@@ -174,21 +169,21 @@
     // don't reset back to zero.
     SkASSERT(!flushState->caps().discardStencilValuesAfterRenderPass());
 
-    resolvePipeline.setUserStencil(&kResolveWindingCoverageAndReset);
-    this->drawResolve(flushState, resolvePipeline, primProc, drawBoundsRect);
-
-    resolvePipeline.setUserStencil(&kResolveEvenOddCoverageAndReset);
-    this->drawResolve(flushState, resolvePipeline, primProc, drawBoundsRect);
+    this->drawResolve(flushState, resolvePipeline, &kResolveWindingCoverageAndReset, primProc,
+                      drawBoundsRect);
+    this->drawResolve(flushState, resolvePipeline, &kResolveEvenOddCoverageAndReset, primProc,
+                      drawBoundsRect);
 }
 
 void GrStencilAtlasOp::drawResolve(GrOpFlushState* flushState, const GrPipeline& resolvePipeline,
+                                   const GrUserStencilSettings* stencil,
                                    const GrPrimitiveProcessor& primProc,
                                    const SkIRect& drawBounds) const {
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->writeView()->origin(), &resolvePipeline, &primProc,
-                              GrPrimitiveType::kTriangleStrip, 0,
+                              flushState->writeView()->origin(), &resolvePipeline, stencil,
+                              &primProc, GrPrimitiveType::kTriangleStrip, 0,
                               flushState->renderPassBarriers());
     flushState->bindPipeline(programInfo, SkRect::Make(drawBounds));
     flushState->setScissorRect(drawBounds);
diff --git a/src/gpu/ccpr/GrStencilAtlasOp.h b/src/gpu/ccpr/GrStencilAtlasOp.h
index d749dc4..72ab6b3 100644
--- a/src/gpu/ccpr/GrStencilAtlasOp.h
+++ b/src/gpu/ccpr/GrStencilAtlasOp.h
@@ -60,8 +60,8 @@
                       GrXferBarrierFlags renderPassXferBarriers) override {}
     void onPrepare(GrOpFlushState*) override {}
     void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
-    void drawResolve(GrOpFlushState*, const GrPipeline&, const GrPrimitiveProcessor&,
-                     const SkIRect& drawBounds) const;
+    void drawResolve(GrOpFlushState*, const GrPipeline&, const GrUserStencilSettings*,
+                     const GrPrimitiveProcessor&, const SkIRect& drawBounds) const;
 
     friend class ::GrOpMemoryPool; // for ctor
 
diff --git a/src/gpu/dawn/GrDawnOpsRenderPass.cpp b/src/gpu/dawn/GrDawnOpsRenderPass.cpp
index 700aef5..552b134 100644
--- a/src/gpu/dawn/GrDawnOpsRenderPass.cpp
+++ b/src/gpu/dawn/GrDawnOpsRenderPass.cpp
@@ -120,10 +120,10 @@
     auto bindGroup = program->setUniformData(fGpu, fRenderTarget, programInfo);
     fPassEncoder.SetPipeline(program->fRenderPipeline);
     fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
-    const GrPipeline& pipeline = programInfo.pipeline();
-    if (pipeline.isStencilEnabled()) {
-        fPassEncoder.SetStencilReference(pipeline.getUserStencil()->fCCWFace.fRef);
+    if (programInfo.isStencilEnabled()) {
+        fPassEncoder.SetStencilReference(programInfo.userStencilSettings()->fCCWFace.fRef);
     }
+    const GrPipeline& pipeline = programInfo.pipeline();
     GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
     const float* c = blendInfo.fBlendConstant.vec();
     wgpu::Color color{c[0], c[1], c[2], c[3]};
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.cpp b/src/gpu/dawn/GrDawnProgramBuilder.cpp
index 5242941..62965f1 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.cpp
+++ b/src/gpu/dawn/GrDawnProgramBuilder.cpp
@@ -351,7 +351,7 @@
     wgpu::DepthStencilStateDescriptor depthStencilState;
 
 #ifdef SK_DEBUG
-    if (pipeline.isStencilEnabled()) {
+    if (programInfo.isStencilEnabled()) {
         SkASSERT(renderTarget->numStencilBits() == 8);
     }
 #endif
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 49115b37..6156086 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1864,9 +1864,9 @@
 
     GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget);
     GrStencilSettings stencil;
-    if (programInfo.pipeline().isStencilEnabled()) {
+    if (programInfo.isStencilEnabled()) {
         SkASSERT(glRT->getStencilAttachment());
-        stencil.reset(*programInfo.pipeline().getUserStencil(),
+        stencil.reset(*programInfo.userStencilSettings(),
                       programInfo.pipeline().hasStencilClip(),
                       glRT->numStencilBits());
     }
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index 340992c..695e412 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -1035,14 +1035,14 @@
     b.add32(programInfo.numRasterSamples());
 
 #ifdef SK_DEBUG
-    if (rt && programInfo.pipeline().isStencilEnabled()) {
+    if (rt && programInfo.isStencilEnabled()) {
         SkASSERT(rt->getStencilAttachment());
     }
 #endif
 
     b.add32(rt && rt->getStencilAttachment() ? this->preferredStencilFormat().fInternalFormat
                                              : MTLPixelFormatInvalid);
-    b.add32((uint32_t)programInfo.pipeline().isStencilEnabled());
+    b.add32((uint32_t)programInfo.isStencilEnabled());
     // Stencil samples don't seem to be tracked in the MTLRenderPipeline
 
     programInfo.pipeline().genKey(&b, *this);
diff --git a/src/gpu/mtl/GrMtlPipelineState.mm b/src/gpu/mtl/GrMtlPipelineState.mm
index 7ce78181..500bb1c 100644
--- a/src/gpu/mtl/GrMtlPipelineState.mm
+++ b/src/gpu/mtl/GrMtlPipelineState.mm
@@ -74,7 +74,7 @@
     fDataManager.resetDirtyBits();
 
 #ifdef SK_DEBUG
-    if (programInfo.pipeline().isStencilEnabled()) {
+    if (programInfo.isStencilEnabled()) {
         SkASSERT(renderTarget->getStencilAttachment());
         SkASSERT(renderTarget->numStencilBits() == 8);
     }
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index bc40662..202cb37 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -1020,7 +1020,7 @@
 
     fProgramInfos[0] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
             arena, pipeline, writeView, lineGP, GrPrimitiveType::kTriangles,
-            renderPassXferBarriers);
+            renderPassXferBarriers, fHelper.stencilSettings());
 }
 
 void AAHairlineOp::makeQuadProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
@@ -1044,7 +1044,7 @@
 
     fProgramInfos[1] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
             arena, pipeline, writeView, quadGP, GrPrimitiveType::kTriangles,
-            renderPassXferBarriers);
+            renderPassXferBarriers, fHelper.stencilSettings());
 }
 
 void AAHairlineOp::makeConicProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
@@ -1068,7 +1068,7 @@
 
     fProgramInfos[2] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
             arena, pipeline, writeView, conicGP, GrPrimitiveType::kTriangles,
-            renderPassXferBarriers);
+            renderPassXferBarriers, fHelper.stencilSettings());
 }
 
 AAHairlineOp::Program AAHairlineOp::predictPrograms(const GrCaps* caps) const {
@@ -1118,8 +1118,8 @@
         geometryProcessorLocalM = &SkMatrix::I();
     }
 
-    auto pipeline = fHelper.createPipelineWithStencil(caps, arena, writeView->swizzle(),
-                                                      std::move(appliedClip), dstProxyView);
+    auto pipeline = fHelper.createPipeline(caps, arena, writeView->swizzle(),
+                                           std::move(appliedClip), dstProxyView);
 
     if (fCharacterization & kLine_Program) {
         this->makeLineProgramInfo(*caps, arena, pipeline, writeView,
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 4054121..b0762d7 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -271,7 +271,8 @@
                                                              std::move(fProcessors),
                                                              GrPipeline::InputFlags::kNone);
 
-    flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
+    flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline,
+                                                    &GrUserStencilSettings::kUnused);
 }
 
 void GrAtlasTextOp::createDrawForGeneratedGlyphs(
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp
index d49bc52..f56f2ed 100644
--- a/src/gpu/ops/GrDrawPathOp.cpp
+++ b/src/gpu/ops/GrDrawPathOp.cpp
@@ -83,8 +83,7 @@
 
     auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState,
                                                              this->detachProcessorSet(),
-                                                             pipelineFlags,
-                                                             &kCoverPass);
+                                                             pipelineFlags);
 
     sk_sp<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(), this->viewMatrix()));
 
@@ -94,6 +93,7 @@
                               proxy->backendFormat(),
                               flushState->writeView()->origin(),
                               pipeline,
+                              &kCoverPass,
                               pathProc.get(),
                               GrPrimitiveType::kPath,
                               0,
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
index 4a876ec..23bc438 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
@@ -115,12 +115,10 @@
                                                 GrAppliedClip&& appliedClip,
                                                 const GrXferProcessor::DstProxyView& dstProxyView,
                                                 GrProcessorSet&& processorSet,
-                                                GrPipeline::InputFlags pipelineFlags,
-                                                const GrUserStencilSettings* stencilSettings) {
+                                                GrPipeline::InputFlags pipelineFlags) {
     GrPipeline::InitArgs pipelineArgs;
 
     pipelineArgs.fInputFlags = pipelineFlags;
-    pipelineArgs.fUserStencil = stencilSettings;
     pipelineArgs.fCaps = caps;
     pipelineArgs.fDstProxyView = dstProxyView;
     pipelineArgs.fWriteSwizzle = writeViewSwizzle;
@@ -133,16 +131,14 @@
 const GrPipeline* GrSimpleMeshDrawOpHelper::CreatePipeline(
                                                 GrOpFlushState* flushState,
                                                 GrProcessorSet&& processorSet,
-                                                GrPipeline::InputFlags pipelineFlags,
-                                                const GrUserStencilSettings* stencilSettings) {
+                                                GrPipeline::InputFlags pipelineFlags) {
     return CreatePipeline(&flushState->caps(),
                           flushState->allocator(),
                           flushState->writeView()->swizzle(),
                           flushState->detachAppliedClip(),
                           flushState->dstProxyView(),
                           std::move(processorSet),
-                          pipelineFlags,
-                          stencilSettings);
+                          pipelineFlags);
 }
 
 const GrPipeline* GrSimpleMeshDrawOpHelper::createPipeline(GrOpFlushState* flushState) {
@@ -155,6 +151,21 @@
                           this->pipelineFlags());
 }
 
+const GrPipeline* GrSimpleMeshDrawOpHelper::createPipeline(
+        const GrCaps* caps,
+        SkArenaAlloc* arena,
+        GrSwizzle writeViewSwizzle,
+        GrAppliedClip&& appliedClip,
+        const GrXferProcessor::DstProxyView& dstProxyView) {
+    return GrSimpleMeshDrawOpHelper::CreatePipeline(caps,
+                                                    arena,
+                                                    writeViewSwizzle,
+                                                    std::move(appliedClip),
+                                                    dstProxyView,
+                                                    this->detachProcessorSet(),
+                                                    this->pipelineFlags());
+}
+
 GrProgramInfo* GrSimpleMeshDrawOpHelper::CreateProgramInfo(
             const GrCaps* caps,
             SkArenaAlloc* arena,
@@ -173,11 +184,10 @@
                                    std::move(appliedClip),
                                    dstProxyView,
                                    std::move(processorSet),
-                                   pipelineFlags,
-                                   stencilSettings);
+                                   pipelineFlags);
 
     return CreateProgramInfo(arena, pipeline, writeView, geometryProcessor, primitiveType,
-                             renderPassXferBarriers);
+                             renderPassXferBarriers, stencilSettings);
 }
 
 GrProgramInfo* GrSimpleMeshDrawOpHelper::CreateProgramInfo(SkArenaAlloc* arena,
@@ -185,7 +195,8 @@
                                                            const GrSurfaceProxyView* writeView,
                                                            GrGeometryProcessor* geometryProcessor,
                                                            GrPrimitiveType primitiveType,
-                                                           GrXferBarrierFlags renderPassXferBarriers) {
+                                                           GrXferBarrierFlags xferBarrierFlags,
+                                                           const GrUserStencilSettings* stencilSettings) {
     GrRenderTargetProxy* outputProxy = writeView->asRenderTargetProxy();
 
     auto tmp = arena->make<GrProgramInfo>(outputProxy->numSamples(),
@@ -193,10 +204,11 @@
                                           outputProxy->backendFormat(),
                                           writeView->origin(),
                                           pipeline,
+                                          stencilSettings,
                                           geometryProcessor,
                                           primitiveType,
                                           0,
-                                          renderPassXferBarriers);
+                                          xferBarrierFlags);
     return tmp;
 }
 
@@ -230,6 +242,12 @@
         if (flags & GrPipeline::InputFlags::kHWAntialias) {
             result->append("HW Antialiasing enabled.\n");
         }
+        if (flags & GrPipeline::InputFlags::kWireframe) {
+            result->append("Wireframe enabled.\n");
+        }
+        if (flags & GrPipeline::InputFlags::kConservativeRaster) {
+            result->append("Conservative raster enabled.\n");
+        }
         return;
     }
     result->append("No pipeline flags\n");
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index 3ef6d8e..679c6c6 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -130,22 +130,28 @@
                                 GrAppliedClip&&,
                                 const GrXferProcessor::DstProxyView&,
                                 GrProcessorSet&&,
-                                GrPipeline::InputFlags pipelineFlags,
-                                const GrUserStencilSettings* = &GrUserStencilSettings::kUnused);
+                                GrPipeline::InputFlags pipelineFlags);
     static const GrPipeline* CreatePipeline(
                                 GrOpFlushState*,
                                 GrProcessorSet&&,
-                                GrPipeline::InputFlags pipelineFlags,
-                                const GrUserStencilSettings* = &GrUserStencilSettings::kUnused);
+                                GrPipeline::InputFlags pipelineFlags);
 
     const GrPipeline* createPipeline(GrOpFlushState* flushState);
 
+    const GrPipeline* createPipeline(const GrCaps*,
+                                     SkArenaAlloc*,
+                                     GrSwizzle writeViewSwizzle,
+                                     GrAppliedClip&&,
+                                     const GrXferProcessor::DstProxyView&);
+
     static GrProgramInfo* CreateProgramInfo(SkArenaAlloc*,
                                             const GrPipeline*,
                                             const GrSurfaceProxyView* writeView,
                                             GrGeometryProcessor*,
                                             GrPrimitiveType,
-                                            GrXferBarrierFlags renderPassXferBarriers);
+                                            GrXferBarrierFlags renderPassXferBarriers,
+                                            const GrUserStencilSettings*
+                                                                = &GrUserStencilSettings::kUnused);
 
     // Create a programInfo with the following properties:
     //     its primitive processor uses no textures
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp
index 000b699..bc8353f 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp
@@ -7,31 +7,6 @@
 
 #include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
 
-const GrPipeline* GrSimpleMeshDrawOpHelperWithStencil::createPipelineWithStencil(
-                                            const GrCaps* caps,
-                                            SkArenaAlloc* arena,
-                                            GrSwizzle writeViewSwizzle,
-                                            GrAppliedClip&& appliedClip,
-                                            const GrXferProcessor::DstProxyView& dstProxyView) {
-    return GrSimpleMeshDrawOpHelper::CreatePipeline(caps,
-                                                    arena,
-                                                    writeViewSwizzle,
-                                                    std::move(appliedClip),
-                                                    dstProxyView,
-                                                    this->detachProcessorSet(),
-                                                    this->pipelineFlags(),
-                                                    this->stencilSettings());
-}
-
-const GrPipeline* GrSimpleMeshDrawOpHelperWithStencil::createPipelineWithStencil(
-        GrOpFlushState* flushState) {
-    return this->createPipelineWithStencil(&flushState->caps(),
-                                           flushState->allocator(),
-                                           flushState->writeView()->swizzle(),
-                                           flushState->detachAppliedClip(),
-                                           flushState->dstProxyView());
-}
-
 GrSimpleMeshDrawOpHelperWithStencil::GrSimpleMeshDrawOpHelperWithStencil(
                                                     const MakeArgs& args,
                                                     GrAAType aaType,
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h b/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h
index b1339ad..2036ae8 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h
@@ -21,14 +21,7 @@
     using InputFlags = GrSimpleMeshDrawOpHelper::InputFlags;
 
     using GrSimpleMeshDrawOpHelper::visitProxies;
-
-    const GrPipeline* createPipelineWithStencil(const GrCaps*,
-                                                SkArenaAlloc*,
-                                                GrSwizzle writeViewSwizzle,
-                                                GrAppliedClip&&,
-                                                const GrXferProcessor::DstProxyView&);
-
-    const GrPipeline* createPipelineWithStencil(GrOpFlushState* flushState);
+    using GrSimpleMeshDrawOpHelper::createPipeline;
 
     GrProgramInfo* createProgramInfoWithStencil(const GrCaps*,
                                                 SkArenaAlloc*,
@@ -39,7 +32,6 @@
                                                 GrPrimitiveType,
                                                 GrXferBarrierFlags renderPassXferBarriers);
 
-
     // using declarations can't be templated, so this is a pass through function instead.
     template <typename Op, typename... OpArgs>
     static std::unique_ptr<GrDrawOp> FactoryHelper(GrRecordingContext* context, GrPaint&& paint,
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index 8d44fb8..d444dc3 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -610,9 +610,10 @@
     }
 
     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
-        auto pipeline = fHelper.createPipelineWithStencil(flushState);
+        auto pipeline = fHelper.createPipeline(flushState);
 
-        flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
+        flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline,
+                                                        fHelper.stencilSettings());
     }
 
     const SkPMColor4f& color() const { return fShapes[0].fColor; }
diff --git a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
index 1631cfa..7716a53 100644
--- a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
+++ b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
@@ -180,8 +180,8 @@
 
     GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
                               state->proxy()->backendFormat(), state->writeView()->origin(),
-                              &pipeline, &shader, GrPrimitiveType::kTriangleStrip, 0,
-                              state->renderPassBarriers());
+                              &pipeline, &GrUserStencilSettings::kUnused, &shader,
+                              GrPrimitiveType::kTriangleStrip, 0, state->renderPassBarriers());
 
     state->bindPipelineAndScissorClip(programInfo, this->bounds());
     state->bindTextures(shader, *fAtlasProxy, pipeline);
diff --git a/src/gpu/tessellate/GrPathShader.h b/src/gpu/tessellate/GrPathShader.h
index 2043102..246a306 100644
--- a/src/gpu/tessellate/GrPathShader.h
+++ b/src/gpu/tessellate/GrPathShader.h
@@ -38,6 +38,7 @@
                                           GrProcessorSet&& processors, GrAppliedClip&& appliedClip,
                                           const GrXferProcessor::DstProxyView& dstProxyView,
                                           GrXferBarrierFlags renderPassXferBarriers,
+                                          const GrUserStencilSettings* stencil,
                                           const GrCaps& caps) {
         GrPipeline::InitArgs pipelineArgs;
         pipelineArgs.fInputFlags = pipelineFlags;
@@ -47,7 +48,7 @@
         auto* pipeline = arena->make<GrPipeline>(pipelineArgs, std::move(processors),
                                                  std::move(appliedClip));
         return MakeProgramInfo(shader, arena, writeView, pipeline, dstProxyView,
-                               renderPassXferBarriers, caps);
+                               renderPassXferBarriers, stencil, caps);
     }
 
     static GrProgramInfo* MakeProgramInfo(const GrPathShader* shader, SkArenaAlloc* arena,
@@ -55,11 +56,12 @@
                                           const GrPipeline* pipeline,
                                           const GrXferProcessor::DstProxyView& dstProxyView,
                                           GrXferBarrierFlags renderPassXferBarriers,
+                                          const GrUserStencilSettings* stencil,
                                           const GrCaps& caps) {
         GrRenderTargetProxy* proxy = writeView->asRenderTargetProxy();
         return arena->make<GrProgramInfo>(proxy->numSamples(), proxy->numStencilSamples(),
                                           proxy->backendFormat(), writeView->origin(), pipeline,
-                                          shader, shader->fPrimitiveType,
+                                          stencil, shader, shader->fPrimitiveType,
                                           shader->fTessellationPatchVertexCount,
                                           renderPassXferBarriers);
     }
diff --git a/src/gpu/tessellate/GrPathTessellateOp.cpp b/src/gpu/tessellate/GrPathTessellateOp.cpp
index 1281355..29c5ae5 100644
--- a/src/gpu/tessellate/GrPathTessellateOp.cpp
+++ b/src/gpu/tessellate/GrPathTessellateOp.cpp
@@ -169,14 +169,37 @@
     return true;
 }
 
+// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
+constexpr static GrUserStencilSettings kIncrDecrStencil(
+    GrUserStencilSettings::StaticInitSeparate<
+        0x0000,                                0x0000,
+        GrUserStencilTest::kAlwaysIfInClip,    GrUserStencilTest::kAlwaysIfInClip,
+        0xffff,                                0xffff,
+        GrUserStencilOp::kIncWrap,             GrUserStencilOp::kDecWrap,
+        GrUserStencilOp::kKeep,                GrUserStencilOp::kKeep,
+        0xffff,                                0xffff>());
+
+// Inverts the bottom stencil bit. Used for "even/odd" fill.
+constexpr static GrUserStencilSettings kInvertStencil(
+    GrUserStencilSettings::StaticInit<
+        0x0000,
+        GrUserStencilTest::kAlwaysIfInClip,
+        0xffff,
+        GrUserStencilOp::kInvert,
+        GrUserStencilOp::kKeep,
+        0x0001>());
+
+constexpr static const GrUserStencilSettings* stencil_pass_settings(SkPathFillType fillType) {
+    return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil;
+}
+
 void GrPathTessellateOp::prePrepareStencilTrianglesProgram(const PrePrepareArgs& args) {
     SkASSERT(!fStencilTrianglesProgram);
     auto* shader = args.fArena->make<GrStencilTriangleShader>(fViewMatrix);
     this->prePrepareSharedStencilPipeline(args);
-    fStencilTrianglesProgram = GrPathShader::MakeProgramInfo(shader, args.fArena, args.fWriteView,
-                                                             fSharedStencilPipeline,
-                                                             *args.fDstProxfView,
-                                                             args.fXferBarrierFlags, *args.fCaps);
+    fStencilTrianglesProgram = GrPathShader::MakeProgramInfo(
+            shader, args.fArena, args.fWriteView, fSharedStencilPipeline, *args.fDstProxfView,
+            args.fXferBarrierFlags, stencil_pass_settings(fPath.getFillType()), *args.fCaps);
 }
 
 template<typename ShaderType>
@@ -184,10 +207,9 @@
     SkASSERT(!fStencilCubicsProgram);
     auto* shader = args.fArena->make<ShaderType>(fViewMatrix);
     this->prePrepareSharedStencilPipeline(args);
-    fStencilCubicsProgram = GrPathShader::MakeProgramInfo(shader, args.fArena, args.fWriteView,
-                                                          fSharedStencilPipeline,
-                                                          *args.fDstProxfView,
-                                                          args.fXferBarrierFlags, *args.fCaps);
+    fStencilCubicsProgram = GrPathShader::MakeProgramInfo(
+            shader, args.fArena, args.fWriteView, fSharedStencilPipeline, *args.fDstProxfView,
+            args.fXferBarrierFlags, stencil_pass_settings(fPath.getFillType()), *args.fCaps);
 }
 
 void GrPathTessellateOp::prePrepareSharedStencilPipeline(const PrePrepareArgs& args) {
@@ -195,26 +217,6 @@
         return;
     }
 
-    // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
-    constexpr static GrUserStencilSettings kIncrDecrStencil(
-        GrUserStencilSettings::StaticInitSeparate<
-            0x0000,                                0x0000,
-            GrUserStencilTest::kAlwaysIfInClip,    GrUserStencilTest::kAlwaysIfInClip,
-            0xffff,                                0xffff,
-            GrUserStencilOp::kIncWrap,             GrUserStencilOp::kDecWrap,
-            GrUserStencilOp::kKeep,                GrUserStencilOp::kKeep,
-            0xffff,                                0xffff>());
-
-    // Inverts the bottom stencil bit. Used for "even/odd" fill.
-    constexpr static GrUserStencilSettings kInvertStencil(
-        GrUserStencilSettings::StaticInit<
-            0x0000,
-            GrUserStencilTest::kAlwaysIfInClip,
-            0xffff,
-            GrUserStencilOp::kInvert,
-            GrUserStencilOp::kKeep,
-            0x0001>());
-
     GrPipeline::InitArgs initArgs;
     if (GrAAType::kNone != fAAType) {
         initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
@@ -224,8 +226,6 @@
     }
     SkASSERT(SkPathFillType::kWinding == fPath.getFillType() ||
              SkPathFillType::kEvenOdd == fPath.getFillType());
-    initArgs.fUserStencil = (SkPathFillType::kWinding == fPath.getFillType()) ?
-            &kIncrDecrStencil : &kInvertStencil;
     initArgs.fCaps = args.fCaps;
     const auto& hardClip = (args.fClip) ? args.fClip->hardClip() : GrAppliedHardClip::Disabled();
     fSharedStencilPipeline = args.fArena->make<GrPipeline>(
@@ -742,26 +742,28 @@
                 GrUserStencilOp::kZero,
                 0xffff>());
 
+        const GrUserStencilSettings* stencil;
         if (fStencilTrianglesProgram) {
             // The path was already stencilled. Here we just need to do a cover pass.
-            pipeline.setUserStencil(&kTestAndResetStencil);
+            stencil = &kTestAndResetStencil;
         } else if (fCubicVertexCount == 0) {
             // There are no stencilled curves. We can ignore stencil and fill the path directly.
-            pipeline.setUserStencil(&GrUserStencilSettings::kUnused);
+            stencil = &GrUserStencilSettings::kUnused;
         } else if (SkPathFillType::kWinding == fPath.getFillType()) {
             // Fill in the path pixels not touched by curves, incr/decr stencil otherwise.
             SkASSERT(!pipeline.hasStencilClip());
-            pipeline.setUserStencil(&kFillOrIncrDecrStencil);
+            stencil = &kFillOrIncrDecrStencil;
         } else {
             // Fill in the path pixels not touched by curves, invert stencil otherwise.
             SkASSERT(!pipeline.hasStencilClip());
-            pipeline.setUserStencil(&kFillOrInvertStencil);
+            stencil = &kFillOrInvertStencil;
         }
 
         GrFillTriangleShader fillTrianglesShader(fViewMatrix, fColor);
         auto* fillTrianglesProgram = GrPathShader::MakeProgramInfo(
                 &fillTrianglesShader, flushState->allocator(), flushState->writeView(), &pipeline,
-                flushState->dstProxyView(), flushState->renderPassBarriers(), flushState->caps());
+                flushState->dstProxyView(), flushState->renderPassBarriers(), stencil,
+                flushState->caps());
         flushState->bindPipelineAndScissorClip(*fillTrianglesProgram, this->bounds());
         flushState->bindTextures(fillTrianglesShader, nullptr, pipeline);
         flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer);
@@ -773,12 +775,11 @@
             // At this point, every pixel is filled in except the ones touched by curves. Issue a
             // final cover pass over the curves by drawing their convex hulls. This will fill in any
             // remaining samples and reset the stencil buffer.
-            pipeline.setUserStencil(&kTestAndResetStencil);
             GrFillCubicHullShader fillCubicHullsShader(fViewMatrix, fColor);
             auto* fillCubicHullsProgram = GrPathShader::MakeProgramInfo(
                     &fillCubicHullsShader, flushState->allocator(), flushState->writeView(),
                     &pipeline, flushState->dstProxyView(), flushState->renderPassBarriers(),
-                    flushState->caps());
+                    &kTestAndResetStencil, flushState->caps());
             flushState->bindPipelineAndScissorClip(*fillCubicHullsProgram, this->bounds());
             flushState->bindTextures(fillCubicHullsShader, nullptr, pipeline);
 
@@ -793,12 +794,11 @@
     }
 
     // There are no triangles to fill. Just draw a bounding box.
-    pipeline.setUserStencil(&kTestAndResetStencil);
     GrFillBoundingBoxShader fillBoundingBoxShader(fViewMatrix, fColor, fPath.getBounds());
     auto* fillBoundingBoxProgram = GrPathShader::MakeProgramInfo(
             &fillBoundingBoxShader, flushState->allocator(), flushState->writeView(),
             &pipeline, flushState->dstProxyView(), flushState->renderPassBarriers(),
-            flushState->caps());
+            &kTestAndResetStencil, flushState->caps());
     flushState->bindPipelineAndScissorClip(*fillBoundingBoxProgram, this->bounds());
     flushState->bindTextures(fillBoundingBoxShader, nullptr, pipeline);
     flushState->bindBuffers(nullptr, nullptr, nullptr);
diff --git a/src/gpu/tessellate/GrStrokeTessellateOp.cpp b/src/gpu/tessellate/GrStrokeTessellateOp.cpp
index 8b45257..ecacda0 100644
--- a/src/gpu/tessellate/GrStrokeTessellateOp.cpp
+++ b/src/gpu/tessellate/GrStrokeTessellateOp.cpp
@@ -101,7 +101,8 @@
     }
     fColorProgram = GrPathShader::MakeProgramInfo(strokeShader, arena, writeView, pipelineFlags,
                                                   std::move(fProcessors), std::move(clip),
-                                                  dstProxyView, renderPassXferBarriers, caps);
+                                                  dstProxyView, renderPassXferBarriers,
+                                                  &GrUserStencilSettings::kUnused, caps);
 }
 
 void GrStrokeTessellateOp::onPrepare(GrOpFlushState* flushState) {
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
index e2c3c04..3a35afb5 100644
--- a/src/gpu/vk/GrVkPipelineStateCache.cpp
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -75,7 +75,7 @@
         const GrProgramInfo& programInfo,
         VkRenderPass compatibleRenderPass) {
 #ifdef SK_DEBUG
-    if (programInfo.pipeline().isStencilEnabled()) {
+    if (programInfo.isStencilEnabled()) {
         SkASSERT(renderTarget->getStencilAttachment());
         SkASSERT(renderTarget->numStencilBits() == 8);
         SkASSERT(renderTarget->getStencilAttachment()->numSamples() ==
diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp
index ee3e5c3b..03bd645 100644
--- a/tests/GrMeshTest.cpp
+++ b/tests/GrMeshTest.cpp
@@ -577,7 +577,8 @@
 
     GrProgramInfo programInfo(fState->proxy()->numSamples(), fState->proxy()->numStencilSamples(),
                               fState->proxy()->backendFormat(), fState->writeView()->origin(),
-                              pipeline, mtp, primitiveType, 0, fState->renderPassBarriers());
+                              pipeline, &GrUserStencilSettings::kUnused, mtp, primitiveType, 0,
+                              fState->renderPassBarriers());
 
     fState->opsRenderPass()->bindPipeline(programInfo, SkRect::MakeIWH(kImageWidth, kImageHeight));
     return fState->opsRenderPass();
diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp
index 11da0e2..46e6149 100644
--- a/tests/GrPipelineDynamicStateTest.cpp
+++ b/tests/GrPipelineDynamicStateTest.cpp
@@ -166,6 +166,7 @@
                                   flushState->proxy()->backendFormat(),
                                   flushState->writeView()->origin(),
                                   &pipeline,
+                                  &GrUserStencilSettings::kUnused,
                                   geomProc,
                                   GrPrimitiveType::kTriangleStrip, 0,
                                   flushState->renderPassBarriers());