converted AARectEffect to new FP system

Bug: skia:
Change-Id: I0e4141c7f547bab92c65a6abff120ed04d5c2c66
Reviewed-on: https://skia-review.googlesource.com/c/153550
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/gm/bigrrectaaeffect.cpp b/gm/bigrrectaaeffect.cpp
index f3f10ae..5802eaf 100644
--- a/gm/bigrrectaaeffect.cpp
+++ b/gm/bigrrectaaeffect.cpp
@@ -7,7 +7,6 @@
 
 #include "gm.h"
 #include "sk_tool_utils.h"
-#include "GrCaps.h"
 #include "GrContext.h"
 #include "GrRenderTargetContextPriv.h"
 #include "SkRRect.h"
@@ -82,8 +81,7 @@
 
                 SkRRect rrect = fRRect;
                 rrect.offset(SkIntToScalar(x + kGap), SkIntToScalar(y + kGap));
-                const auto& caps = *renderTargetContext->caps()->shaderCaps();
-                auto fp = GrRRectEffect::Make(edgeType, rrect, caps);
+                auto fp = GrRRectEffect::Make(edgeType, rrect, context);
                 SkASSERT(fp);
                 if (fp) {
                     GrPaint grPaint;
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 462405e..b3c2d19 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -205,7 +205,9 @@
                 path->transform(m, &p);
 
                 GrClipEdgeType edgeType = (GrClipEdgeType) et;
-                std::unique_ptr<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, p));
+                std::unique_ptr<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(
+                                                                           edgeType, p,
+                                                                           canvas->getGrContext()));
                 if (!fp) {
                     continue;
                 }
@@ -245,7 +247,9 @@
                 SkRect rect = *iter.get();
                 rect.offset(x, y);
                 GrClipEdgeType edgeType = (GrClipEdgeType) et;
-                std::unique_ptr<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, rect));
+                std::unique_ptr<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(
+                                                                           edgeType, rect,
+                                                                           canvas->getGrContext()));
                 if (!fp) {
                     continue;
                 }
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index 2fbd3b9..4e5fce1 100644
--- a/gm/rrects.cpp
+++ b/gm/rrects.cpp
@@ -105,8 +105,7 @@
                         SkRRect rrect = fRRects[curRRect];
                         rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
                         GrClipEdgeType edgeType = (GrClipEdgeType) et;
-                        const auto& caps = *renderTargetContext->caps()->shaderCaps();
-                        auto fp = GrRRectEffect::Make(edgeType, rrect, caps);
+                        auto fp = GrRRectEffect::Make(edgeType, rrect, context);
                         if (fp) {
                             GrPaint grPaint;
                             grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
diff --git a/gm/windowrectangles.cpp b/gm/windowrectangles.cpp
index 14d10e2..57744d9 100644
--- a/gm/windowrectangles.cpp
+++ b/gm/windowrectangles.cpp
@@ -179,7 +179,7 @@
         return;
     }
 
-    const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), rtc->caps(), kNumWindows);
+    const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), ctx, kNumWindows);
 
     GrPaint paint;
     if (GrFSAAType::kNone == rtc->fsaaType()) {
@@ -231,7 +231,7 @@
     // Draw a checker pattern into the stencil buffer so we can visualize the regions left untouched
     // by the clip mask generation.
     this->stencilCheckerboard(rtc, false);
-    reducedClip.drawStencilClipMask(ctx, rtc);
+    reducedClip.drawStencilClipMask(rtc);
 
     // Now visualize the stencil mask by covering the entire render target. The regions inside
     // window rectangles or outside the scissor should still have the initial checkerboard intact.
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 4f54eb1..defaacf 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -295,8 +295,6 @@
   "$_src/gpu/ops/GrTextureOp.cpp",
   "$_src/gpu/ops/GrTextureOp.h",
 
-  "$_src/gpu/effects/GrAARectEffect.cpp",
-  "$_src/gpu/effects/GrAARectEffect.h",
   "$_src/gpu/effects/GrAlphaThresholdFragmentProcessor.cpp",
   "$_src/gpu/effects/GrAlphaThresholdFragmentProcessor.h",
   "$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp",
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 7497a64..3543896 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -30,7 +30,6 @@
 ]
 
 skia_gpu_processor_sources = [
-  "$_src/gpu/effects/GrAARectEffect.fp",
   "$_src/gpu/effects/GrAlphaThresholdFragmentProcessor.fp",
   "$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp",
   "$_src/gpu/effects/GrCircleBlurFragmentProcessor.fp",
diff --git a/src/effects/SkOverdrawColorFilter.cpp b/src/effects/SkOverdrawColorFilter.cpp
index 12c9921..35ef587 100644
--- a/src/effects/SkOverdrawColorFilter.cpp
+++ b/src/effects/SkOverdrawColorFilter.cpp
@@ -91,8 +91,7 @@
 std::unique_ptr<GrFragmentProcessor> SkOverdrawColorFilter::asFragmentProcessor(
         GrContext* context, const GrColorSpaceInfo&) const {
     static int overdrawIndex = GrSkSLFP::NewIndex();
-    return GrSkSLFP::Make(context, overdrawIndex, "Overdraw", SKSL_OVERDRAW_SRC, fColors,
-                          sizeof(fColors));
+    return GrSkSLFP::Make(context, overdrawIndex, "Overdraw", SKSL_OVERDRAW_SRC, fColors);
 }
 
 #endif
diff --git a/src/effects/imagefilters/SkArithmeticImageFilter.cpp b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
index bd72e3a..c1663c0 100644
--- a/src/effects/imagefilters/SkArithmeticImageFilter.cpp
+++ b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
@@ -344,8 +344,7 @@
                                                                      arithmeticIndex,
                                                                      "Arithmetic",
                                                                      SKSL_ARITHMETIC_SRC,
-                                                                     &inputs,
-                                                                     sizeof(inputs));
+                                                                     inputs);
         if (xferFP) {
             ((GrSkSLFP&) *xferFP).addChild(std::move(bgFP));
             paint.addColorFragmentProcessor(std::move(xferFP));
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 92af020..5c429e0 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -211,8 +211,8 @@
     }
     auto* ccpr = context->contextPriv().drawingManager()->getCoverageCountingPathRenderer();
 
-    GrReducedClip reducedClip(*fStack, devBounds, context->contextPriv().caps(),
-                              maxWindowRectangles, maxAnalyticFPs, ccpr ? maxAnalyticFPs : 0);
+    GrReducedClip reducedClip(*fStack, devBounds, context, maxWindowRectangles, maxAnalyticFPs,
+                              ccpr ? maxAnalyticFPs : 0);
     if (InitialState::kAllOut == reducedClip.initialState() &&
         reducedClip.maskElements().isEmpty()) {
         return false;
@@ -291,7 +291,7 @@
     // after clipping is overhauled.
     if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor(),
                                                    reducedClip.numAnalyticFPs())) {
-        reducedClip.drawStencilClipMask(context, renderTargetContext);
+        reducedClip.drawStencilClipMask(renderTargetContext);
         renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(),
                                                 reducedClip.numAnalyticFPs());
     }
diff --git a/src/gpu/GrMemoryPool.cpp b/src/gpu/GrMemoryPool.cpp
index 89e8f01..7d085ea 100644
--- a/src/gpu/GrMemoryPool.cpp
+++ b/src/gpu/GrMemoryPool.cpp
@@ -11,6 +11,7 @@
 #include "SkAtomics.h"
 #endif
 #include "ops/GrOp.h"
+#include "effects/GrSkSLFP.h"
 
 #ifdef SK_DEBUG
     #define VALIDATE this->validate()
@@ -18,6 +19,13 @@
     #define VALIDATE
 #endif
 
+enum {
+    // We assume this alignment is good enough for everybody.
+    kAlignment    = alignof(GrSkSLFP),
+    kHeaderSize   = GR_CT_ALIGN_UP(GrMemoryPool::kBlockHeaderSize, kAlignment),
+    kPerAllocPad  = GR_CT_ALIGN_UP(GrMemoryPool::kAllocHeaderSize, kAlignment),
+};
+
 void GrOpMemoryPool::release(std::unique_ptr<GrOp> op) {
     GrOp* tmp = op.release();
     SkASSERT(tmp);
diff --git a/src/gpu/GrMemoryPool.h b/src/gpu/GrMemoryPool.h
index 15399b6..316deae 100644
--- a/src/gpu/GrMemoryPool.h
+++ b/src/gpu/GrMemoryPool.h
@@ -115,13 +115,10 @@
     SkTHashSet<int32_t>               fAllocatedIDs;
 #endif
 
-protected:
-    enum {
-        // We assume this alignment is good enough for everybody.
-        kAlignment    = 8,
-        kHeaderSize   = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment),
-        kPerAllocPad  = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment),
-    };
+public:
+    constexpr static size_t kBlockHeaderSize = sizeof(BlockHeader);
+
+    constexpr static size_t kAllocHeaderSize = sizeof(AllocHeader);
 };
 
 class GrOp;
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index aafe1d8..078cfbdf 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -57,7 +57,7 @@
  * we verify the count is as expected.  If a new factory is added, then these numbers must be
  * manually adjusted.
  */
-static const int kFPFactoryCount = 36;
+static const int kFPFactoryCount = 35;
 static const int kGPFactoryCount = 14;
 static const int kXPFactoryCount = 4;
 
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 4cf3477..111ef7f 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -22,7 +22,6 @@
 #include "GrUserStencilSettings.h"
 #include "SkClipOpPriv.h"
 #include "ccpr/GrCoverageCountingPathRenderer.h"
-#include "effects/GrAARectEffect.h"
 #include "effects/GrConvexPolyEffect.h"
 #include "effects/GrRRectEffect.h"
 
@@ -34,9 +33,9 @@
  * take a rect in case the caller knows a bound on what is to be drawn through this clip.
  */
 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds,
-                             const GrCaps* caps, int maxWindowRectangles, int maxAnalyticFPs,
-                             int maxCCPRClipPaths)
-        : fCaps(caps)
+                             GrContext* context, int maxWindowRectangles,
+                             int maxAnalyticFPs, int maxCCPRClipPaths)
+        : fContext(context)
         , fMaxWindowRectangles(maxWindowRectangles)
         , fMaxAnalyticFPs(maxAnalyticFPs)
         , fMaxCCPRClipPaths(maxCCPRClipPaths) {
@@ -612,13 +611,14 @@
     }
 }
 
-GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const SkRect& deviceSpaceRect,
-                                                       Invert invert, GrAA aa) {
+GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const SkRect& deviceSpaceRect, Invert invert,
+                                                       GrAA aa) {
     if (this->numAnalyticFPs() >= fMaxAnalyticFPs) {
         return ClipResult::kNotClipped;
     }
 
-    fAnalyticFPs.push_back(GrAARectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRect));
+    fAnalyticFPs.push_back(GrConvexPolyEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRect,
+                                                    fContext));
     SkASSERT(fAnalyticFPs.back());
 
     return ClipResult::kClipped;
@@ -630,8 +630,7 @@
         return ClipResult::kNotClipped;
     }
 
-    if (auto fp = GrRRectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRRect,
-                                      *fCaps->shaderCaps())) {
+    if (auto fp = GrRRectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRRect, fContext)) {
         fAnalyticFPs.push_back(std::move(fp));
         return ClipResult::kClipped;
     }
@@ -648,7 +647,8 @@
         return ClipResult::kNotClipped;
     }
 
-    if (auto fp = GrConvexPolyEffect::Make(GetClipEdgeType(invert, aa), deviceSpacePath)) {
+    if (auto fp = GrConvexPolyEffect::Make(GetClipEdgeType(invert, aa), deviceSpacePath,
+                                           fContext)) {
         fAnalyticFPs.push_back(std::move(fp));
         return ClipResult::kClipped;
     }
@@ -805,8 +805,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Create a 1-bit clip mask in the stencil buffer.
 
-bool GrReducedClip::drawStencilClipMask(GrContext* context,
-                                        GrRenderTargetContext* renderTargetContext) const {
+bool GrReducedClip::drawStencilClipMask(GrRenderTargetContext* renderTargetContext) const {
     // We set the current clip to the bounds so that our recursive draws are scissored to them.
     GrStencilClip stencilClip(fScissor, this->maskGenID());
 
@@ -848,14 +847,14 @@
 
             GrShape shape(clipPath, GrStyle::SimpleFill());
             GrPathRenderer::CanDrawPathArgs canDrawArgs;
-            canDrawArgs.fCaps = context->contextPriv().caps();
+            canDrawArgs.fCaps = fContext->contextPriv().caps();
             canDrawArgs.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect();
             canDrawArgs.fViewMatrix = &SkMatrix::I();
             canDrawArgs.fShape = &shape;
             canDrawArgs.fAAType = aaType;
             canDrawArgs.fHasUserStencilSettings = false;
 
-            GrDrawingManager* dm = context->contextPriv().drawingManager();
+            GrDrawingManager* dm = fContext->contextPriv().drawingManager();
             pr = dm->getPathRenderer(canDrawArgs, false, GrPathRendererChain::DrawType::kStencil,
                                      &stencilSupport);
             if (!pr) {
@@ -895,7 +894,7 @@
                         GrPaint paint;
                         paint.setXPFactory(GrDisableColorXPFactory::Get());
 
-                        GrPathRenderer::DrawPathArgs args{context,
+                        GrPathRenderer::DrawPathArgs args{fContext,
                                                           std::move(paint),
                                                           &kDrawToStencil,
                                                           renderTargetContext,
@@ -908,7 +907,7 @@
                         pr->drawPath(args);
                     } else {
                         GrPathRenderer::StencilPathArgs args;
-                        args.fContext = context;
+                        args.fContext = fContext;
                         args.fRenderTargetContext = renderTargetContext;
                         args.fClip = &stencilClip.fixedClip();
                         args.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect();
@@ -933,7 +932,7 @@
                     GrShape shape(clipPath, GrStyle::SimpleFill());
                     GrPaint paint;
                     paint.setXPFactory(GrDisableColorXPFactory::Get());
-                    GrPathRenderer::DrawPathArgs args{context,
+                    GrPathRenderer::DrawPathArgs args{fContext,
                                                       std::move(paint),
                                                       *pass,
                                                       renderTargetContext,
@@ -967,7 +966,7 @@
             SkASSERT(ccpr);
             SkASSERT(fHasScissor);
             auto fp = ccpr->makeClipProcessor(opListID, ccprClipPath, fScissor, rtWidth, rtHeight,
-                                              *fCaps);
+                                              *fContext->contextPriv().caps());
             fAnalyticFPs.push_back(std::move(fp));
         }
         fCCPRClipPaths.reset();
diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h
index fcdc66c..6a8bc9e 100644
--- a/src/gpu/GrReducedClip.h
+++ b/src/gpu/GrReducedClip.h
@@ -26,8 +26,9 @@
     using Element = SkClipStack::Element;
     using ElementList = SkTLList<SkClipStack::Element, 16>;
 
-    GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrCaps* caps,
-                  int maxWindowRectangles = 0, int maxAnalyticFPs = 0, int maxCCPRClipPaths = 0);
+    GrReducedClip(const SkClipStack&, const SkRect& queryBounds, GrContext* context,
+                  int maxWindowRectangles = 0, int maxAnalyticFPs = 0,
+                  int maxCCPRClipPaths = 0);
 
     enum class InitialState : bool {
         kAllIn,
@@ -83,7 +84,7 @@
     bool maskRequiresAA() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskRequiresAA; }
 
     bool drawAlphaClipMask(GrRenderTargetContext*) const;
-    bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const;
+    bool drawStencilClipMask(GrRenderTargetContext*) const;
 
     int numAnalyticFPs() const { return fAnalyticFPs.count() + fCCPRClipPaths.count(); }
 
@@ -131,7 +132,7 @@
 
     void makeEmpty();
 
-    const GrCaps* fCaps;
+    GrContext* fContext;
     const int fMaxWindowRectangles;
     const int fMaxAnalyticFPs;
     const int fMaxCCPRClipPaths;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 584ed33..3333328 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1224,14 +1224,13 @@
         inverseVM.reset();
     }
 
-    const auto& caps = *this->caps()->shaderCaps();
     // TODO these need to be a geometry processors
-    auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
+    auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, fContext);
     if (!innerEffect) {
         return false;
     }
 
-    auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
+    auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, fContext);
     if (!outerEffect) {
         return false;
     }
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index f78ef18..9f348c2 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -490,7 +490,7 @@
         if (ditherRange >= 0) {
             static int ditherIndex = GrSkSLFP::NewIndex();
             auto ditherFP = GrSkSLFP::Make(context, ditherIndex, "Dither", SKSL_DITHER_SRC,
-                                           &ditherRange, sizeof(ditherRange));
+                                           ditherRange);
             if (ditherFP) {
                 grPaint->addColorFragmentProcessor(std::move(ditherFP));
             }
diff --git a/src/gpu/effects/GrAARectEffect.cpp b/src/gpu/effects/GrAARectEffect.cpp
deleted file mode 100644
index 9ee0ad5..0000000
--- a/src/gpu/effects/GrAARectEffect.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrAARectEffect.fp; do not modify.
- **************************************************************************************************/
-#include "GrAARectEffect.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramBuilder.h"
-#include "GrTexture.h"
-#include "SkSLCPP.h"
-#include "SkSLUtil.h"
-class GrGLSLAARectEffect : public GrGLSLFragmentProcessor {
-public:
-    GrGLSLAARectEffect() {}
-    void emitCode(EmitArgs& args) override {
-        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
-        const GrAARectEffect& _outer = args.fFp.cast<GrAARectEffect>();
-        (void)_outer;
-        auto edgeType = _outer.edgeType();
-        (void)edgeType;
-        auto rect = _outer.rect();
-        (void)rect;
-        prevRect = float4(-1.0);
-        fRectUniformVar = args.fUniformHandler->addUniform(
-                kFragment_GrShaderFlag, kFloat4_GrSLType, kDefault_GrSLPrecision, "rectUniform");
-        fragBuilder->codeAppendf(
-                "float4 prevRect = float4(%f, %f, %f, %f);\nhalf alpha;\n@switch (%d) {\n    case "
-                "0:\n    case 2:\n        alpha = half(all(greaterThan(float4(sk_FragCoord.xy, "
-                "%s.zw), float4(%s.xy, sk_FragCoord.xy))) ? 1 : 0);\n        break;\n    "
-                "default:\n        half xSub, ySub;\n        xSub = half(min(sk_FragCoord.x - "
-                "%s.x, 0.0));\n        xSub += half(min(%s.z - sk_FragCoord.x, 0.0));\n        "
-                "ySub = half(min(sk_FragCoord.y - %s.y, 0.0));\n        ySub += half(min(%s.w - "
-                "sk_FragCoord.y, 0.0));\n        alpha = half((1",
-                prevRect.left(),
-                prevRect.top(),
-                prevRect.right(),
-                prevRect.bottom(),
-                (int)_outer.edgeType(),
-                args.fUniformHandler->getUniformCStr(fRectUniformVar),
-                args.fUniformHandler->getUniformCStr(fRectUniformVar),
-                args.fUniformHandler->getUniformCStr(fRectUniformVar),
-                args.fUniformHandler->getUniformCStr(fRectUniformVar),
-                args.fUniformHandler->getUniformCStr(fRectUniformVar),
-                args.fUniformHandler->getUniformCStr(fRectUniformVar));
-        fragBuilder->codeAppendf(
-                ".0 + max(float(xSub), -1.0)) * (1.0 + max(float(ySub), -1.0)));\n}\n@if (%d == 2 "
-                "|| %d == 3) {\n    alpha = half(1.0 - float(alpha));\n}\n%s = %s * alpha;\n",
-                (int)_outer.edgeType(),
-                (int)_outer.edgeType(),
-                args.fOutputColor,
-                args.fInputColor);
-    }
-
-private:
-    void onSetData(const GrGLSLProgramDataManager& pdman,
-                   const GrFragmentProcessor& _proc) override {
-        const GrAARectEffect& _outer = _proc.cast<GrAARectEffect>();
-        auto edgeType = _outer.edgeType();
-        (void)edgeType;
-        auto rect = _outer.rect();
-        (void)rect;
-        UniformHandle& rectUniform = fRectUniformVar;
-        (void)rectUniform;
-
-        const SkRect& newRect = GrProcessorEdgeTypeIsAA(edgeType) ? rect.makeInset(.5f, .5f) : rect;
-        if (newRect != prevRect) {
-            pdman.set4f(rectUniform, newRect.fLeft, newRect.fTop, newRect.fRight, newRect.fBottom);
-            prevRect = newRect;
-        }
-    }
-    SkRect prevRect = float4(0);
-    UniformHandle fRectUniformVar;
-};
-GrGLSLFragmentProcessor* GrAARectEffect::onCreateGLSLInstance() const {
-    return new GrGLSLAARectEffect();
-}
-void GrAARectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
-                                           GrProcessorKeyBuilder* b) const {
-    b->add32((int32_t)fEdgeType);
-}
-bool GrAARectEffect::onIsEqual(const GrFragmentProcessor& other) const {
-    const GrAARectEffect& that = other.cast<GrAARectEffect>();
-    (void)that;
-    if (fEdgeType != that.fEdgeType) return false;
-    if (fRect != that.fRect) return false;
-    return true;
-}
-GrAARectEffect::GrAARectEffect(const GrAARectEffect& src)
-        : INHERITED(kGrAARectEffect_ClassID, src.optimizationFlags())
-        , fEdgeType(src.fEdgeType)
-        , fRect(src.fRect) {}
-std::unique_ptr<GrFragmentProcessor> GrAARectEffect::clone() const {
-    return std::unique_ptr<GrFragmentProcessor>(new GrAARectEffect(*this));
-}
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAARectEffect);
-#if GR_TEST_UTILS
-std::unique_ptr<GrFragmentProcessor> GrAARectEffect::TestCreate(GrProcessorTestData* d) {
-    SkRect rect = SkRect::MakeLTRB(d->fRandom->nextSScalar1(),
-                                   d->fRandom->nextSScalar1(),
-                                   d->fRandom->nextSScalar1(),
-                                   d->fRandom->nextSScalar1());
-    std::unique_ptr<GrFragmentProcessor> fp;
-    do {
-        GrClipEdgeType edgeType =
-                static_cast<GrClipEdgeType>(d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
-
-        fp = GrAARectEffect::Make(edgeType, rect);
-    } while (nullptr == fp);
-    return fp;
-}
-#endif
diff --git a/src/gpu/effects/GrAARectEffect.fp b/src/gpu/effects/GrAARectEffect.fp
deleted file mode 100644
index 95064dd..0000000
--- a/src/gpu/effects/GrAARectEffect.fp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-layout(key) in GrClipEdgeType edgeType;
-layout(ctype=SkRect) in float4 rect;
-layout(ctype=SkRect) float4 prevRect = float4(-1);
-uniform float4 rectUniform;
-
-@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag }
-
-void main() {
-    half alpha;
-    @switch (edgeType) {
-        case GrClipEdgeType::kFillBW: // fall through
-        case GrClipEdgeType::kInverseFillBW:
-            // non-AA
-            alpha = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
-                                    float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
-            break;
-        default:
-            // The amount of coverage removed in x and y by the edges is computed as a pair of
-            // negative numbers, xSub and ySub.
-            half xSub, ySub;
-            xSub = min(sk_FragCoord.x - rectUniform.x, 0.0);
-            xSub += min(rectUniform.z - sk_FragCoord.x, 0.0);
-            ySub = min(sk_FragCoord.y - rectUniform.y, 0.0);
-            ySub += min(rectUniform.w - sk_FragCoord.y, 0.0);
-            // Now compute coverage in x and y and multiply them to get the fraction of the pixel
-            // covered.
-            alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));
-    }
-
-    @if (edgeType == GrClipEdgeType::kInverseFillBW || edgeType == GrClipEdgeType::kInverseFillAA) {
-        alpha = 1.0 - alpha;
-    }
-    sk_OutColor = sk_InColor * alpha;
-}
-
-@setData(pdman) {
-    const SkRect& newRect = GrProcessorEdgeTypeIsAA(edgeType) ?
-                            rect.makeInset(.5f, .5f) : rect;
-    if (newRect != prevRect) {
-        pdman.set4f(rectUniform, newRect.fLeft, newRect.fTop, newRect.fRight, newRect.fBottom);
-        prevRect = newRect;
-    }
-}
-
-@test(d) {
-    SkRect rect = SkRect::MakeLTRB(d->fRandom->nextSScalar1(),
-                                   d->fRandom->nextSScalar1(),
-                                   d->fRandom->nextSScalar1(),
-                                   d->fRandom->nextSScalar1());
-    std::unique_ptr<GrFragmentProcessor> fp;
-    do {
-        GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(
-                d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
-
-        fp = GrAARectEffect::Make(edgeType, rect);
-    } while (nullptr == fp);
-    return fp;
-}
diff --git a/src/gpu/effects/GrAARectEffect.h b/src/gpu/effects/GrAARectEffect.h
deleted file mode 100644
index 94974e2..0000000
--- a/src/gpu/effects/GrAARectEffect.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrAARectEffect.fp; do not modify.
- **************************************************************************************************/
-#ifndef GrAARectEffect_DEFINED
-#define GrAARectEffect_DEFINED
-#include "SkTypes.h"
-#include "GrFragmentProcessor.h"
-#include "GrCoordTransform.h"
-class GrAARectEffect : public GrFragmentProcessor {
-public:
-    const GrClipEdgeType& edgeType() const { return fEdgeType; }
-    const SkRect& rect() const { return fRect; }
-    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkRect rect) {
-        return std::unique_ptr<GrFragmentProcessor>(new GrAARectEffect(edgeType, rect));
-    }
-    GrAARectEffect(const GrAARectEffect& src);
-    std::unique_ptr<GrFragmentProcessor> clone() const override;
-    const char* name() const override { return "AARectEffect"; }
-
-private:
-    GrAARectEffect(GrClipEdgeType edgeType, SkRect rect)
-            : INHERITED(kGrAARectEffect_ClassID,
-                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
-            , fEdgeType(edgeType)
-            , fRect(rect) {}
-    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-    bool onIsEqual(const GrFragmentProcessor&) const override;
-    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
-    GrClipEdgeType fEdgeType;
-    SkRect fRect;
-    typedef GrFragmentProcessor INHERITED;
-};
-#endif
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index 4751fec..a0440f0 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -7,13 +7,52 @@
 
 #include "GrConvexPolyEffect.h"
 #include "SkPathPriv.h"
-#include "effects/GrAARectEffect.h"
 #include "effects/GrConstColorProcessor.h"
+#include "effects/GrSkSLFP.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
 #include "glsl/GrGLSLUniformHandler.h"
 
+GR_FP_SRC_STRING SKSL_AARECT_SRC = R"(
+layout(key) in GrClipEdgeType edgeType;
+layout(ctype=SkRect) in float4 rect;
+uniform float4 rectUniform;
+
+void main(int x, int y, inout half4 color) {
+    half alpha;
+    @switch (edgeType) {
+        case GrClipEdgeType::kFillBW: // fall through
+        case GrClipEdgeType::kInverseFillBW:
+            // non-AA
+            alpha = all(greaterThan(float4(x, y, rectUniform.zw),
+                                    float4(rectUniform.xy, x, y))) ? 1 : 0;
+            break;
+        default:
+            // The amount of coverage removed in x and y by the edges is computed as a pair of
+            // negative numbers, xSub and ySub.
+            half xSub, ySub;
+            xSub = min(x - rectUniform.x, 0.0);
+            xSub += min(rectUniform.z - x, 0.0);
+            ySub = min(y - rectUniform.y, 0.0);
+            ySub += min(rectUniform.w - y, 0.0);
+            // Now compute coverage in x and y and multiply them to get the fraction of the pixel
+            // covered.
+            alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));
+    }
+
+    @if (edgeType == GrClipEdgeType::kInverseFillBW || edgeType == GrClipEdgeType::kInverseFillAA) {
+        alpha = 1.0 - alpha;
+    }
+    color *= alpha;
+}
+)";
+
+struct AARectInputs {
+    GrClipEdgeType fEdgeType;
+    SkRect fRect;
+};
+
 //////////////////////////////////////////////////////////////////////////////
 
 class GrGLConvexPolyEffect : public GrGLSLFragmentProcessor {
@@ -88,7 +127,8 @@
 //////////////////////////////////////////////////////////////////////////////
 
 std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType type,
-                                                              const SkPath& path) {
+                                                              const SkPath& path,
+                                                              GrContext* context) {
     if (GrClipEdgeType::kHairlineAA == type) {
         return nullptr;
     }
@@ -158,12 +198,34 @@
     return Make(type, n, edges);
 }
 
+static void aa_rect_set_data_hook(const GrGLSLProgramDataManager& pdman,
+                                  const GrGLSLSkSLFP& glslProc,
+                                  const AARectInputs& inputs,
+                                  SkRect* prevRect) {
+    if (inputs.fRect != *prevRect) {
+        const SkRect& newRect = GrProcessorEdgeTypeIsAA(inputs.fEdgeType) ?
+                                inputs.fRect.makeInset(.5f, .5f) : inputs.fRect;
+        pdman.set4f(glslProc.uniformHandle(0), newRect.fLeft, newRect.fTop, newRect.fRight,
+                    newRect.fBottom);
+        *prevRect = inputs.fRect;
+    }
+}
+
 std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType edgeType,
-                                                              const SkRect& rect) {
+                                                              const SkRect& rect,
+                                                              GrContext* context) {
     if (GrClipEdgeType::kHairlineAA == edgeType){
         return nullptr;
     }
-    return GrAARectEffect::Make(edgeType, rect);
+    static int aaRectIndex = GrSkSLFP::NewIndex();
+    AARectInputs inputs;
+    inputs.fEdgeType = edgeType;
+    inputs.fRect = rect;
+    std::unique_ptr<GrSkSLFP> result = GrSkSLFP::Make(context, aaRectIndex, "AARect",
+                                                      SKSL_AARECT_SRC, inputs,
+                                                      SkRect::MakeXYWH(-1, -1, -1, -1),
+                                                      aa_rect_set_data_hook);
+    return std::unique_ptr<GrFragmentProcessor>(result.release());
 }
 
 GrConvexPolyEffect::~GrConvexPolyEffect() {}
diff --git a/src/gpu/effects/GrConvexPolyEffect.h b/src/gpu/effects/GrConvexPolyEffect.h
index d2ab4c9..886fed4 100644
--- a/src/gpu/effects/GrConvexPolyEffect.h
+++ b/src/gpu/effects/GrConvexPolyEffect.h
@@ -50,12 +50,14 @@
      * Creates an effect that clips against the path. If the path is not a convex polygon, is
      * inverse filled, or has too many edges, this will return nullptr.
      */
-    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkPath&);
+    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkPath&,
+                                                     GrContext* context);
 
     /**
-     * Creates an effect that fills inside the rect with AA edges..
+     * Creates an effect that fills inside the rect with AA edges.
      */
-    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&);
+    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&,
+                                                     GrContext* context);
 
     ~GrConvexPolyEffect() override;
 
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 6478306..0666089 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -7,6 +7,8 @@
 
 #include "GrRRectEffect.h"
 
+#include "GrContext.h"
+#include "GrContextPriv.h"
 #include "GrConvexPolyEffect.h"
 #include "GrFragmentProcessor.h"
 #include "GrOvalEffect.h"
@@ -122,7 +124,7 @@
     do {
         GrClipEdgeType et =
                 (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
-        fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps());
+        fp = GrRRectEffect::Make(et, rrect, d->context());
     } while (nullptr == fp);
     return fp;
 }
@@ -471,7 +473,7 @@
     std::unique_ptr<GrFragmentProcessor> fp;
     do {
         GrClipEdgeType et = (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
-        fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps());
+        fp = GrRRectEffect::Make(et, rrect, d->context());
     } while (nullptr == fp);
     return fp;
 }
@@ -670,13 +672,14 @@
 
 std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType,
                                                          const SkRRect& rrect,
-                                                         const GrShaderCaps& caps) {
+                                                         GrContext* context) {
     if (rrect.isRect()) {
-        return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
+        return GrConvexPolyEffect::Make(edgeType, rrect.getBounds(), context);
     }
 
     if (rrect.isOval()) {
-        return GrOvalEffect::Make(edgeType, rrect.getBounds(), caps);
+        return GrOvalEffect::Make(edgeType, rrect.getBounds(),
+                                  *context->contextPriv().caps()->shaderCaps());
     }
 
     if (rrect.isSimple()) {
@@ -684,7 +687,7 @@
             SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) {
             // In this case the corners are extremely close to rectangular and we collapse the
             // clip to a rectangular clip.
-            return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
+            return GrConvexPolyEffect::Make(edgeType, rrect.getBounds(), context);
         }
         if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) {
             return CircularRRectEffect::Make(edgeType, CircularRRectEffect::kAll_CornerFlags,
@@ -749,7 +752,7 @@
                 return CircularRRectEffect::Make(edgeType, cornerFlags, *rr);
             }
             case CircularRRectEffect::kNone_CornerFlags:
-                return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
+                return GrConvexPolyEffect::Make(edgeType, rrect.getBounds(), context);
             default: {
                 if (squashedRadii) {
                     // If we got here then we squashed some but not all the radii to zero. (If all
diff --git a/src/gpu/effects/GrRRectEffect.h b/src/gpu/effects/GrRRectEffect.h
index 55ef535..f44de74 100644
--- a/src/gpu/effects/GrRRectEffect.h
+++ b/src/gpu/effects/GrRRectEffect.h
@@ -12,6 +12,7 @@
 #include "GrTypesPriv.h"
 #include "SkRefCnt.h"
 
+class GrContext;
 class GrFragmentProcessor;
 class GrShaderCaps;
 class GrProcessor;
@@ -23,7 +24,7 @@
  * Creates an effect that performs anti-aliased clipping against a SkRRect. It doesn't support
  * all varieties of SkRRect so the caller must check for a nullptr return.
  */
-std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&, const GrShaderCaps&);
+std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&, GrContext*);
 };
 
 #endif
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index aa81ea5..3174d40 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -6,7 +6,6 @@
  */
 
 #include "GrSkSLFP.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "GrContext.h"
@@ -34,6 +33,9 @@
                 if (var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
                     fInputVars.push_back(&var);
                 }
+                if (var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
+                    fUniformVars.push_back(&var);
+                }
                 if (var.fModifiers.fLayout.fKey) {
                     fKeyVars.push_back(&var);
                 }
@@ -53,7 +55,8 @@
     size_t offset = 0;
     for (const auto& v : fInputVars) {
         SkSL::String name(v->fName);
-        if (&v->fType == fCompiler.context().fInt_Type.get()) {
+        if (v->fType.kind() == SkSL::Type::kEnum_Kind ||
+            &v->fType == fCompiler.context().fInt_Type.get()) {
             offset = SkAlign4(offset);
             int32_t v = *(int32_t*) (((uint8_t*) inputs) + offset);
             inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(v)));
@@ -80,178 +83,172 @@
     return result;
 }
 
-class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
-public:
-    GrGLSLSkSLFP(const SkSL::Context* context, const std::vector<const SkSL::Variable*>* inputVars,
-                 SkSL::String glsl, std::vector<SkSL::Compiler::FormatArg> formatArgs)
-            : fContext(*context)
-            , fInputVars(*inputVars)
-            , fGLSL(glsl)
-            , fFormatArgs(formatArgs) {}
+GrGLSLSkSLFP::GrGLSLSkSLFP(SkSL::Context* context,
+                           const std::vector<const SkSL::Variable*>* uniformVars,
+                           SkSL::String glsl,
+                           std::vector<SkSL::Compiler::FormatArg> formatArgs,
+                           void* extraData)
+        : fContext(*context)
+        , fUniformVars(*uniformVars)
+        , fGLSL(glsl)
+        , fFormatArgs(formatArgs)
+        , fExtraData(extraData) {}
 
-    GrSLType uniformType(const SkSL::Type& type) {
-        if (type == *fContext.fFloat_Type) {
-            return kFloat_GrSLType;
-        } else if (type == *fContext.fHalf_Type) {
-            return kHalf_GrSLType;
-        } else if (type == *fContext.fFloat2_Type) {
-            return kFloat2_GrSLType;
-        } else if (type == *fContext.fHalf2_Type) {
-            return kHalf2_GrSLType;
-        } else if (type == *fContext.fFloat4_Type) {
-            return kFloat4_GrSLType;
-        } else if (type == *fContext.fHalf4_Type) {
-            return kHalf4_GrSLType;
-        } else if (type == *fContext.fFloat4x4_Type) {
-            return kFloat4x4_GrSLType;
-        } else if (type == *fContext.fHalf4x4_Type) {
-            return kHalf4x4_GrSLType;
-        } else if (type == *fContext.fBool_Type) {
-            return kBool_GrSLType;
-        } else if (type == *fContext.fInt_Type) {
-            return kInt_GrSLType;
-        }
-        printf("%s\n", SkSL::String(type.fName).c_str());
-        SK_ABORT("unsupported uniform type");
+GrSLType GrGLSLSkSLFP::uniformType(const SkSL::Type& type) {
+    if (type == *fContext.fFloat_Type) {
         return kFloat_GrSLType;
+    } else if (type == *fContext.fHalf_Type) {
+        return kHalf_GrSLType;
+    } else if (type == *fContext.fFloat2_Type) {
+        return kFloat2_GrSLType;
+    } else if (type == *fContext.fHalf2_Type) {
+        return kHalf2_GrSLType;
+    } else if (type == *fContext.fFloat4_Type) {
+        return kFloat4_GrSLType;
+    } else if (type == *fContext.fHalf4_Type) {
+        return kHalf4_GrSLType;
+    } else if (type == *fContext.fFloat4x4_Type) {
+        return kFloat4x4_GrSLType;
+    } else if (type == *fContext.fHalf4x4_Type) {
+        return kHalf4x4_GrSLType;
+    } else if (type == *fContext.fBool_Type) {
+        return kBool_GrSLType;
+    } else if (type == *fContext.fInt_Type) {
+        return kInt_GrSLType;
     }
+    SK_ABORT("unsupported uniform type");
+    return kFloat_GrSLType;
+}
 
-    void emitCode(EmitArgs& args) override {
-        for (const auto& v : fInputVars) {
-            if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag && v->fType !=
-                                                                *fContext.fFragmentProcessor_Type) {
-                fUniformHandles.push_back(args.fUniformHandler->addUniform(
-                                                                   kFragment_GrShaderFlag,
-                                                                   this->uniformType(v->fType),
-                                                                   kDefault_GrSLPrecision,
-                                                                   SkSL::String(v->fName).c_str()));
-            }
+void* GrGLSLSkSLFP::extraData() const {
+    return fExtraData;
+}
+
+void GrGLSLSkSLFP::emitCode(EmitArgs& args) {
+    for (const auto& v : fUniformVars) {
+        if (v->fType != *fContext.fFragmentProcessor_Type) {
+            fUniformHandles.push_back(args.fUniformHandler->addUniform(
+                                                               kFragment_GrShaderFlag,
+                                                               this->uniformType(v->fType),
+                                                               kDefault_GrSLPrecision,
+                                                               SkSL::String(v->fName).c_str()));
         }
-        std::vector<SkString> childNames;
-        for (int i = 0; i < this->numChildProcessors(); ++i) {
-            childNames.push_back(SkStringPrintf("_child%d", i));
-            this->emitChild(i, &childNames[i], args);
-        }
-        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
-        int substringStartIndex = 0;
-        int formatArgIndex = 0;
-        for (size_t i = 0; i < fGLSL.length(); ++i) {
-            char c = fGLSL[i];
-            if (c == '%') {
-                fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex,
-                                        i - substringStartIndex);
-                ++i;
-                c = fGLSL[i];
-                switch (c) {
-                    case 's': {
-                        SkSL::Compiler::FormatArg& arg = fFormatArgs[formatArgIndex++];
-                        switch (arg.fKind) {
-                            case SkSL::Compiler::FormatArg::Kind::kInput:
-                                fragBuilder->codeAppend(args.fInputColor);
-                                break;
-                            case SkSL::Compiler::FormatArg::Kind::kOutput:
-                                fragBuilder->codeAppend(args.fOutputColor);
-                                break;
-                            case SkSL::Compiler::FormatArg::Kind::kUniform:
-                                fragBuilder->codeAppend(args.fUniformHandler->getUniformCStr(
-                                                                      fUniformHandles[arg.fIndex]));
-                                break;
-                            case SkSL::Compiler::FormatArg::Kind::kChildProcessor:
-                                fragBuilder->codeAppend(childNames[arg.fIndex].c_str());
-                                break;
-                        }
-                        break;
+    }
+    std::vector<SkString> childNames;
+    for (int i = 0; i < this->numChildProcessors(); ++i) {
+        childNames.push_back(SkStringPrintf("_child%d", i));
+        this->emitChild(i, &childNames[i], args);
+    }
+    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    int substringStartIndex = 0;
+    int formatArgIndex = 0;
+    for (size_t i = 0; i < fGLSL.length(); ++i) {
+        char c = fGLSL[i];
+        if (c == '%') {
+            fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex,
+                                    i - substringStartIndex);
+            ++i;
+            c = fGLSL[i];
+            switch (c) {
+                case 's': {
+                    SkSL::Compiler::FormatArg& arg = fFormatArgs[formatArgIndex++];
+                    switch (arg.fKind) {
+                        case SkSL::Compiler::FormatArg::Kind::kInput:
+                            fragBuilder->codeAppend(args.fInputColor);
+                            break;
+                        case SkSL::Compiler::FormatArg::Kind::kOutput:
+                            fragBuilder->codeAppend(args.fOutputColor);
+                            break;
+                        case SkSL::Compiler::FormatArg::Kind::kUniform:
+                            fragBuilder->codeAppend(args.fUniformHandler->getUniformCStr(
+                                                                  fUniformHandles[arg.fIndex]));
+                            break;
+                        case SkSL::Compiler::FormatArg::Kind::kChildProcessor:
+                            fragBuilder->codeAppend(childNames[arg.fIndex].c_str());
+                            break;
                     }
-                    default:
-                        fragBuilder->codeAppendf("%c", c);
+                    break;
                 }
-                substringStartIndex = i + 1;
+                default:
+                    fragBuilder->codeAppendf("%c", c);
             }
-        }
-        fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex,
-                                fGLSL.length() - substringStartIndex);
-    }
-
-    void onSetData(const GrGLSLProgramDataManager& pdman,
-                   const GrFragmentProcessor& _proc) override {
-        size_t uniformIndex = 0;
-        size_t offset = 0;
-        const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
-        char* inputs = (char*) outer.fInputs.get();
-        const SkSL::Context& context = outer.fFactory->fCompiler.context();
-        for (const auto& v : outer.fFactory->fInputVars) {
-            if (&v->fType == context.fFloat4_Type.get() ||
-                &v->fType == context.fHalf4_Type.get()) {
-                float f1, f2, f3, f4;
-                switch (v->fModifiers.fLayout.fCType) {
-                    case SkSL::Layout::CType::kSkPMColor:
-                        f1 = ((uint8_t*) inputs)[offset++] / 255.0;
-                        f2 = ((uint8_t*) inputs)[offset++] / 255.0;
-                        f3 = ((uint8_t*) inputs)[offset++] / 255.0;
-                        f4 = ((uint8_t*) inputs)[offset++] / 255.0;
-                        break;
-                    case SkSL::Layout::CType::kSkRect: // fall through
-                    case SkSL::Layout::CType::kDefault:
-                        offset = SkAlign4(offset);
-                        f1 = *(float*) (inputs + offset);
-                        offset += sizeof(float);
-                        f2 = *(float*) (inputs + offset);
-                        offset += sizeof(float);
-                        f3 = *(float*) (inputs + offset);
-                        offset += sizeof(float);
-                        f4 = *(float*) (inputs + offset);
-                        offset += sizeof(float);
-                        break;
-                    default:
-                        SK_ABORT("unsupported uniform ctype");
-                }
-                if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
-                    pdman.set4f(fUniformHandles[uniformIndex++], f1, f2, f3, f4);
-                }
-            } else if (&v->fType == context.fInt_Type.get()) {
-                int32_t i = *(int*) (inputs + offset);
-                offset += sizeof(int32_t);
-                if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
-                    pdman.set1i(fUniformHandles[uniformIndex++], i);
-                }
-            } else if (&v->fType == context.fBool_Type.get()) {
-                SkASSERT(!(v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag));
-                ++offset;
-            } else {
-                SkASSERT(&v->fType == context.fFragmentProcessor_Type.get());
-            }
+            substringStartIndex = i + 1;
         }
     }
+    fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex,
+                            fGLSL.length() - substringStartIndex);
+}
 
-    const SkSL::Context& fContext;
-    const std::vector<const SkSL::Variable*>& fInputVars;
-    // nearly-finished GLSL; still contains printf-style "%s" format tokens
-    const SkSL::String fGLSL;
-    std::vector<SkSL::Compiler::FormatArg> fFormatArgs;
-    std::vector<UniformHandle> fUniformHandles;
-};
-
-std::unique_ptr<GrSkSLFP> GrSkSLFP::Make(GrContext* context, int index, const char* name,
-                                         const char* sksl, const void* inputs,
-                                         size_t inputSize) {
-    return std::unique_ptr<GrSkSLFP>(new GrSkSLFP(context->contextPriv().getFPFactoryCache(),
-                                                  context->contextPriv().caps()->shaderCaps(),
-                                                  index, name, sksl, inputs, inputSize));
+void GrGLSLSkSLFP::onSetData(const GrGLSLProgramDataManager& pdman,
+                             const GrFragmentProcessor& _proc) {
+    size_t uniformIndex = 0;
+    size_t offset = 0;
+    const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
+    uint8_t* inputs = (uint8_t*) outer.fInputs;
+    const SkSL::Context& context = outer.fFactory->fCompiler.context();
+    for (const auto& v : outer.fFactory->fInputVars) {
+        if (&v->fType == context.fFloat4_Type.get() ||
+            &v->fType == context.fHalf4_Type.get()) {
+            float f1, f2, f3, f4;
+            switch (v->fModifiers.fLayout.fCType) {
+                case SkSL::Layout::CType::kSkPMColor:
+                    f1 = inputs[offset++] / 255.0;
+                    f2 = inputs[offset++] / 255.0;
+                    f3 = inputs[offset++] / 255.0;
+                    f4 = inputs[offset++] / 255.0;
+                    break;
+                case SkSL::Layout::CType::kSkRect: // fall through
+                case SkSL::Layout::CType::kDefault:
+                    offset = SkAlign4(offset);
+                    f1 = *(float*) (inputs + offset);
+                    offset += sizeof(float);
+                    f2 = *(float*) (inputs + offset);
+                    offset += sizeof(float);
+                    f3 = *(float*) (inputs + offset);
+                    offset += sizeof(float);
+                    f4 = *(float*) (inputs + offset);
+                    offset += sizeof(float);
+                    break;
+                default:
+                    SK_ABORT("unsupported uniform ctype");
+            }
+            if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
+                pdman.set4f(fUniformHandles[uniformIndex++], f1, f2, f3, f4);
+            }
+        } else if (v->fType.kind() == SkSL::Type::kEnum_Kind ||
+                   &v->fType == context.fInt_Type.get()) {
+            int32_t i = *(int*) (inputs + offset);
+            offset += sizeof(int32_t);
+            if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
+                pdman.set1i(fUniformHandles[uniformIndex++], i);
+            }
+        } else if (&v->fType == context.fBool_Type.get()) {
+            SkASSERT(!(v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag));
+            ++offset;
+        } else {
+            SkASSERT(&v->fType == context.fFragmentProcessor_Type.get());
+        }
+    }
+    if (fUniformHandles.size() && outer.fSetDataHook) {
+        outer.fSetDataHook(pdman, *this, outer.fInputs, fExtraData);
+    }
 }
 
 GrSkSLFP::GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps,
                    int index, const char* name, const char* sksl, const void* inputs,
-                   size_t inputSize)
+                   size_t inputSize, const void* extraData, size_t extraDataSize,
+                   UntypedDataHookFn setDataHook)
         : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags)
         , fFactoryCache(factoryCache)
         , fShaderCaps(sk_ref_sp(shaderCaps))
         , fIndex(index)
         , fName(name)
         , fSkSL(sksl)
-        , fInputs(new int8_t[inputSize])
-        , fInputSize(inputSize) {
-    memcpy(fInputs.get(), inputs, inputSize);
-}
+        , fInputs(inputs)
+        , fInputSize(inputSize)
+        , fExtraData(extraData)
+        , fExtraDataSize(extraDataSize)
+        , fSetDataHook(setDataHook) {}
 
 GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
         : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags)
@@ -261,10 +258,11 @@
         , fIndex(other.fIndex)
         , fName(other.fName)
         , fSkSL(other.fSkSL)
-        , fInputs(new int8_t[other.fInputSize])
-        , fInputSize(other.fInputSize) {
-    memcpy(fInputs.get(), other.fInputs.get(), fInputSize);
-}
+        , fInputs(other.fInputs)
+        , fInputSize(other.fInputSize)
+        , fExtraData(other.fExtraData)
+        , fExtraDataSize(other.fExtraDataSize)
+        , fSetDataHook(other.fSetDataHook) {}
 
 const char* GrSkSLFP::name() const {
     return fName;
@@ -286,24 +284,30 @@
 
 GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
     this->createFactory();
-    const SkSL::Program* specialized = fFactory->getSpecialization(fKey, fInputs.get(), fInputSize);
+    const SkSL::Program* specialized = fFactory->getSpecialization(fKey, fInputs, fInputSize);
     SkSL::String glsl;
     std::vector<SkSL::Compiler::FormatArg> formatArgs;
     if (!fFactory->fCompiler.toPipelineStage(*specialized, &glsl, &formatArgs)) {
         printf("%s\n", fFactory->fCompiler.errorText().c_str());
         SkASSERT(false);
     }
-    return new GrGLSLSkSLFP(specialized->fContext.get(), &fFactory->fInputVars, glsl, formatArgs);
+    void* result = ::operator new(sizeof(GrGLSLSkSLFP) + fExtraDataSize);
+    void* extraDataBytes = ((uint8_t*) result) + sizeof(GrGLSLSkSLFP);
+    if (fExtraDataSize) {
+        memcpy(extraDataBytes, fExtraData, fExtraDataSize);
+    }
+    return new (result) GrGLSLSkSLFP(specialized->fContext.get(), &fFactory->fUniformVars, glsl,
+                                     formatArgs, extraDataBytes);
 }
 
 void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                      GrProcessorKeyBuilder* b) const {
     this->createFactory();
     size_t offset = 0;
-    char* inputs = (char*) fInputs.get();
+    uint8_t* inputs = (uint8_t*) fInputs;
     const SkSL::Context& context = fFactory->fCompiler.context();
     for (const auto& v : fFactory->fInputVars) {
-        if (&v->fType == context.fInt_Type.get()) {
+        if (v->fType.kind() == SkSL::Type::kEnum_Kind || &v->fType == context.fInt_Type.get()) {
             offset = SkAlign4(offset);
             if (v->fModifiers.fLayout.fKey) {
                 fKey += inputs[offset + 0];
@@ -350,11 +354,20 @@
     const GrSkSLFP& sk = other.cast<GrSkSLFP>();
     SkASSERT(fIndex != sk.fIndex || fInputSize == sk.fInputSize);
     return fIndex == sk.fIndex &&
-            !memcmp(fInputs.get(), sk.fInputs.get(), fInputSize);
+            !memcmp(fInputs, sk.fInputs, fInputSize);
 }
 
 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
-    std::unique_ptr<GrSkSLFP> result(new GrSkSLFP(*this));
+    void* placement = GrSkSLFP::operator new(sizeof(GrSkSLFP) + fInputSize + fExtraDataSize);
+    std::unique_ptr<GrSkSLFP> result(new (placement) GrSkSLFP(*this));
+    void* inputsTarget = ((int8_t*) placement) + sizeof(GrSkSLFP);
+    memcpy(inputsTarget, fInputs, fInputSize);
+    result->fInputs = inputsTarget;
+    if (fExtraData) {
+        void* extraDataTarget = ((int8_t*) placement) + sizeof(GrSkSLFP) + fInputSize;
+        memcpy(extraDataTarget, fExtraData, fExtraDataSize);
+        result->fExtraData = extraDataTarget;
+    }
     for (int i = 0; i < this->numChildProcessors(); ++i) {
         result->registerChildProcessor(this->childProcessor(i).clone());
     }
@@ -398,6 +411,7 @@
 
 #include "GrConstColorProcessor.h"
 #include "SkArithmeticImageFilter.h"
+#include "effects/GrConvexPolyEffect.h"
 
 extern const char* SKSL_ARITHMETIC_SRC;
 extern const char* SKSL_DITHER_SRC;
@@ -406,14 +420,13 @@
 using Value = SkSL::Program::Settings::Value;
 
 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
-    int type = d->fRandom->nextULessThan(3);
+    int type = d->fRandom->nextULessThan(4);
     switch (type) {
         case 0: {
             static int ditherIndex = NewIndex();
             int rangeType = d->fRandom->nextULessThan(3);
             std::unique_ptr<GrSkSLFP> result = GrSkSLFP::Make(d->context(), ditherIndex, "Dither",
-                                                              SKSL_DITHER_SRC, &rangeType,
-                                                              sizeof(rangeType));
+                                                              SKSL_DITHER_SRC, rangeType);
             return std::unique_ptr<GrFragmentProcessor>(result.release());
         }
         case 1: {
@@ -426,7 +439,7 @@
             inputs.enforcePMColor = d->fRandom->nextBool();
             std::unique_ptr<GrSkSLFP> result = GrSkSLFP::Make(d->context(), arithmeticIndex,
                                                               "Arithmetic", SKSL_ARITHMETIC_SRC,
-                                                              &inputs, sizeof(inputs));
+                                                              inputs);
             result->addChild(GrConstColorProcessor::Make(
                                                         SK_PMColor4fWHITE,
                                                         GrConstColorProcessor::InputMode::kIgnore));
@@ -440,9 +453,23 @@
             }
             std::unique_ptr<GrSkSLFP> result = GrSkSLFP::Make(d->context(), overdrawIndex,
                                                               "Overdraw", SKSL_OVERDRAW_SRC,
-                                                              &inputs, sizeof(inputs));
+                                                              inputs);
             return std::unique_ptr<GrFragmentProcessor>(result.release());
         }
+        case 3: {
+            SkRect rect = SkRect::MakeLTRB(d->fRandom->nextSScalar1(),
+                                           d->fRandom->nextSScalar1(),
+                                           d->fRandom->nextSScalar1(),
+                                           d->fRandom->nextSScalar1());
+            std::unique_ptr<GrFragmentProcessor> fp;
+            do {
+                GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(
+                        d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
+
+                fp = GrConvexPolyEffect::Make(edgeType, rect, d->context());
+            } while (nullptr == fp);
+            return fp;
+        }
     }
     SK_ABORT("unreachable");
     return nullptr;
diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h
index c4acfd0..ae9be33 100644
--- a/src/gpu/effects/GrSkSLFP.h
+++ b/src/gpu/effects/GrSkSLFP.h
@@ -9,12 +9,17 @@
 #define GrSkSLFP_DEFINED
 
 #include "GrCaps.h"
-#include "GrFragmentProcessor.h"
+#include "GrContext.h"
+#include "GrContextPriv.h"
 #include "GrCoordTransform.h"
+#include "GrFragmentProcessor.h"
 #include "GrShaderCaps.h"
 #include "SkSLCompiler.h"
 #include "SkSLPipelineStageCodeGenerator.h"
 #include "SkRefCnt.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLUniformHandler.h"
 #include "../private/GrSkSLFPFactoryCache.h"
 
 #if GR_TEST_UTILS
@@ -25,9 +30,16 @@
 
 class GrContext;
 class GrSkSLFPFactory;
+class GrGLSLSkSLFP;
 
 class GrSkSLFP : public GrFragmentProcessor {
 public:
+    using UniformHandle = GrGLSLUniformHandler::UniformHandle;
+
+    template<typename Inputs, typename ExtraData>
+    using DataHookFn = void(const GrGLSLProgramDataManager& pdman, const GrGLSLSkSLFP& glslProc,
+                            const Inputs& inputs, ExtraData* extraData);
+
     /**
      * Returns a new unique identifier. Each different SkSL fragment processor should call
      * NewIndex once, statically, and use this index for all calls to Make.
@@ -66,23 +78,72 @@
      * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
      * associated with it.
      */
-    static std::unique_ptr<GrSkSLFP> Make(
-                   GrContext* context,
-                   int index,
-                   const char* name,
-                   const char* sksl,
-                   const void* inputs,
-                   size_t inputSize);
+    template<typename Inputs>
+    static std::unique_ptr<GrSkSLFP> Make(GrContext* context, int index, const char* name,
+                                          const char* sksl, const Inputs& inputs) {
+        void* resultBytes = GrSkSLFP::operator new(sizeof(GrSkSLFP) + sizeof(Inputs));
+        void* inputBytes = (int8_t*) resultBytes + sizeof(GrSkSLFP);
+        memcpy(inputBytes, &inputs, sizeof(Inputs));
+        GrSkSLFP* result = new (resultBytes) GrSkSLFP(context->contextPriv().getFPFactoryCache(),
+                                                      context->contextPriv().caps()->shaderCaps(),
+                                                      index, name, sksl, inputBytes,
+                                                      sizeof(Inputs), nullptr, 0, nullptr);
+        return std::unique_ptr<GrSkSLFP>(result);
+    }
+
+    /**
+     * As the above overload of Make, but also tracks an additional extraData struct which is shared
+     * between all instances of the FP. The extraData struct is copied into the GrGLSLSkSLFP and is
+     * passed as an argument to the setDataHook function. setDataHook is called after the automatic
+     * handling of 'in uniform' variables is completed and is responsible for providing values for
+     * all non-'in' uniform variables.
+     */
+    template<typename Inputs, typename ExtraData>
+    static std::unique_ptr<GrSkSLFP> Make(GrContext* context, int index, const char* name,
+                                          const char* sksl, const Inputs& inputs,
+                                          const ExtraData& extraData,
+                                          DataHookFn<Inputs, ExtraData>* setDataHook) {
+        void* resultBytes = GrSkSLFP::operator new(sizeof(GrSkSLFP) + sizeof(Inputs) +
+                                                   sizeof(ExtraData));
+        void* inputBytes = (int8_t*) resultBytes + sizeof(GrSkSLFP);
+        memcpy(inputBytes, &inputs, sizeof(Inputs));
+        void* extraDataBytes = (int8_t*) resultBytes + sizeof(GrSkSLFP) + sizeof(Inputs);
+        memcpy(extraDataBytes, &extraData, sizeof(ExtraData));
+        auto genericFn = [setDataHook] (const GrGLSLProgramDataManager& pdman,
+                                        const GrGLSLSkSLFP& glslProc,
+                                        const void* inputs,
+                                        void* extraData) {
+            (*setDataHook)(pdman, glslProc, *reinterpret_cast<const Inputs*>(inputs),
+                           reinterpret_cast<ExtraData*>(extraData));
+        };
+        return std::unique_ptr<GrSkSLFP>(new (resultBytes) GrSkSLFP(
+                                                        context->contextPriv().getFPFactoryCache(),
+                                                        context->contextPriv().caps()->shaderCaps(),
+                                                        index, name, sksl, inputBytes,
+                                                        sizeof(Inputs), extraDataBytes,
+                                                        sizeof(ExtraData), genericFn));
+    }
 
     const char* name() const override;
 
     void addChild(std::unique_ptr<GrFragmentProcessor> child);
 
+    void setSetDataHook(void (*hook)(const GrGLSLProgramDataManager& pdman,
+                                     const GrGLSLSkSLFP& glslProc,
+                                     const GrSkSLFP& proc));
+
+    const void* inputs() const { return fInputs; }
+
     std::unique_ptr<GrFragmentProcessor> clone() const override;
 
 private:
+    using UntypedDataHookFn = std::function<void(const GrGLSLProgramDataManager&,
+                                                 const GrGLSLSkSLFP&,
+                                                 const void*,
+                                                 void*)>;
     GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, int fIndex,
-             const char* name, const char* sksl, const void* inputs, size_t inputSize);
+             const char* name, const char* sksl, const void* inputs, size_t inputSize,
+             const void* extraData, size_t extraDataSize, UntypedDataHookFn setDataHook);
 
     GrSkSLFP(const GrSkSLFP& other);
 
@@ -106,10 +167,16 @@
 
     const char* fSkSL;
 
-    const std::unique_ptr<int8_t[]> fInputs;
+    const void* fInputs;
 
     size_t fInputSize;
 
+    const void* fExtraData;
+
+    size_t fExtraDataSize;
+
+    UntypedDataHookFn fSetDataHook;
+
     mutable SkSL::String fKey;
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
@@ -121,6 +188,41 @@
     friend class GrSkSLFPFactory;
 };
 
+class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLSkSLFP(SkSL::Context* context, const std::vector<const SkSL::Variable*>* uniformVars,
+                 SkSL::String glsl, std::vector<SkSL::Compiler::FormatArg> formatArgs,
+                 void* extraData);
+
+    GrSLType uniformType(const SkSL::Type& type);
+
+    /**
+     * Returns the extraData pointer.
+     */
+    void* extraData() const;
+
+    void emitCode(EmitArgs& args) override;
+
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override;
+
+    UniformHandle uniformHandle(int index) const { return fUniformHandles[index]; }
+
+private:
+    const SkSL::Context& fContext;
+
+    const std::vector<const SkSL::Variable*>& fUniformVars;
+
+    // nearly-finished GLSL; still contains printf-style "%s" format tokens
+    const SkSL::String fGLSL;
+
+    std::vector<SkSL::Compiler::FormatArg> fFormatArgs;
+
+    std::vector<UniformHandle> fUniformHandles;
+
+    void* fExtraData;
+};
+
 /**
  * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
  * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
@@ -147,6 +249,8 @@
 
     std::vector<const SkSL::Variable*> fInputVars;
 
+    std::vector<const SkSL::Variable*> fUniformVars;
+
     std::vector<const SkSL::Variable*> fKeyVars;
 
     std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp
index c267058..f7492eb 100644
--- a/src/sksl/SkSLCFGGenerator.cpp
+++ b/src/sksl/SkSLCFGGenerator.cpp
@@ -596,6 +596,11 @@
         case Statement::kSwitch_Kind: {
             SwitchStatement& ss = (SwitchStatement&) **s;
             this->addExpression(cfg, &ss.fValue, true);
+            for (const auto& c : ss.fCases) {
+                if (c->fValue) {
+                    this->addExpression(cfg, &c->fValue, true);
+                }
+            }
             cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
                                                          nullptr, s });
             BlockId start = cfg.fCurrent;
@@ -604,11 +609,6 @@
             for (const auto& c : ss.fCases) {
                 cfg.newBlock();
                 cfg.addExit(start, cfg.fCurrent);
-                if (c->fValue) {
-                    // technically this should go in the start block, but it doesn't actually matter
-                    // because it must be constant. Not worth running two loops for.
-                    this->addExpression(cfg, &c->fValue, true);
-                }
                 for (auto& caseStatement : c->fStatements) {
                     this->addStatement(cfg, &caseStatement);
                 }
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 41ff5cc..09af06b 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -57,6 +57,7 @@
 ;
 
 static const char* SKSL_PIPELINE_STAGE_INCLUDE =
+#include "sksl_enums.inc"
 #include "sksl_pipeline.inc"
 ;
 
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index bf9e5e1..5f79896 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -933,14 +933,13 @@
     ASTType enumType(e.fOffset, e.fTypeName, ASTType::kIdentifier_Kind, {});
     const Type* type = this->convertType(enumType);
     Modifiers modifiers(layout, Modifiers::kConst_Flag);
-    std::shared_ptr<SymbolTable> symbols(new SymbolTable(fSymbolTable, &fErrors));
-    fSymbolTable = symbols;
+    AutoSymbolTable s(this);
+    std::shared_ptr<SymbolTable> symbols = fSymbolTable;
     for (size_t i = 0; i < e.fNames.size(); i++) {
         std::unique_ptr<Expression> value;
         if (e.fValues[i]) {
             value = this->convertExpression(*e.fValues[i]);
             if (!value) {
-                fSymbolTable = symbols->fParent;
                 return;
             }
             this->getConstantInt(*value, &currentValue);
@@ -956,7 +955,6 @@
     }
     fProgramElements->push_back(std::unique_ptr<ProgramElement>(new Enum(e.fOffset, e.fTypeName,
                                                                          symbols)));
-    fSymbolTable = symbols->fParent;
 }
 
 const Type* IRGenerator::convertType(const ASTType& type) {
diff --git a/src/sksl/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/SkSLPipelineStageCodeGenerator.cpp
index 4ca839d..694b368 100644
--- a/src/sksl/SkSLPipelineStageCodeGenerator.cpp
+++ b/src/sksl/SkSLPipelineStageCodeGenerator.cpp
@@ -146,8 +146,7 @@
                                 found = true;
                                 break;
                             }
-                            if (var.fModifiers.fFlags & (Modifiers::kIn_Flag |
-                                                         Modifiers::kUniform_Flag)) {
+                            if (var.fModifiers.fFlags & Modifiers::kUniform_Flag) {
                                 ++index;
                             }
                         }
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index 4cbde55..719767d 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -223,6 +223,14 @@
     , fInheritedElements(inheritedElements)
     , fElements(std::move(elements)) {}
 
+    ~Program() {
+        // destroy elements in reverse order, so references to variables are destroyed before the
+        // variables themselves
+        while (fElements.size()) {
+            fElements.pop_back();
+        }
+    }
+
     iterator begin() {
         if (fInheritedElements) {
             return iterator(fInheritedElements->begin(), fInheritedElements->end(),
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index 2cfeaae..0f1966b 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -1041,7 +1041,6 @@
         }
 
         auto context = GrContext::MakeMock(nullptr);
-        const GrCaps* caps = context->contextPriv().caps();
 
         // Zero the memory we will new the GrReducedClip into. This ensures the elements gen ID
         // will be kInvalidGenID if left uninitialized.
@@ -1052,7 +1051,8 @@
         // Get the reduced version of the stack.
         SkRect queryBounds = kBounds;
         queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
-        const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, queryBounds, caps);
+        const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, queryBounds,
+                                                                         context.get());
 
         REPORTER_ASSERT(reporter,
                         reduced->maskElements().isEmpty() ||
@@ -1112,12 +1112,12 @@
         SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
 
         auto context = GrContext::MakeMock(nullptr);
-        const GrCaps* caps = context->contextPriv().caps();
 
         SkAlignedSTStorage<1, GrReducedClip> storage;
         memset(storage.get(), 0, sizeof(GrReducedClip));
         GR_STATIC_ASSERT(0 == SkClipStack::kInvalidGenID);
-        const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, bounds, caps);
+        const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, bounds,
+                                                                         context.get());
 
         REPORTER_ASSERT(reporter, reduced->maskElements().count() == 1);
         // Clips will be cached based on the generation id. Make sure the gen id is valid.
@@ -1201,10 +1201,9 @@
 #undef XYWH
 #undef IXYWH
         auto context = GrContext::MakeMock(nullptr);
-        const GrCaps* caps = context->contextPriv().caps();
 
         for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) {
-            const GrReducedClip reduced(stack, testCases[i].testBounds, caps);
+            const GrReducedClip reduced(stack, testCases[i].testBounds, context.get());
             REPORTER_ASSERT(reporter, reduced.maskElements().count() ==
                             testCases[i].reducedClipCount);
             SkASSERT(reduced.maskElements().count() == testCases[i].reducedClipCount);
@@ -1229,10 +1228,9 @@
     SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
 
     auto context = GrContext::MakeMock(nullptr);
-    const GrCaps* caps = context->contextPriv().caps();
 
     // At the time, this would crash.
-    const GrReducedClip reduced(stack, bounds, caps);
+    const GrReducedClip reduced(stack, bounds, context.get());
     REPORTER_ASSERT(reporter, reduced.maskElements().isEmpty());
 }
 
@@ -1248,11 +1246,10 @@
                           const SkRect& preXformQuery, ClipMethod expectedMethod,
                           int numExpectedElems = 0) {
     auto context = GrContext::MakeMock(nullptr);
-    const GrCaps* caps = context->contextPriv().caps();
 
     SkRect queryBounds;
     queryXform.mapRect(&queryBounds, preXformQuery);
-    const GrReducedClip reduced(stack, queryBounds, caps);
+    const GrReducedClip reduced(stack, queryBounds, context.get());
 
     SkClipStack::BoundsType stackBoundsType;
     SkRect stackBounds;
@@ -1410,14 +1407,13 @@
     pathStack.clipPath(clipPath, SkMatrix::I(), kIntersect_SkClipOp, true);
 
     auto context = GrContext::MakeMock(nullptr);
-    const GrCaps* caps = context->contextPriv().caps();
 
     for (const SkClipStack& stack : {rectStack, pathStack}) {
         for (SkRect queryBounds : {SkRect::MakeXYWH(53, 60, GrClip::kBoundsTolerance, 1000),
                                    SkRect::MakeXYWH(53, 60, GrClip::kBoundsTolerance/2, 1000),
                                    SkRect::MakeXYWH(53, 160, 1000, GrClip::kBoundsTolerance),
                                    SkRect::MakeXYWH(53, 160, 1000, GrClip::kBoundsTolerance/2)}) {
-            const GrReducedClip reduced(stack, queryBounds, caps);
+            const GrReducedClip reduced(stack, queryBounds, context.get());
             REPORTER_ASSERT(reporter, !reduced.hasScissor());
             REPORTER_ASSERT(reporter, reduced.maskElements().isEmpty());
             REPORTER_ASSERT(reporter,