moved files generated from .fp files into generated/ directories

Bug: skia:
Change-Id: I8605cdfcc0b1c56c23a6075c7fe188ab7384681c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/207221
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/gpu/effects/generated/GrAARectEffect.cpp b/src/gpu/effects/generated/GrAARectEffect.cpp
new file mode 100644
index 0000000..62d9f52
--- /dev/null
+++ b/src/gpu/effects/generated/GrAARectEffect.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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);
+        rectUniformVar = args.fUniformHandler->addUniform(
+                kFragment_GrShaderFlag, kFloat4_GrSLType, "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 = min(half(sk_FragCoord.x - "
+                "%s.x), 0.0);\n        xSub += min(half(%s.z - sk_FragCoord.x), 0.0);\n        "
+                "ySub = min(half(sk_FragCoord.y - %s.y), 0.0);\n        ySub += min(half(%s.w - "
+                "sk_FragCoord.y), 0.0);\n        alpha = (1.0 + ",
+                prevRect.left(),
+                prevRect.top(),
+                prevRect.right(),
+                prevRect.bottom(),
+                (int)_outer.edgeType,
+                args.fUniformHandler->getUniformCStr(rectUniformVar),
+                args.fUniformHandler->getUniformCStr(rectUniformVar),
+                args.fUniformHandler->getUniformCStr(rectUniformVar),
+                args.fUniformHandler->getUniformCStr(rectUniformVar),
+                args.fUniformHandler->getUniformCStr(rectUniformVar),
+                args.fUniformHandler->getUniformCStr(rectUniformVar));
+        fragBuilder->codeAppendf(
+                "max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n}\n@if (%d == 2 || %d == 3) {\n    "
+                "alpha = 1.0 - 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 = rectUniformVar;
+        (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 rectUniformVar;
+};
+GrGLSLFragmentProcessor* GrAARectEffect::onCreateGLSLInstance() const {
+    return new GrGLSLAARectEffect();
+}
+void GrAARectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                           GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)edgeType);
+}
+bool GrAARectEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrAARectEffect& that = other.cast<GrAARectEffect>();
+    (void)that;
+    if (edgeType != that.edgeType) return false;
+    if (rect != that.rect) return false;
+    return true;
+}
+GrAARectEffect::GrAARectEffect(const GrAARectEffect& src)
+        : INHERITED(kGrAARectEffect_ClassID, src.optimizationFlags())
+        , edgeType(src.edgeType)
+        , rect(src.rect) {}
+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/generated/GrAARectEffect.h b/src/gpu/effects/generated/GrAARectEffect.h
new file mode 100644
index 0000000..0c302c5
--- /dev/null
+++ b/src/gpu/effects/generated/GrAARectEffect.h
@@ -0,0 +1,39 @@
+/*
+ * 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:
+    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"; }
+    GrClipEdgeType edgeType;
+    SkRect rect;
+
+private:
+    GrAARectEffect(GrClipEdgeType edgeType, SkRect rect)
+            : INHERITED(kGrAARectEffect_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , edgeType(edgeType)
+            , rect(rect) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp b/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp
new file mode 100644
index 0000000..70fe78a
--- /dev/null
+++ b/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 GrAlphaThresholdFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrAlphaThresholdFragmentProcessor.h"
+
+inline GrFragmentProcessor::OptimizationFlags GrAlphaThresholdFragmentProcessor::optFlags(
+        float outerThreshold) {
+    if (outerThreshold >= 1.0) {
+        return kPreservesOpaqueInput_OptimizationFlag |
+               kCompatibleWithCoverageAsAlpha_OptimizationFlag;
+    } else {
+        return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
+    }
+}
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLAlphaThresholdFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLAlphaThresholdFragmentProcessor() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrAlphaThresholdFragmentProcessor& _outer =
+                args.fFp.cast<GrAlphaThresholdFragmentProcessor>();
+        (void)_outer;
+        auto innerThreshold = _outer.innerThreshold;
+        (void)innerThreshold;
+        auto outerThreshold = _outer.outerThreshold;
+        (void)outerThreshold;
+        innerThresholdVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                             "innerThreshold");
+        outerThresholdVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                             "outerThreshold");
+        SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
+        fragBuilder->codeAppendf(
+                "half4 color = %s;\nhalf4 mask_color = texture(%s, %s).%s;\nif (mask_color.w < "
+                "0.5) {\n    if (color.w > %s) {\n        half scale = %s / color.w;\n        "
+                "color.xyz *= scale;\n        color.w = %s;\n    }\n} else if (color.w < %s) {\n   "
+                " half scale = %s / max(0.001, color.w);\n    color.xyz *= scale;\n    color.w = "
+                "%s;\n}\n%s = color;\n",
+                args.fInputColor,
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                sk_TransformedCoords2D_0.c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fUniformHandler->getUniformCStr(outerThresholdVar),
+                args.fUniformHandler->getUniformCStr(outerThresholdVar),
+                args.fUniformHandler->getUniformCStr(outerThresholdVar),
+                args.fUniformHandler->getUniformCStr(innerThresholdVar),
+                args.fUniformHandler->getUniformCStr(innerThresholdVar),
+                args.fUniformHandler->getUniformCStr(innerThresholdVar), args.fOutputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrAlphaThresholdFragmentProcessor& _outer =
+                _proc.cast<GrAlphaThresholdFragmentProcessor>();
+        {
+            pdman.set1f(innerThresholdVar, (_outer.innerThreshold));
+            pdman.set1f(outerThresholdVar, (_outer.outerThreshold));
+        }
+    }
+    UniformHandle innerThresholdVar;
+    UniformHandle outerThresholdVar;
+};
+GrGLSLFragmentProcessor* GrAlphaThresholdFragmentProcessor::onCreateGLSLInstance() const {
+    return new GrGLSLAlphaThresholdFragmentProcessor();
+}
+void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                              GrProcessorKeyBuilder* b) const {}
+bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrAlphaThresholdFragmentProcessor& that = other.cast<GrAlphaThresholdFragmentProcessor>();
+    (void)that;
+    if (mask != that.mask) return false;
+    if (innerThreshold != that.innerThreshold) return false;
+    if (outerThreshold != that.outerThreshold) return false;
+    return true;
+}
+GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor(
+        const GrAlphaThresholdFragmentProcessor& src)
+        : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, src.optimizationFlags())
+        , maskCoordTransform(src.maskCoordTransform)
+        , mask(src.mask)
+        , innerThreshold(src.innerThreshold)
+        , outerThreshold(src.outerThreshold) {
+    this->setTextureSamplerCnt(1);
+    this->addCoordTransform(&maskCoordTransform);
+}
+std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(*this));
+}
+const GrFragmentProcessor::TextureSampler& GrAlphaThresholdFragmentProcessor::onTextureSampler(
+        int index) const {
+    return IthTextureSampler(index, mask);
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate(
+        GrProcessorTestData* testData) {
+    sk_sp<GrTextureProxy> maskProxy = testData->textureProxy(GrProcessorUnitTest::kAlphaTextureIdx);
+    // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly.
+    float innerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f;
+    float outerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f;
+    const int kMaxWidth = 1000;
+    const int kMaxHeight = 1000;
+    uint32_t width = testData->fRandom->nextULessThan(kMaxWidth);
+    uint32_t height = testData->fRandom->nextULessThan(kMaxHeight);
+    uint32_t x = testData->fRandom->nextULessThan(kMaxWidth - width);
+    uint32_t y = testData->fRandom->nextULessThan(kMaxHeight - height);
+    SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height);
+    return GrAlphaThresholdFragmentProcessor::Make(std::move(maskProxy), innerThresh, outerThresh,
+                                                   bounds);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h b/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h
new file mode 100644
index 0000000..8067db5
--- /dev/null
+++ b/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h
@@ -0,0 +1,55 @@
+/*
+ * 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 GrAlphaThresholdFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrAlphaThresholdFragmentProcessor_DEFINED
+#define GrAlphaThresholdFragmentProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrAlphaThresholdFragmentProcessor : public GrFragmentProcessor {
+public:
+    inline OptimizationFlags optFlags(float outerThreshold);
+
+    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> mask,
+                                                     float innerThreshold,
+                                                     float outerThreshold,
+                                                     const SkIRect& bounds) {
+        return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(
+                mask, innerThreshold, outerThreshold, bounds));
+    }
+    GrAlphaThresholdFragmentProcessor(const GrAlphaThresholdFragmentProcessor& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "AlphaThresholdFragmentProcessor"; }
+    GrCoordTransform maskCoordTransform;
+    TextureSampler mask;
+    float innerThreshold;
+    float outerThreshold;
+
+private:
+    GrAlphaThresholdFragmentProcessor(sk_sp<GrTextureProxy> mask, float innerThreshold,
+                                      float outerThreshold, const SkIRect& bounds)
+            : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, kNone_OptimizationFlags)
+            , maskCoordTransform(
+                      SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())),
+                      mask.get())
+            , mask(std::move(mask))
+            , innerThreshold(innerThreshold)
+            , outerThreshold(outerThreshold) {
+        this->setTextureSamplerCnt(1);
+        this->addCoordTransform(&maskCoordTransform);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp
new file mode 100644
index 0000000..b91e148
--- /dev/null
+++ b/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 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 GrBlurredEdgeFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrBlurredEdgeFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLBlurredEdgeFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLBlurredEdgeFragmentProcessor() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrBlurredEdgeFragmentProcessor& _outer =
+                args.fFp.cast<GrBlurredEdgeFragmentProcessor>();
+        (void)_outer;
+        auto mode = _outer.mode;
+        (void)mode;
+        fragBuilder->codeAppendf(
+                "half factor = 1.0 - %s.w;\n@switch (%d) {\n    case 0:\n        factor = "
+                "exp((-factor * factor) * 4.0) - 0.017999999999999999;\n        break;\n    case "
+                "1:\n        factor = smoothstep(1.0, 0.0, factor);\n        break;\n}\n%s = "
+                "half4(factor);\n",
+                args.fInputColor, (int)_outer.mode, args.fOutputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {}
+};
+GrGLSLFragmentProcessor* GrBlurredEdgeFragmentProcessor::onCreateGLSLInstance() const {
+    return new GrGLSLBlurredEdgeFragmentProcessor();
+}
+void GrBlurredEdgeFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                           GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)mode);
+}
+bool GrBlurredEdgeFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrBlurredEdgeFragmentProcessor& that = other.cast<GrBlurredEdgeFragmentProcessor>();
+    (void)that;
+    if (mode != that.mode) return false;
+    return true;
+}
+GrBlurredEdgeFragmentProcessor::GrBlurredEdgeFragmentProcessor(
+        const GrBlurredEdgeFragmentProcessor& src)
+        : INHERITED(kGrBlurredEdgeFragmentProcessor_ClassID, src.optimizationFlags())
+        , mode(src.mode) {}
+std::unique_ptr<GrFragmentProcessor> GrBlurredEdgeFragmentProcessor::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrBlurredEdgeFragmentProcessor(*this));
+}
diff --git a/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h b/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h
new file mode 100644
index 0000000..c149bcc
--- /dev/null
+++ b/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 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 GrBlurredEdgeFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrBlurredEdgeFragmentProcessor_DEFINED
+#define GrBlurredEdgeFragmentProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrBlurredEdgeFragmentProcessor : public GrFragmentProcessor {
+public:
+    enum class Mode { kGaussian = 0, kSmoothStep = 1 };
+    static std::unique_ptr<GrFragmentProcessor> Make(Mode mode) {
+        return std::unique_ptr<GrFragmentProcessor>(new GrBlurredEdgeFragmentProcessor(mode));
+    }
+    GrBlurredEdgeFragmentProcessor(const GrBlurredEdgeFragmentProcessor& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "BlurredEdgeFragmentProcessor"; }
+    Mode mode;
+
+private:
+    GrBlurredEdgeFragmentProcessor(Mode mode)
+            : INHERITED(kGrBlurredEdgeFragmentProcessor_ClassID, kNone_OptimizationFlags)
+            , mode(mode) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp b/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp
new file mode 100644
index 0000000..28cdbd5
--- /dev/null
+++ b/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp
@@ -0,0 +1,350 @@
+/*
+ * 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 GrCircleBlurFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrCircleBlurFragmentProcessor.h"
+
+#include "GrProxyProvider.h"
+
+// Computes an unnormalized half kernel (right side). Returns the summation of all the half
+// kernel values.
+static float make_unnormalized_half_kernel(float* halfKernel, int halfKernelSize, float sigma) {
+    const float invSigma = 1.f / sigma;
+    const float b = -0.5f * invSigma * invSigma;
+    float tot = 0.0f;
+    // Compute half kernel values at half pixel steps out from the center.
+    float t = 0.5f;
+    for (int i = 0; i < halfKernelSize; ++i) {
+        float value = expf(t * t * b);
+        tot += value;
+        halfKernel[i] = value;
+        t += 1.f;
+    }
+    return tot;
+}
+
+// Create a Gaussian half-kernel (right side) and a summed area table given a sigma and number
+// of discrete steps. The half kernel is normalized to sum to 0.5.
+static void make_half_kernel_and_summed_table(float* halfKernel, float* summedHalfKernel,
+                                              int halfKernelSize, float sigma) {
+    // The half kernel should sum to 0.5 not 1.0.
+    const float tot = 2.f * make_unnormalized_half_kernel(halfKernel, halfKernelSize, sigma);
+    float sum = 0.f;
+    for (int i = 0; i < halfKernelSize; ++i) {
+        halfKernel[i] /= tot;
+        sum += halfKernel[i];
+        summedHalfKernel[i] = sum;
+    }
+}
+
+// Applies the 1D half kernel vertically at points along the x axis to a circle centered at the
+// origin with radius circleR.
+void apply_kernel_in_y(float* results, int numSteps, float firstX, float circleR,
+                       int halfKernelSize, const float* summedHalfKernelTable) {
+    float x = firstX;
+    for (int i = 0; i < numSteps; ++i, x += 1.f) {
+        if (x < -circleR || x > circleR) {
+            results[i] = 0;
+            continue;
+        }
+        float y = sqrtf(circleR * circleR - x * x);
+        // In the column at x we exit the circle at +y and -y
+        // The summed table entry j is actually reflects an offset of j + 0.5.
+        y -= 0.5f;
+        int yInt = SkScalarFloorToInt(y);
+        SkASSERT(yInt >= -1);
+        if (y < 0) {
+            results[i] = (y + 0.5f) * summedHalfKernelTable[0];
+        } else if (yInt >= halfKernelSize - 1) {
+            results[i] = 0.5f;
+        } else {
+            float yFrac = y - yInt;
+            results[i] = (1.f - yFrac) * summedHalfKernelTable[yInt] +
+                         yFrac * summedHalfKernelTable[yInt + 1];
+        }
+    }
+}
+
+// Apply a Gaussian at point (evalX, 0) to a circle centered at the origin with radius circleR.
+// This relies on having a half kernel computed for the Gaussian and a table of applications of
+// the half kernel in y to columns at (evalX - halfKernel, evalX - halfKernel + 1, ..., evalX +
+// halfKernel) passed in as yKernelEvaluations.
+static uint8_t eval_at(float evalX, float circleR, const float* halfKernel, int halfKernelSize,
+                       const float* yKernelEvaluations) {
+    float acc = 0;
+
+    float x = evalX - halfKernelSize;
+    for (int i = 0; i < halfKernelSize; ++i, x += 1.f) {
+        if (x < -circleR || x > circleR) {
+            continue;
+        }
+        float verticalEval = yKernelEvaluations[i];
+        acc += verticalEval * halfKernel[halfKernelSize - i - 1];
+    }
+    for (int i = 0; i < halfKernelSize; ++i, x += 1.f) {
+        if (x < -circleR || x > circleR) {
+            continue;
+        }
+        float verticalEval = yKernelEvaluations[i + halfKernelSize];
+        acc += verticalEval * halfKernel[i];
+    }
+    // Since we applied a half kernel in y we multiply acc by 2 (the circle is symmetric about
+    // the x axis).
+    return SkUnitScalarClampToByte(2.f * acc);
+}
+
+// This function creates a profile of a blurred circle. It does this by computing a kernel for
+// half the Gaussian and a matching summed area table. The summed area table is used to compute
+// an array of vertical applications of the half kernel to the circle along the x axis. The
+// table of y evaluations has 2 * k + n entries where k is the size of the half kernel and n is
+// the size of the profile being computed. Then for each of the n profile entries we walk out k
+// steps in each horizontal direction multiplying the corresponding y evaluation by the half
+// kernel entry and sum these values to compute the profile entry.
+static void create_circle_profile(uint8_t* weights, float sigma, float circleR,
+                                  int profileTextureWidth) {
+    const int numSteps = profileTextureWidth;
+
+    // The full kernel is 6 sigmas wide.
+    int halfKernelSize = SkScalarCeilToInt(6.0f * sigma);
+    // round up to next multiple of 2 and then divide by 2
+    halfKernelSize = ((halfKernelSize + 1) & ~1) >> 1;
+
+    // Number of x steps at which to apply kernel in y to cover all the profile samples in x.
+    int numYSteps = numSteps + 2 * halfKernelSize;
+
+    SkAutoTArray<float> bulkAlloc(halfKernelSize + halfKernelSize + numYSteps);
+    float* halfKernel = bulkAlloc.get();
+    float* summedKernel = bulkAlloc.get() + halfKernelSize;
+    float* yEvals = bulkAlloc.get() + 2 * halfKernelSize;
+    make_half_kernel_and_summed_table(halfKernel, summedKernel, halfKernelSize, sigma);
+
+    float firstX = -halfKernelSize + 0.5f;
+    apply_kernel_in_y(yEvals, numYSteps, firstX, circleR, halfKernelSize, summedKernel);
+
+    for (int i = 0; i < numSteps - 1; ++i) {
+        float evalX = i + 0.5f;
+        weights[i] = eval_at(evalX, circleR, halfKernel, halfKernelSize, yEvals + i);
+    }
+    // Ensure the tail of the Gaussian goes to zero.
+    weights[numSteps - 1] = 0;
+}
+
+static void create_half_plane_profile(uint8_t* profile, int profileWidth) {
+    SkASSERT(!(profileWidth & 0x1));
+    // The full kernel is 6 sigmas wide.
+    float sigma = profileWidth / 6.f;
+    int halfKernelSize = profileWidth / 2;
+
+    SkAutoTArray<float> halfKernel(halfKernelSize);
+
+    // The half kernel should sum to 0.5.
+    const float tot = 2.f * make_unnormalized_half_kernel(halfKernel.get(), halfKernelSize, sigma);
+    float sum = 0.f;
+    // Populate the profile from the right edge to the middle.
+    for (int i = 0; i < halfKernelSize; ++i) {
+        halfKernel[halfKernelSize - i - 1] /= tot;
+        sum += halfKernel[halfKernelSize - i - 1];
+        profile[profileWidth - i - 1] = SkUnitScalarClampToByte(sum);
+    }
+    // Populate the profile from the middle to the left edge (by flipping the half kernel and
+    // continuing the summation).
+    for (int i = 0; i < halfKernelSize; ++i) {
+        sum += halfKernel[i];
+        profile[halfKernelSize - i - 1] = SkUnitScalarClampToByte(sum);
+    }
+    // Ensure tail goes to 0.
+    profile[profileWidth - 1] = 0;
+}
+
+static sk_sp<GrTextureProxy> create_profile_texture(GrProxyProvider* proxyProvider,
+                                                    const SkRect& circle, float sigma,
+                                                    float* solidRadius, float* textureRadius) {
+    float circleR = circle.width() / 2.0f;
+    if (circleR < SK_ScalarNearlyZero) {
+        return nullptr;
+    }
+    // Profile textures are cached by the ratio of sigma to circle radius and by the size of the
+    // profile texture (binned by powers of 2).
+    SkScalar sigmaToCircleRRatio = sigma / circleR;
+    // When sigma is really small this becomes a equivalent to convolving a Gaussian with a
+    // half-plane. Similarly, in the extreme high ratio cases circle becomes a point WRT to the
+    // Guassian and the profile texture is a just a Gaussian evaluation. However, we haven't yet
+    // implemented this latter optimization.
+    sigmaToCircleRRatio = SkTMin(sigmaToCircleRRatio, 8.f);
+    SkFixed sigmaToCircleRRatioFixed;
+    static const SkScalar kHalfPlaneThreshold = 0.1f;
+    bool useHalfPlaneApprox = false;
+    if (sigmaToCircleRRatio <= kHalfPlaneThreshold) {
+        useHalfPlaneApprox = true;
+        sigmaToCircleRRatioFixed = 0;
+        *solidRadius = circleR - 3 * sigma;
+        *textureRadius = 6 * sigma;
+    } else {
+        // Convert to fixed point for the key.
+        sigmaToCircleRRatioFixed = SkScalarToFixed(sigmaToCircleRRatio);
+        // We shave off some bits to reduce the number of unique entries. We could probably
+        // shave off more than we do.
+        sigmaToCircleRRatioFixed &= ~0xff;
+        sigmaToCircleRRatio = SkFixedToScalar(sigmaToCircleRRatioFixed);
+        sigma = circleR * sigmaToCircleRRatio;
+        *solidRadius = 0;
+        *textureRadius = circleR + 3 * sigma;
+    }
+
+    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+    GrUniqueKey key;
+    GrUniqueKey::Builder builder(&key, kDomain, 1, "1-D Circular Blur");
+    builder[0] = sigmaToCircleRRatioFixed;
+    builder.finish();
+
+    sk_sp<GrTextureProxy> blurProfile =
+            proxyProvider->findOrCreateProxyByUniqueKey(key, kTopLeft_GrSurfaceOrigin);
+    if (!blurProfile) {
+        static constexpr int kProfileTextureWidth = 512;
+
+        SkBitmap bm;
+        if (!bm.tryAllocPixels(SkImageInfo::MakeA8(kProfileTextureWidth, 1))) {
+            return nullptr;
+        }
+
+        if (useHalfPlaneApprox) {
+            create_half_plane_profile(bm.getAddr8(0, 0), kProfileTextureWidth);
+        } else {
+            // Rescale params to the size of the texture we're creating.
+            SkScalar scale = kProfileTextureWidth / *textureRadius;
+            create_circle_profile(bm.getAddr8(0, 0), sigma * scale, circleR * scale,
+                                  kProfileTextureWidth);
+        }
+
+        bm.setImmutable();
+        sk_sp<SkImage> image = SkImage::MakeFromBitmap(bm);
+
+        blurProfile = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
+                                                        SkBudgeted::kYes, SkBackingFit::kExact);
+        if (!blurProfile) {
+            return nullptr;
+        }
+
+        SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
+        proxyProvider->assignUniqueKeyToProxy(key, blurProfile.get());
+    }
+
+    return blurProfile;
+}
+
+std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make(
+        GrProxyProvider* proxyProvider, const SkRect& circle, float sigma) {
+    float solidRadius;
+    float textureRadius;
+    sk_sp<GrTextureProxy> profile(
+            create_profile_texture(proxyProvider, circle, sigma, &solidRadius, &textureRadius));
+    if (!profile) {
+        return nullptr;
+    }
+    return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(
+            circle, textureRadius, solidRadius, std::move(profile)));
+}
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLCircleBlurFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLCircleBlurFragmentProcessor() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrCircleBlurFragmentProcessor& _outer =
+                args.fFp.cast<GrCircleBlurFragmentProcessor>();
+        (void)_outer;
+        auto circleRect = _outer.circleRect;
+        (void)circleRect;
+        auto textureRadius = _outer.textureRadius;
+        (void)textureRadius;
+        auto solidRadius = _outer.solidRadius;
+        (void)solidRadius;
+        circleDataVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
+                                                         "circleData");
+        fragBuilder->codeAppendf(
+                "half2 vec = half2(half((sk_FragCoord.x - float(%s.x)) * float(%s.w)), "
+                "half((sk_FragCoord.y - float(%s.y)) * float(%s.w)));\nhalf dist = length(vec) + "
+                "(0.5 - %s.z) * %s.w;\n%s = %s * texture(%s, float2(half2(dist, 0.5))).%s.w;\n",
+                args.fUniformHandler->getUniformCStr(circleDataVar),
+                args.fUniformHandler->getUniformCStr(circleDataVar),
+                args.fUniformHandler->getUniformCStr(circleDataVar),
+                args.fUniformHandler->getUniformCStr(circleDataVar),
+                args.fUniformHandler->getUniformCStr(circleDataVar),
+                args.fUniformHandler->getUniformCStr(circleDataVar), args.fOutputColor,
+                args.fInputColor,
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& data,
+                   const GrFragmentProcessor& _proc) override {
+        const GrCircleBlurFragmentProcessor& _outer = _proc.cast<GrCircleBlurFragmentProcessor>();
+        auto circleRect = _outer.circleRect;
+        (void)circleRect;
+        auto textureRadius = _outer.textureRadius;
+        (void)textureRadius;
+        auto solidRadius = _outer.solidRadius;
+        (void)solidRadius;
+        GrSurfaceProxy& blurProfileSamplerProxy = *_outer.textureSampler(0).proxy();
+        GrTexture& blurProfileSampler = *blurProfileSamplerProxy.peekTexture();
+        (void)blurProfileSampler;
+        UniformHandle& circleData = circleDataVar;
+        (void)circleData;
+
+        data.set4f(circleData, circleRect.centerX(), circleRect.centerY(), solidRadius,
+                   1.f / textureRadius);
+    }
+    UniformHandle circleDataVar;
+};
+GrGLSLFragmentProcessor* GrCircleBlurFragmentProcessor::onCreateGLSLInstance() const {
+    return new GrGLSLCircleBlurFragmentProcessor();
+}
+void GrCircleBlurFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                          GrProcessorKeyBuilder* b) const {}
+bool GrCircleBlurFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrCircleBlurFragmentProcessor& that = other.cast<GrCircleBlurFragmentProcessor>();
+    (void)that;
+    if (circleRect != that.circleRect) return false;
+    if (textureRadius != that.textureRadius) return false;
+    if (solidRadius != that.solidRadius) return false;
+    if (blurProfileSampler != that.blurProfileSampler) return false;
+    return true;
+}
+GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(
+        const GrCircleBlurFragmentProcessor& src)
+        : INHERITED(kGrCircleBlurFragmentProcessor_ClassID, src.optimizationFlags())
+        , circleRect(src.circleRect)
+        , textureRadius(src.textureRadius)
+        , solidRadius(src.solidRadius)
+        , blurProfileSampler(src.blurProfileSampler) {
+    this->setTextureSamplerCnt(1);
+}
+std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(*this));
+}
+const GrFragmentProcessor::TextureSampler& GrCircleBlurFragmentProcessor::onTextureSampler(
+        int index) const {
+    return IthTextureSampler(index, blurProfileSampler);
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate(
+        GrProcessorTestData* testData) {
+    SkScalar wh = testData->fRandom->nextRangeScalar(100.f, 1000.f);
+    SkScalar sigma = testData->fRandom->nextRangeF(1.f, 10.f);
+    SkRect circle = SkRect::MakeWH(wh, wh);
+    return GrCircleBlurFragmentProcessor::Make(testData->proxyProvider(), circle, sigma);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h b/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h
new file mode 100644
index 0000000..1969fc3
--- /dev/null
+++ b/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h
@@ -0,0 +1,46 @@
+/*
+ * 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 GrCircleBlurFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrCircleBlurFragmentProcessor_DEFINED
+#define GrCircleBlurFragmentProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrCircleBlurFragmentProcessor : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(GrProxyProvider*, const SkRect& circle,
+                                                     float sigma);
+    GrCircleBlurFragmentProcessor(const GrCircleBlurFragmentProcessor& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "CircleBlurFragmentProcessor"; }
+    SkRect circleRect;
+    float textureRadius;
+    float solidRadius;
+    TextureSampler blurProfileSampler;
+
+private:
+    GrCircleBlurFragmentProcessor(SkRect circleRect, float textureRadius, float solidRadius,
+                                  sk_sp<GrTextureProxy> blurProfileSampler)
+            : INHERITED(kGrCircleBlurFragmentProcessor_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , circleRect(circleRect)
+            , textureRadius(textureRadius)
+            , solidRadius(solidRadius)
+            , blurProfileSampler(std::move(blurProfileSampler)) {
+        this->setTextureSamplerCnt(1);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrCircleEffect.cpp b/src/gpu/effects/generated/GrCircleEffect.cpp
new file mode 100644
index 0000000..f24f2d7
--- /dev/null
+++ b/src/gpu/effects/generated/GrCircleEffect.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017 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 GrCircleEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrCircleEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLCircleEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLCircleEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrCircleEffect& _outer = args.fFp.cast<GrCircleEffect>();
+        (void)_outer;
+        auto edgeType = _outer.edgeType;
+        (void)edgeType;
+        auto center = _outer.center;
+        (void)center;
+        auto radius = _outer.radius;
+        (void)radius;
+        prevRadius = -1.0;
+        circleVar =
+                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "circle");
+        fragBuilder->codeAppendf(
+                "half2 prevCenter;\nhalf prevRadius = %f;\nhalf d;\n@if (%d == 2 || %d == 3) {\n   "
+                " d = half((length((float2(%s.xy) - sk_FragCoord.xy) * float(%s.w)) - 1.0) * "
+                "float(%s.z));\n} else {\n    d = half((1.0 - length((float2(%s.xy) - "
+                "sk_FragCoord.xy) * float(%s.w))) * float(%s.z));\n}\n@if ((%d == 1 || %d == 3) || "
+                "%d == 4) {\n    d = clamp(d, 0.0, 1.0);\n} else {\n    d = d > 0.5 ? 1.0 : "
+                "0.0;\n}\n%s = %s * d;\n",
+                prevRadius, (int)_outer.edgeType, (int)_outer.edgeType,
+                args.fUniformHandler->getUniformCStr(circleVar),
+                args.fUniformHandler->getUniformCStr(circleVar),
+                args.fUniformHandler->getUniformCStr(circleVar),
+                args.fUniformHandler->getUniformCStr(circleVar),
+                args.fUniformHandler->getUniformCStr(circleVar),
+                args.fUniformHandler->getUniformCStr(circleVar), (int)_outer.edgeType,
+                (int)_outer.edgeType, (int)_outer.edgeType, args.fOutputColor, args.fInputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrCircleEffect& _outer = _proc.cast<GrCircleEffect>();
+        auto edgeType = _outer.edgeType;
+        (void)edgeType;
+        auto center = _outer.center;
+        (void)center;
+        auto radius = _outer.radius;
+        (void)radius;
+        UniformHandle& circle = circleVar;
+        (void)circle;
+
+        if (radius != prevRadius || center != prevCenter) {
+            SkScalar effectiveRadius = radius;
+            if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType)edgeType)) {
+                effectiveRadius -= 0.5f;
+                // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the
+                // shader.
+                effectiveRadius = SkTMax(0.001f, effectiveRadius);
+            } else {
+                effectiveRadius += 0.5f;
+            }
+            pdman.set4f(circle, center.fX, center.fY, effectiveRadius,
+                        SkScalarInvert(effectiveRadius));
+            prevCenter = center;
+            prevRadius = radius;
+        }
+    }
+    SkPoint prevCenter = half2(0);
+    float prevRadius = 0;
+    UniformHandle circleVar;
+};
+GrGLSLFragmentProcessor* GrCircleEffect::onCreateGLSLInstance() const {
+    return new GrGLSLCircleEffect();
+}
+void GrCircleEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                           GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)edgeType);
+}
+bool GrCircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrCircleEffect& that = other.cast<GrCircleEffect>();
+    (void)that;
+    if (edgeType != that.edgeType) return false;
+    if (center != that.center) return false;
+    if (radius != that.radius) return false;
+    return true;
+}
+GrCircleEffect::GrCircleEffect(const GrCircleEffect& src)
+        : INHERITED(kGrCircleEffect_ClassID, src.optimizationFlags())
+        , edgeType(src.edgeType)
+        , center(src.center)
+        , radius(src.radius) {}
+std::unique_ptr<GrFragmentProcessor> GrCircleEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(*this));
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrCircleEffect::TestCreate(GrProcessorTestData* testData) {
+    SkPoint center;
+    center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
+    center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
+    SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f);
+    GrClipEdgeType et;
+    do {
+        et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
+    } while (GrClipEdgeType::kHairlineAA == et);
+    return GrCircleEffect::Make(et, center, radius);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrCircleEffect.h b/src/gpu/effects/generated/GrCircleEffect.h
new file mode 100644
index 0000000..81ab40e
--- /dev/null
+++ b/src/gpu/effects/generated/GrCircleEffect.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 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 GrCircleEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrCircleEffect_DEFINED
+#define GrCircleEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrCircleEffect : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center,
+                                                     float radius) {
+        // A radius below half causes the implicit insetting done by this processor to become
+        // inverted. We could handle this case by making the processor code more complicated.
+        if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) {
+            return nullptr;
+        }
+        return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius));
+    }
+    GrCircleEffect(const GrCircleEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "CircleEffect"; }
+    GrClipEdgeType edgeType;
+    SkPoint center;
+    float radius;
+
+private:
+    GrCircleEffect(GrClipEdgeType edgeType, SkPoint center, float radius)
+            : INHERITED(kGrCircleEffect_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , edgeType(edgeType)
+            , center(center)
+            , radius(radius) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrComposeLerpEffect.cpp b/src/gpu/effects/generated/GrComposeLerpEffect.cpp
new file mode 100644
index 0000000..a768b5c
--- /dev/null
+++ b/src/gpu/effects/generated/GrComposeLerpEffect.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * 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 GrComposeLerpEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrComposeLerpEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLComposeLerpEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLComposeLerpEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrComposeLerpEffect& _outer = args.fFp.cast<GrComposeLerpEffect>();
+        (void)_outer;
+        auto weight = _outer.weight;
+        (void)weight;
+        weightVar =
+                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, "weight");
+        SkString _child0("_child0");
+        if (_outer.child1_index >= 0) {
+            this->emitChild(_outer.child1_index, &_child0, args);
+        } else {
+            fragBuilder->codeAppendf("half4 %s;", _child0.c_str());
+        }
+        SkString _child1("_child1");
+        if (_outer.child2_index >= 0) {
+            this->emitChild(_outer.child2_index, &_child1, args);
+        } else {
+            fragBuilder->codeAppendf("half4 %s;", _child1.c_str());
+        }
+        fragBuilder->codeAppendf("%s = mix(%s ? %s : %s, %s ? %s : %s, half(%s));\n",
+                                 args.fOutputColor, _outer.child1_index >= 0 ? "true" : "false",
+                                 _child0.c_str(), args.fInputColor,
+                                 _outer.child2_index >= 0 ? "true" : "false", _child1.c_str(),
+                                 args.fInputColor, args.fUniformHandler->getUniformCStr(weightVar));
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrComposeLerpEffect& _outer = _proc.cast<GrComposeLerpEffect>();
+        { pdman.set1f(weightVar, (_outer.weight)); }
+    }
+    UniformHandle weightVar;
+};
+GrGLSLFragmentProcessor* GrComposeLerpEffect::onCreateGLSLInstance() const {
+    return new GrGLSLComposeLerpEffect();
+}
+void GrComposeLerpEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                GrProcessorKeyBuilder* b) const {}
+bool GrComposeLerpEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrComposeLerpEffect& that = other.cast<GrComposeLerpEffect>();
+    (void)that;
+    if (weight != that.weight) return false;
+    return true;
+}
+GrComposeLerpEffect::GrComposeLerpEffect(const GrComposeLerpEffect& src)
+        : INHERITED(kGrComposeLerpEffect_ClassID, src.optimizationFlags())
+        , child1_index(src.child1_index)
+        , child2_index(src.child2_index)
+        , weight(src.weight) {
+    if (child1_index >= 0) {
+        this->registerChildProcessor(src.childProcessor(child1_index).clone());
+    }
+    if (child2_index >= 0) {
+        this->registerChildProcessor(src.childProcessor(child2_index).clone());
+    }
+}
+std::unique_ptr<GrFragmentProcessor> GrComposeLerpEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrComposeLerpEffect(*this));
+}
diff --git a/src/gpu/effects/generated/GrComposeLerpEffect.h b/src/gpu/effects/generated/GrComposeLerpEffect.h
new file mode 100644
index 0000000..823d44d
--- /dev/null
+++ b/src/gpu/effects/generated/GrComposeLerpEffect.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * 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 GrComposeLerpEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrComposeLerpEffect_DEFINED
+#define GrComposeLerpEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrComposeLerpEffect : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child1,
+                                                     std::unique_ptr<GrFragmentProcessor> child2,
+                                                     float weight) {
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrComposeLerpEffect(std::move(child1), std::move(child2), weight));
+    }
+    GrComposeLerpEffect(const GrComposeLerpEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "ComposeLerpEffect"; }
+    int child1_index = -1;
+    int child2_index = -1;
+    float weight;
+
+private:
+    GrComposeLerpEffect(std::unique_ptr<GrFragmentProcessor> child1,
+                        std::unique_ptr<GrFragmentProcessor> child2, float weight)
+            : INHERITED(kGrComposeLerpEffect_ClassID, kNone_OptimizationFlags), weight(weight) {
+        if (child1) {
+            child1_index = this->numChildProcessors();
+            this->registerChildProcessor(std::move(child1));
+        }
+        if (child2) {
+            child2_index = this->numChildProcessors();
+            this->registerChildProcessor(std::move(child2));
+        }
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp b/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp
new file mode 100644
index 0000000..2f3a5e4
--- /dev/null
+++ b/src/gpu/effects/generated/GrComposeLerpRedEffect.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * 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 GrComposeLerpRedEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrComposeLerpRedEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLComposeLerpRedEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLComposeLerpRedEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrComposeLerpRedEffect& _outer = args.fFp.cast<GrComposeLerpRedEffect>();
+        (void)_outer;
+        SkString _child0("_child0");
+        if (_outer.child1_index >= 0) {
+            this->emitChild(_outer.child1_index, &_child0, args);
+        } else {
+            fragBuilder->codeAppendf("half4 %s;", _child0.c_str());
+        }
+        SkString _child1("_child1");
+        if (_outer.child2_index >= 0) {
+            this->emitChild(_outer.child2_index, &_child1, args);
+        } else {
+            fragBuilder->codeAppendf("half4 %s;", _child1.c_str());
+        }
+        SkString _child2("_child2");
+        this->emitChild(_outer.lerp_index, &_child2, args);
+        fragBuilder->codeAppendf("%s = mix(%s ? %s : %s, %s ? %s : %s, %s.x);\n", args.fOutputColor,
+                                 _outer.child1_index >= 0 ? "true" : "false", _child0.c_str(),
+                                 args.fInputColor, _outer.child2_index >= 0 ? "true" : "false",
+                                 _child1.c_str(), args.fInputColor, _child2.c_str());
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {}
+};
+GrGLSLFragmentProcessor* GrComposeLerpRedEffect::onCreateGLSLInstance() const {
+    return new GrGLSLComposeLerpRedEffect();
+}
+void GrComposeLerpRedEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                   GrProcessorKeyBuilder* b) const {}
+bool GrComposeLerpRedEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrComposeLerpRedEffect& that = other.cast<GrComposeLerpRedEffect>();
+    (void)that;
+    return true;
+}
+GrComposeLerpRedEffect::GrComposeLerpRedEffect(const GrComposeLerpRedEffect& src)
+        : INHERITED(kGrComposeLerpRedEffect_ClassID, src.optimizationFlags())
+        , child1_index(src.child1_index)
+        , child2_index(src.child2_index)
+        , lerp_index(src.lerp_index) {
+    if (child1_index >= 0) {
+        this->registerChildProcessor(src.childProcessor(child1_index).clone());
+    }
+    if (child2_index >= 0) {
+        this->registerChildProcessor(src.childProcessor(child2_index).clone());
+    }
+    this->registerChildProcessor(src.childProcessor(lerp_index).clone());
+}
+std::unique_ptr<GrFragmentProcessor> GrComposeLerpRedEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrComposeLerpRedEffect(*this));
+}
diff --git a/src/gpu/effects/generated/GrComposeLerpRedEffect.h b/src/gpu/effects/generated/GrComposeLerpRedEffect.h
new file mode 100644
index 0000000..f109c8c
--- /dev/null
+++ b/src/gpu/effects/generated/GrComposeLerpRedEffect.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * 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 GrComposeLerpRedEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrComposeLerpRedEffect_DEFINED
+#define GrComposeLerpRedEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrComposeLerpRedEffect : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child1,
+                                                     std::unique_ptr<GrFragmentProcessor> child2,
+                                                     std::unique_ptr<GrFragmentProcessor> lerp) {
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrComposeLerpRedEffect(std::move(child1), std::move(child2), std::move(lerp)));
+    }
+    GrComposeLerpRedEffect(const GrComposeLerpRedEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "ComposeLerpRedEffect"; }
+    int child1_index = -1;
+    int child2_index = -1;
+    int lerp_index = -1;
+
+private:
+    GrComposeLerpRedEffect(std::unique_ptr<GrFragmentProcessor> child1,
+                           std::unique_ptr<GrFragmentProcessor> child2,
+                           std::unique_ptr<GrFragmentProcessor> lerp)
+            : INHERITED(kGrComposeLerpRedEffect_ClassID, kNone_OptimizationFlags) {
+        if (child1) {
+            child1_index = this->numChildProcessors();
+            this->registerChildProcessor(std::move(child1));
+        }
+        if (child2) {
+            child2_index = this->numChildProcessors();
+            this->registerChildProcessor(std::move(child2));
+        }
+        SkASSERT(lerp);
+        lerp_index = this->numChildProcessors();
+        this->registerChildProcessor(std::move(lerp));
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrConfigConversionEffect.cpp b/src/gpu/effects/generated/GrConfigConversionEffect.cpp
new file mode 100644
index 0000000..5acd214
--- /dev/null
+++ b/src/gpu/effects/generated/GrConfigConversionEffect.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 GrConfigConversionEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrConfigConversionEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLConfigConversionEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLConfigConversionEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrConfigConversionEffect& _outer = args.fFp.cast<GrConfigConversionEffect>();
+        (void)_outer;
+        auto pmConversion = _outer.pmConversion;
+        (void)pmConversion;
+
+        fragBuilder->forceHighPrecision();
+        fragBuilder->codeAppendf(
+                "%s = floor(%s * 255.0 + 0.5) / 255.0;\n@switch (%d) {\n    case 0:\n        "
+                "%s.xyz = floor((%s.xyz * %s.w) * 255.0 + 0.5) / 255.0;\n        break;\n    case "
+                "1:\n        %s.xyz = %s.w <= 0.0 ? half3(0.0) : floor((%s.xyz / %s.w) * 255.0 + "
+                "0.5) / 255.0;\n        break;\n}\n",
+                args.fOutputColor, args.fInputColor, (int)_outer.pmConversion, args.fOutputColor,
+                args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor,
+                args.fOutputColor, args.fOutputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {}
+};
+GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
+    return new GrGLSLConfigConversionEffect();
+}
+void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                     GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)pmConversion);
+}
+bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrConfigConversionEffect& that = other.cast<GrConfigConversionEffect>();
+    (void)that;
+    if (pmConversion != that.pmConversion) return false;
+    return true;
+}
+GrConfigConversionEffect::GrConfigConversionEffect(const GrConfigConversionEffect& src)
+        : INHERITED(kGrConfigConversionEffect_ClassID, src.optimizationFlags())
+        , pmConversion(src.pmConversion) {}
+std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(*this));
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(
+        GrProcessorTestData* data) {
+    PMConversion pmConv = static_cast<PMConversion>(
+            data->fRandom->nextULessThan((int)PMConversion::kPMConversionCnt));
+    return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
+}
+#endif
diff --git a/src/gpu/effects/generated/GrConfigConversionEffect.h b/src/gpu/effects/generated/GrConfigConversionEffect.h
new file mode 100644
index 0000000..1b8dac2
--- /dev/null
+++ b/src/gpu/effects/generated/GrConfigConversionEffect.h
@@ -0,0 +1,160 @@
+/*
+ * 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 GrConfigConversionEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrConfigConversionEffect_DEFINED
+#define GrConfigConversionEffect_DEFINED
+#include "SkTypes.h"
+
+#include "GrClip.h"
+#include "GrContext.h"
+#include "GrContextPriv.h"
+#include "GrProxyProvider.h"
+#include "GrRenderTargetContext.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrConfigConversionEffect : public GrFragmentProcessor {
+public:
+    static bool TestForPreservingPMConversions(GrContext* context) {
+        static constexpr int kSize = 256;
+        static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
+        static constexpr SkColorType kColorType = kRGBA_8888_SkColorType;
+        const GrBackendFormat format =
+                context->priv().caps()->getBackendFormatFromColorType(kColorType);
+        SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
+        uint32_t* srcData = data.get();
+        uint32_t* firstRead = data.get() + kSize * kSize;
+        uint32_t* secondRead = data.get() + 2 * kSize * kSize;
+
+        // Fill with every possible premultiplied A, color channel value. There will be 256-y
+        // duplicate values in row y. We set r, g, and b to the same value since they are handled
+        // identically.
+        for (int y = 0; y < kSize; ++y) {
+            for (int x = 0; x < kSize; ++x) {
+                uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize * y + x]);
+                color[3] = y;
+                color[2] = SkTMin(x, y);
+                color[1] = SkTMin(x, y);
+                color[0] = SkTMin(x, y);
+            }
+        }
+        memset(firstRead, 0, kSize * kSize * sizeof(uint32_t));
+        memset(secondRead, 0, kSize * kSize * sizeof(uint32_t));
+
+        const SkImageInfo ii =
+                SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+
+        sk_sp<GrRenderTargetContext> readRTC(context->priv().makeDeferredRenderTargetContext(
+                format, SkBackingFit::kExact, kSize, kSize, kConfig, nullptr));
+        sk_sp<GrRenderTargetContext> tempRTC(context->priv().makeDeferredRenderTargetContext(
+                format, SkBackingFit::kExact, kSize, kSize, kConfig, nullptr));
+        if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
+            return false;
+        }
+        // Adding discard to appease vulkan validation warning about loading uninitialized data on
+        // draw
+        readRTC->discard();
+
+        GrProxyProvider* proxyProvider = context->priv().proxyProvider();
+
+        SkPixmap pixmap(ii, srcData, 4 * kSize);
+
+        // This function is only ever called if we are in a GrContext that has a GrGpu since we are
+        // calling read pixels here. Thus the pixel data will be uploaded immediately and we don't
+        // need to keep the pixel data alive in the proxy. Therefore the ReleaseProc is nullptr.
+        sk_sp<SkImage> image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
+
+        sk_sp<GrTextureProxy> dataProxy = proxyProvider->createTextureProxy(
+                std::move(image), kNone_GrSurfaceFlags, 1, SkBudgeted::kYes, SkBackingFit::kExact);
+        if (!dataProxy) {
+            return false;
+        }
+
+        static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
+
+        // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
+        // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
+        // We then verify that two reads produced the same values.
+
+        GrPaint paint1;
+        GrPaint paint2;
+        GrPaint paint3;
+        std::unique_ptr<GrFragmentProcessor> pmToUPM(
+                new GrConfigConversionEffect(PMConversion::kToUnpremul));
+        std::unique_ptr<GrFragmentProcessor> upmToPM(
+                new GrConfigConversionEffect(PMConversion::kToPremul));
+
+        paint1.addColorTextureProcessor(dataProxy, SkMatrix::I());
+        paint1.addColorFragmentProcessor(pmToUPM->clone());
+        paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+        readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect,
+                                kRect);
+        if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
+            return false;
+        }
+
+        // Adding discard to appease vulkan validation warning about loading uninitialized data on
+        // draw
+        tempRTC->discard();
+
+        paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), SkMatrix::I());
+        paint2.addColorFragmentProcessor(std::move(upmToPM));
+        paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+        tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect,
+                                kRect);
+
+        paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), SkMatrix::I());
+        paint3.addColorFragmentProcessor(std::move(pmToUPM));
+        paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+        readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect,
+                                kRect);
+
+        if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
+            return false;
+        }
+
+        for (int y = 0; y < kSize; ++y) {
+            for (int x = 0; x <= y; ++x) {
+                if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+                                                     PMConversion pmConversion) {
+        if (!fp) {
+            return nullptr;
+        }
+        std::unique_ptr<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
+        std::unique_ptr<GrFragmentProcessor> fpPipeline[] = {std::move(fp), std::move(ccFP)};
+        return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
+    }
+    GrConfigConversionEffect(const GrConfigConversionEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "ConfigConversionEffect"; }
+    PMConversion pmConversion;
+
+private:
+    GrConfigConversionEffect(PMConversion pmConversion)
+            : INHERITED(kGrConfigConversionEffect_ClassID, kNone_OptimizationFlags)
+            , pmConversion(pmConversion) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrConstColorProcessor.cpp b/src/gpu/effects/generated/GrConstColorProcessor.cpp
new file mode 100644
index 0000000..ca23d07
--- /dev/null
+++ b/src/gpu/effects/generated/GrConstColorProcessor.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 GrConstColorProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrConstColorProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLConstColorProcessor : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLConstColorProcessor() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrConstColorProcessor& _outer = args.fFp.cast<GrConstColorProcessor>();
+        (void)_outer;
+        auto color = _outer.color;
+        (void)color;
+        auto mode = _outer.mode;
+        (void)mode;
+        colorVar =
+                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "color");
+        fragBuilder->codeAppendf(
+                "@switch (%d) {\n    case 0:\n        %s = %s;\n        break;\n    case 1:\n      "
+                "  %s = %s * %s;\n        break;\n    case 2:\n        %s = %s.w * %s;\n        "
+                "break;\n}\n",
+                (int)_outer.mode, args.fOutputColor, args.fUniformHandler->getUniformCStr(colorVar),
+                args.fOutputColor, args.fInputColor, args.fUniformHandler->getUniformCStr(colorVar),
+                args.fOutputColor, args.fInputColor,
+                args.fUniformHandler->getUniformCStr(colorVar));
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrConstColorProcessor& _outer = _proc.cast<GrConstColorProcessor>();
+        {
+            const SkPMColor4f& colorValue = _outer.color;
+            if (colorPrev != colorValue) {
+                colorPrev = colorValue;
+                pdman.set4fv(colorVar, 1, colorValue.vec());
+            }
+        }
+    }
+    SkPMColor4f colorPrev = {SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN};
+    UniformHandle colorVar;
+};
+GrGLSLFragmentProcessor* GrConstColorProcessor::onCreateGLSLInstance() const {
+    return new GrGLSLConstColorProcessor();
+}
+void GrConstColorProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                  GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)mode);
+}
+bool GrConstColorProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrConstColorProcessor& that = other.cast<GrConstColorProcessor>();
+    (void)that;
+    if (color != that.color) return false;
+    if (mode != that.mode) return false;
+    return true;
+}
+GrConstColorProcessor::GrConstColorProcessor(const GrConstColorProcessor& src)
+        : INHERITED(kGrConstColorProcessor_ClassID, src.optimizationFlags())
+        , color(src.color)
+        , mode(src.mode) {}
+std::unique_ptr<GrFragmentProcessor> GrConstColorProcessor::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrConstColorProcessor(*this));
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConstColorProcessor);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrConstColorProcessor::TestCreate(GrProcessorTestData* d) {
+    SkPMColor4f color;
+    int colorPicker = d->fRandom->nextULessThan(3);
+    switch (colorPicker) {
+        case 0: {
+            uint32_t a = d->fRandom->nextULessThan(0x100);
+            uint32_t r = d->fRandom->nextULessThan(a + 1);
+            uint32_t g = d->fRandom->nextULessThan(a + 1);
+            uint32_t b = d->fRandom->nextULessThan(a + 1);
+            color = SkPMColor4f::FromBytes_RGBA(GrColorPackRGBA(r, g, b, a));
+            break;
+        }
+        case 1:
+            color = SK_PMColor4fTRANSPARENT;
+            break;
+        case 2:
+            uint32_t c = d->fRandom->nextULessThan(0x100);
+            color = SkPMColor4f::FromBytes_RGBA(c | (c << 8) | (c << 16) | (c << 24));
+            break;
+    }
+    InputMode mode = static_cast<InputMode>(d->fRandom->nextULessThan(kInputModeCnt));
+    return GrConstColorProcessor::Make(color, mode);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrConstColorProcessor.h b/src/gpu/effects/generated/GrConstColorProcessor.h
new file mode 100644
index 0000000..9959cf5
--- /dev/null
+++ b/src/gpu/effects/generated/GrConstColorProcessor.h
@@ -0,0 +1,65 @@
+/*
+ * 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 GrConstColorProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrConstColorProcessor_DEFINED
+#define GrConstColorProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrConstColorProcessor : public GrFragmentProcessor {
+public:
+    enum class InputMode { kIgnore = 0, kLast = 2, kModulateA = 2, kModulateRGBA = 1 };
+
+    static const int kInputModeCnt = (int)InputMode::kLast + 1;
+
+    static OptimizationFlags OptFlags(const SkPMColor4f& color, InputMode mode) {
+        OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag;
+        if (mode != InputMode::kIgnore) {
+            flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
+        }
+        if (color.isOpaque()) {
+            flags |= kPreservesOpaqueInput_OptimizationFlag;
+        }
+        return flags;
+    }
+
+    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+        switch (mode) {
+            case InputMode::kIgnore:
+                return color;
+            case InputMode::kModulateA:
+                return color * input.fA;
+            case InputMode::kModulateRGBA:
+                return color * input;
+        }
+        SK_ABORT("Unexpected mode");
+        return SK_PMColor4fTRANSPARENT;
+    }
+    static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f color, InputMode mode) {
+        return std::unique_ptr<GrFragmentProcessor>(new GrConstColorProcessor(color, mode));
+    }
+    GrConstColorProcessor(const GrConstColorProcessor& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "ConstColorProcessor"; }
+    SkPMColor4f color;
+    InputMode mode;
+
+private:
+    GrConstColorProcessor(SkPMColor4f color, InputMode mode)
+            : INHERITED(kGrConstColorProcessor_ClassID, (OptimizationFlags)OptFlags(color, mode))
+            , color(color)
+            , mode(mode) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrEllipseEffect.cpp b/src/gpu/effects/generated/GrEllipseEffect.cpp
new file mode 100644
index 0000000..42998d0
--- /dev/null
+++ b/src/gpu/effects/generated/GrEllipseEffect.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2017 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 GrEllipseEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrEllipseEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLEllipseEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLEllipseEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrEllipseEffect& _outer = args.fFp.cast<GrEllipseEffect>();
+        (void)_outer;
+        auto edgeType = _outer.edgeType;
+        (void)edgeType;
+        auto center = _outer.center;
+        (void)center;
+        auto radii = _outer.radii;
+        (void)radii;
+        prevRadii = float2(-1.0);
+        medPrecision = !sk_Caps.floatIs32Bits;
+        ellipseVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
+                                                      "ellipse");
+        if (medPrecision) {
+            scaleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat2_GrSLType,
+                                                        "scale");
+        }
+        fragBuilder->codeAppendf(
+                "float2 prevCenter;\nfloat2 prevRadii = float2(%f, %f);\nbool medPrecision = "
+                "%s;\nfloat2 d = sk_FragCoord.xy - %s.xy;\n@if (medPrecision) {\n    d *= "
+                "%s.y;\n}\nfloat2 Z = d * %s.zw;\nfloat implicit = dot(Z, d) - 1.0;\nfloat "
+                "grad_dot = 4.0 * dot(Z, Z);\n@if (medPrecision) {\n    grad_dot = max(grad_dot, "
+                "6.1036000000000003e-05);\n} else {\n    grad_dot = max(grad_dot, "
+                "1.1755e-38);\n}\nfloat approx_dist = implicit * inversesqrt(grad_dot);\n@if "
+                "(medPrecision) {\n    approx_dist *= %s.x;\n}\nhalf alpha;\n@switch ",
+                prevRadii.fX, prevRadii.fY, (medPrecision ? "true" : "false"),
+                args.fUniformHandler->getUniformCStr(ellipseVar),
+                scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)",
+                args.fUniformHandler->getUniformCStr(ellipseVar),
+                scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)");
+        fragBuilder->codeAppendf(
+                "(%d) {\n    case 0:\n        alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n        "
+                "break;\n    case 1:\n        alpha = clamp(0.5 - half(approx_dist), 0.0, 1.0);\n  "
+                "      break;\n    case 2:\n        alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n       "
+                " break;\n    case 3:\n        alpha = clamp(0.5 + half(approx_dist), 0.0, 1.0);\n "
+                "       break;\n    default:\n        discard;\n}\n%s = %s * alpha;\n",
+                (int)_outer.edgeType, args.fOutputColor, args.fInputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrEllipseEffect& _outer = _proc.cast<GrEllipseEffect>();
+        auto edgeType = _outer.edgeType;
+        (void)edgeType;
+        auto center = _outer.center;
+        (void)center;
+        auto radii = _outer.radii;
+        (void)radii;
+        UniformHandle& ellipse = ellipseVar;
+        (void)ellipse;
+        UniformHandle& scale = scaleVar;
+        (void)scale;
+
+        if (radii != prevRadii || center != prevCenter) {
+            float invRXSqd;
+            float invRYSqd;
+            // If we're using a scale factor to work around precision issues, choose the larger
+            // radius as the scale factor. The inv radii need to be pre-adjusted by the scale
+            // factor.
+            if (scale.isValid()) {
+                if (radii.fX > radii.fY) {
+                    invRXSqd = 1.f;
+                    invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
+                    pdman.set2f(scale, radii.fX, 1.f / radii.fX);
+                } else {
+                    invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
+                    invRYSqd = 1.f;
+                    pdman.set2f(scale, radii.fY, 1.f / radii.fY);
+                }
+            } else {
+                invRXSqd = 1.f / (radii.fX * radii.fX);
+                invRYSqd = 1.f / (radii.fY * radii.fY);
+            }
+            pdman.set4f(ellipse, center.fX, center.fY, invRXSqd, invRYSqd);
+            prevCenter = center;
+            prevRadii = radii;
+        }
+    }
+    SkPoint prevCenter = float2(0);
+    SkPoint prevRadii = float2(0);
+    bool medPrecision = false;
+    UniformHandle ellipseVar;
+    UniformHandle scaleVar;
+};
+GrGLSLFragmentProcessor* GrEllipseEffect::onCreateGLSLInstance() const {
+    return new GrGLSLEllipseEffect();
+}
+void GrEllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                            GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)edgeType);
+}
+bool GrEllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrEllipseEffect& that = other.cast<GrEllipseEffect>();
+    (void)that;
+    if (edgeType != that.edgeType) return false;
+    if (center != that.center) return false;
+    if (radii != that.radii) return false;
+    return true;
+}
+GrEllipseEffect::GrEllipseEffect(const GrEllipseEffect& src)
+        : INHERITED(kGrEllipseEffect_ClassID, src.optimizationFlags())
+        , edgeType(src.edgeType)
+        , center(src.center)
+        , radii(src.radii) {}
+std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(*this));
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrEllipseEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::TestCreate(GrProcessorTestData* testData) {
+    SkPoint center;
+    center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
+    center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
+    SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f);
+    SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f);
+    GrClipEdgeType et;
+    do {
+        et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
+    } while (GrClipEdgeType::kHairlineAA == et);
+    return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry),
+                                 *testData->caps()->shaderCaps());
+}
+#endif
diff --git a/src/gpu/effects/generated/GrEllipseEffect.h b/src/gpu/effects/generated/GrEllipseEffect.h
new file mode 100644
index 0000000..c2a76d8
--- /dev/null
+++ b/src/gpu/effects/generated/GrEllipseEffect.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 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 GrEllipseEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrEllipseEffect_DEFINED
+#define GrEllipseEffect_DEFINED
+#include "SkTypes.h"
+
+#include "GrShaderCaps.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrEllipseEffect : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center,
+                                                     SkPoint radii, const GrShaderCaps& caps) {
+        // Small radii produce bad results on devices without full float.
+        if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) {
+            return nullptr;
+        }
+        // Very narrow ellipses produce bad results on devices without full float
+        if (!caps.floatIs32Bits() && (radii.fX > 255 * radii.fY || radii.fY > 255 * radii.fX)) {
+            return nullptr;
+        }
+        // Very large ellipses produce bad results on devices without full float
+        if (!caps.floatIs32Bits() && (radii.fX > 16384 || radii.fY > 16384)) {
+            return nullptr;
+        }
+        return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii));
+    }
+    GrEllipseEffect(const GrEllipseEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "EllipseEffect"; }
+    GrClipEdgeType edgeType;
+    SkPoint center;
+    SkPoint radii;
+
+private:
+    GrEllipseEffect(GrClipEdgeType edgeType, SkPoint center, SkPoint radii)
+            : INHERITED(kGrEllipseEffect_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , edgeType(edgeType)
+            , center(center)
+            , radii(radii) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp b/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp
new file mode 100644
index 0000000..d0b1e1c
--- /dev/null
+++ b/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 GrLumaColorFilterEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrLumaColorFilterEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLLumaColorFilterEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLLumaColorFilterEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrLumaColorFilterEffect& _outer = args.fFp.cast<GrLumaColorFilterEffect>();
+        (void)_outer;
+        fragBuilder->codeAppendf(
+                "\nhalf luma = clamp(dot(half3(0.21260000000000001, 0.71519999999999995, 0.0722), "
+                "%s.xyz), 0.0, 1.0);\n%s = half4(0.0, 0.0, 0.0, luma);\n",
+                args.fInputColor, args.fOutputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {}
+};
+GrGLSLFragmentProcessor* GrLumaColorFilterEffect::onCreateGLSLInstance() const {
+    return new GrGLSLLumaColorFilterEffect();
+}
+void GrLumaColorFilterEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                    GrProcessorKeyBuilder* b) const {}
+bool GrLumaColorFilterEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrLumaColorFilterEffect& that = other.cast<GrLumaColorFilterEffect>();
+    (void)that;
+    return true;
+}
+GrLumaColorFilterEffect::GrLumaColorFilterEffect(const GrLumaColorFilterEffect& src)
+        : INHERITED(kGrLumaColorFilterEffect_ClassID, src.optimizationFlags()) {}
+std::unique_ptr<GrFragmentProcessor> GrLumaColorFilterEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrLumaColorFilterEffect(*this));
+}
diff --git a/src/gpu/effects/generated/GrLumaColorFilterEffect.h b/src/gpu/effects/generated/GrLumaColorFilterEffect.h
new file mode 100644
index 0000000..c93f6a3
--- /dev/null
+++ b/src/gpu/effects/generated/GrLumaColorFilterEffect.h
@@ -0,0 +1,41 @@
+/*
+ * 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 GrLumaColorFilterEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrLumaColorFilterEffect_DEFINED
+#define GrLumaColorFilterEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrLumaColorFilterEffect : public GrFragmentProcessor {
+public:
+#include "SkColorData.h"
+
+    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+        float luma = SK_ITU_BT709_LUM_COEFF_R * input.fR + SK_ITU_BT709_LUM_COEFF_G * input.fG +
+                     SK_ITU_BT709_LUM_COEFF_B * input.fB;
+        return {0, 0, 0, SkTPin(luma, 0.0f, 1.0f)};
+    }
+    static std::unique_ptr<GrFragmentProcessor> Make() {
+        return std::unique_ptr<GrFragmentProcessor>(new GrLumaColorFilterEffect());
+    }
+    GrLumaColorFilterEffect(const GrLumaColorFilterEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "LumaColorFilterEffect"; }
+
+private:
+    GrLumaColorFilterEffect()
+            : INHERITED(kGrLumaColorFilterEffect_ClassID, kNone_OptimizationFlags) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrMagnifierEffect.cpp b/src/gpu/effects/generated/GrMagnifierEffect.cpp
new file mode 100644
index 0000000..3e34da7
--- /dev/null
+++ b/src/gpu/effects/generated/GrMagnifierEffect.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 GrMagnifierEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrMagnifierEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLMagnifierEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLMagnifierEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrMagnifierEffect& _outer = args.fFp.cast<GrMagnifierEffect>();
+        (void)_outer;
+        auto bounds = _outer.bounds;
+        (void)bounds;
+        auto srcRect = _outer.srcRect;
+        (void)srcRect;
+        auto xInvZoom = _outer.xInvZoom;
+        (void)xInvZoom;
+        auto yInvZoom = _outer.yInvZoom;
+        (void)yInvZoom;
+        auto xInvInset = _outer.xInvInset;
+        (void)xInvInset;
+        auto yInvInset = _outer.yInvInset;
+        (void)yInvInset;
+        boundsUniformVar = args.fUniformHandler->addUniform(
+                kFragment_GrShaderFlag, kFloat4_GrSLType, "boundsUniform");
+        xInvZoomVar = args.fUniformHandler->addUniform(
+                kFragment_GrShaderFlag, kFloat_GrSLType, "xInvZoom");
+        yInvZoomVar = args.fUniformHandler->addUniform(
+                kFragment_GrShaderFlag, kFloat_GrSLType, "yInvZoom");
+        xInvInsetVar = args.fUniformHandler->addUniform(
+                kFragment_GrShaderFlag, kFloat_GrSLType, "xInvInset");
+        yInvInsetVar = args.fUniformHandler->addUniform(
+                kFragment_GrShaderFlag, kFloat_GrSLType, "yInvInset");
+        offsetVar =
+                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "offset");
+        SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
+        fragBuilder->codeAppendf(
+                "float2 coord = %s;\nfloat2 zoom_coord = float2(%s) + coord * float2(%s, "
+                "%s);\nfloat2 delta = (coord - %s.xy) * %s.zw;\ndelta = min(delta, "
+                "float2(half2(1.0, 1.0)) - delta);\ndelta *= float2(%s, %s);\nfloat weight = "
+                "0.0;\nif (delta.x < 2.0 && delta.y < 2.0) {\n    delta = float2(half2(2.0, 2.0)) "
+                "- delta;\n    float dist = length(delta);\n    dist = max(2.0 - dist, 0.0);\n    "
+                "weight = min(dist * dist, 1.0);\n} else {\n    float2 delta_squared = delta * "
+                "delta;\n    weight = min(min(delta_squared.x, delta_square",
+                sk_TransformedCoords2D_0.c_str(),
+                args.fUniformHandler->getUniformCStr(offsetVar),
+                args.fUniformHandler->getUniformCStr(xInvZoomVar),
+                args.fUniformHandler->getUniformCStr(yInvZoomVar),
+                args.fUniformHandler->getUniformCStr(boundsUniformVar),
+                args.fUniformHandler->getUniformCStr(boundsUniformVar),
+                args.fUniformHandler->getUniformCStr(xInvInsetVar),
+                args.fUniformHandler->getUniformCStr(yInvInsetVar));
+        fragBuilder->codeAppendf(
+                "d.y), 1.0);\n}\n%s = texture(%s, mix(coord, zoom_coord, weight)).%s;\n",
+                args.fOutputColor,
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrMagnifierEffect& _outer = _proc.cast<GrMagnifierEffect>();
+        {
+            pdman.set1f(xInvZoomVar, (_outer.xInvZoom));
+            pdman.set1f(yInvZoomVar, (_outer.yInvZoom));
+            pdman.set1f(xInvInsetVar, (_outer.xInvInset));
+            pdman.set1f(yInvInsetVar, (_outer.yInvInset));
+        }
+        GrSurfaceProxy& srcProxy = *_outer.textureSampler(0).proxy();
+        GrTexture& src = *srcProxy.peekTexture();
+        (void)src;
+        auto bounds = _outer.bounds;
+        (void)bounds;
+        UniformHandle& boundsUniform = boundsUniformVar;
+        (void)boundsUniform;
+        auto srcRect = _outer.srcRect;
+        (void)srcRect;
+        UniformHandle& xInvZoom = xInvZoomVar;
+        (void)xInvZoom;
+        UniformHandle& yInvZoom = yInvZoomVar;
+        (void)yInvZoom;
+        UniformHandle& xInvInset = xInvInsetVar;
+        (void)xInvInset;
+        UniformHandle& yInvInset = yInvInsetVar;
+        (void)yInvInset;
+        UniformHandle& offset = offsetVar;
+        (void)offset;
+
+        SkScalar invW = 1.0f / src.width();
+        SkScalar invH = 1.0f / src.height();
+
+        {
+            SkScalar y = srcRect.y() * invH;
+            if (srcProxy.origin() != kTopLeft_GrSurfaceOrigin) {
+                y = 1.0f - (srcRect.height() / bounds.height()) - y;
+            }
+
+            pdman.set2f(offset, srcRect.x() * invW, y);
+        }
+
+        {
+            SkScalar y = bounds.y() * invH;
+            if (srcProxy.origin() != kTopLeft_GrSurfaceOrigin) {
+                y = 1.0f - bounds.height() * invH;
+            }
+
+            pdman.set4f(boundsUniform,
+                        bounds.x() * invW,
+                        y,
+                        SkIntToScalar(src.width()) / bounds.width(),
+                        SkIntToScalar(src.height()) / bounds.height());
+        }
+    }
+    UniformHandle boundsUniformVar;
+    UniformHandle offsetVar;
+    UniformHandle xInvZoomVar;
+    UniformHandle yInvZoomVar;
+    UniformHandle xInvInsetVar;
+    UniformHandle yInvInsetVar;
+};
+GrGLSLFragmentProcessor* GrMagnifierEffect::onCreateGLSLInstance() const {
+    return new GrGLSLMagnifierEffect();
+}
+void GrMagnifierEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                              GrProcessorKeyBuilder* b) const {}
+bool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrMagnifierEffect& that = other.cast<GrMagnifierEffect>();
+    (void)that;
+    if (src != that.src) return false;
+    if (bounds != that.bounds) return false;
+    if (srcRect != that.srcRect) return false;
+    if (xInvZoom != that.xInvZoom) return false;
+    if (yInvZoom != that.yInvZoom) return false;
+    if (xInvInset != that.xInvInset) return false;
+    if (yInvInset != that.yInvInset) return false;
+    return true;
+}
+GrMagnifierEffect::GrMagnifierEffect(const GrMagnifierEffect& src)
+        : INHERITED(kGrMagnifierEffect_ClassID, src.optimizationFlags())
+        , srcCoordTransform(src.srcCoordTransform)
+        , src(src.src)
+        , bounds(src.bounds)
+        , srcRect(src.srcRect)
+        , xInvZoom(src.xInvZoom)
+        , yInvZoom(src.yInvZoom)
+        , xInvInset(src.xInvInset)
+        , yInvInset(src.yInvInset) {
+    this->setTextureSamplerCnt(1);
+    this->addCoordTransform(&srcCoordTransform);
+}
+std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrMagnifierEffect(*this));
+}
+const GrFragmentProcessor::TextureSampler& GrMagnifierEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, src);
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMagnifierEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::TestCreate(GrProcessorTestData* d) {
+    sk_sp<GrTextureProxy> proxy = d->textureProxy(0);
+    const int kMaxWidth = 200;
+    const int kMaxHeight = 200;
+    const SkScalar kMaxInset = 20.0f;
+    uint32_t width = d->fRandom->nextULessThan(kMaxWidth);
+    uint32_t height = d->fRandom->nextULessThan(kMaxHeight);
+    SkScalar inset = d->fRandom->nextRangeScalar(1.0f, kMaxInset);
+
+    SkIRect bounds = SkIRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight));
+    SkRect srcRect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
+
+    auto effect = GrMagnifierEffect::Make(std::move(proxy),
+                                          bounds,
+                                          srcRect,
+                                          srcRect.width() / bounds.width(),
+                                          srcRect.height() / bounds.height(),
+                                          bounds.width() / inset,
+                                          bounds.height() / inset);
+    SkASSERT(effect);
+    return effect;
+}
+#endif
diff --git a/src/gpu/effects/generated/GrMagnifierEffect.h b/src/gpu/effects/generated/GrMagnifierEffect.h
new file mode 100644
index 0000000..c1bf22b
--- /dev/null
+++ b/src/gpu/effects/generated/GrMagnifierEffect.h
@@ -0,0 +1,58 @@
+/*
+ * 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 GrMagnifierEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrMagnifierEffect_DEFINED
+#define GrMagnifierEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrMagnifierEffect : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> src, SkIRect bounds,
+                                                     SkRect srcRect, float xInvZoom, float yInvZoom,
+                                                     float xInvInset, float yInvInset) {
+        return std::unique_ptr<GrFragmentProcessor>(new GrMagnifierEffect(
+                src, bounds, srcRect, xInvZoom, yInvZoom, xInvInset, yInvInset));
+    }
+    GrMagnifierEffect(const GrMagnifierEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "MagnifierEffect"; }
+    GrCoordTransform srcCoordTransform;
+    TextureSampler src;
+    SkIRect bounds;
+    SkRect srcRect;
+    float xInvZoom;
+    float yInvZoom;
+    float xInvInset;
+    float yInvInset;
+
+private:
+    GrMagnifierEffect(sk_sp<GrTextureProxy> src, SkIRect bounds, SkRect srcRect, float xInvZoom,
+                      float yInvZoom, float xInvInset, float yInvInset)
+            : INHERITED(kGrMagnifierEffect_ClassID, kNone_OptimizationFlags)
+            , srcCoordTransform(SkMatrix::I(), src.get())
+            , src(std::move(src))
+            , bounds(bounds)
+            , srcRect(srcRect)
+            , xInvZoom(xInvZoom)
+            , yInvZoom(yInvZoom)
+            , xInvInset(xInvInset)
+            , yInvInset(yInvInset) {
+        this->setTextureSamplerCnt(1);
+        this->addCoordTransform(&srcCoordTransform);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrMixerEffect.cpp b/src/gpu/effects/generated/GrMixerEffect.cpp
new file mode 100644
index 0000000..98e9a47
--- /dev/null
+++ b/src/gpu/effects/generated/GrMixerEffect.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 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 GrMixerEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrMixerEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLMixerEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLMixerEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrMixerEffect& _outer = args.fFp.cast<GrMixerEffect>();
+        (void)_outer;
+        auto weight = _outer.weight;
+        (void)weight;
+        weightVar =
+                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "weight");
+        SkString _input0 = SkStringPrintf("%s", args.fInputColor);
+        SkString _child0("_child0");
+        this->emitChild(_outer.fp0_index, _input0.c_str(), &_child0, args);
+        fragBuilder->codeAppendf("half4 in0 = %s;", _child0.c_str());
+        SkString _input1 = SkStringPrintf("%s", args.fInputColor);
+        SkString _child1("_child1");
+        if (_outer.fp1_index >= 0) {
+            this->emitChild(_outer.fp1_index, _input1.c_str(), &_child1, args);
+        } else {
+            fragBuilder->codeAppendf("half4 %s;", _child1.c_str());
+        }
+        fragBuilder->codeAppendf("\nhalf4 in1 = %s ? %s : %s;\n%s = mix(in0, in1, %s);\n",
+                                 _outer.fp1_index >= 0 ? "true" : "false", _child1.c_str(),
+                                 args.fInputColor, args.fOutputColor,
+                                 args.fUniformHandler->getUniformCStr(weightVar));
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrMixerEffect& _outer = _proc.cast<GrMixerEffect>();
+        { pdman.set1f(weightVar, (_outer.weight)); }
+    }
+    UniformHandle weightVar;
+};
+GrGLSLFragmentProcessor* GrMixerEffect::onCreateGLSLInstance() const {
+    return new GrGLSLMixerEffect();
+}
+void GrMixerEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                          GrProcessorKeyBuilder* b) const {}
+bool GrMixerEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrMixerEffect& that = other.cast<GrMixerEffect>();
+    (void)that;
+    if (weight != that.weight) return false;
+    return true;
+}
+GrMixerEffect::GrMixerEffect(const GrMixerEffect& src)
+        : INHERITED(kGrMixerEffect_ClassID, src.optimizationFlags())
+        , fp0_index(src.fp0_index)
+        , fp1_index(src.fp1_index)
+        , weight(src.weight) {
+    this->registerChildProcessor(src.childProcessor(fp0_index).clone());
+    if (fp1_index >= 0) {
+        this->registerChildProcessor(src.childProcessor(fp1_index).clone());
+    }
+}
+std::unique_ptr<GrFragmentProcessor> GrMixerEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrMixerEffect(*this));
+}
diff --git a/src/gpu/effects/generated/GrMixerEffect.h b/src/gpu/effects/generated/GrMixerEffect.h
new file mode 100644
index 0000000..d318285
--- /dev/null
+++ b/src/gpu/effects/generated/GrMixerEffect.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019 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 GrMixerEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrMixerEffect_DEFINED
+#define GrMixerEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrMixerEffect : public GrFragmentProcessor {
+public:
+    static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
+                                      const std::unique_ptr<GrFragmentProcessor>& fp1) {
+        auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
+            auto flags = kNone_OptimizationFlags;
+
+            if (fp->compatibleWithCoverageAsAlpha()) {
+                flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
+            }
+
+            if (fp->preservesOpaqueInput()) {
+                flags |= kPreservesOpaqueInput_OptimizationFlag;
+            }
+
+            if (fp->hasConstantOutputForConstantInput()) {
+                flags |= kConstantOutputForConstantInput_OptimizationFlag;
+            }
+
+            return flags;
+        };
+
+        const auto fp0_flags = get_flags(fp0);
+
+        return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
+    }
+
+    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+        const auto c0 = ConstantOutputForConstantInput(this->childProcessor(0), input),
+                   c1 = (this->numChildProcessors() > 1)
+                                ? ConstantOutputForConstantInput(this->childProcessor(1), input)
+                                : input;
+        return {c0.fR + (c1.fR - c0.fR) * weight, c0.fG + (c1.fG - c0.fG) * weight,
+                c0.fB + (c1.fB - c0.fB) * weight, c0.fA + (c1.fA - c0.fA) * weight};
+    }
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp0,
+                                                     std::unique_ptr<GrFragmentProcessor>
+                                                             fp1,
+                                                     float weight) {
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrMixerEffect(std::move(fp0), std::move(fp1), weight));
+    }
+    GrMixerEffect(const GrMixerEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "MixerEffect"; }
+    int fp0_index = -1;
+    int fp1_index = -1;
+    float weight;
+
+private:
+    GrMixerEffect(std::unique_ptr<GrFragmentProcessor> fp0,
+                  std::unique_ptr<GrFragmentProcessor>
+                          fp1,
+                  float weight)
+            : INHERITED(kGrMixerEffect_ClassID, (OptimizationFlags)OptFlags(fp0, fp1))
+            , weight(weight) {
+        SkASSERT(fp0);
+        fp0_index = this->numChildProcessors();
+        this->registerChildProcessor(std::move(fp0));
+        if (fp1) {
+            fp1_index = this->numChildProcessors();
+            this->registerChildProcessor(std::move(fp1));
+        }
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp b/src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp
new file mode 100644
index 0000000..846a4f8
--- /dev/null
+++ b/src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 GrPremulInputFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrPremulInputFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLPremulInputFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLPremulInputFragmentProcessor() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrPremulInputFragmentProcessor& _outer =
+                args.fFp.cast<GrPremulInputFragmentProcessor>();
+        (void)_outer;
+        fragBuilder->codeAppendf("%s = %s;\n%s.xyz *= %s.w;\n", args.fOutputColor, args.fInputColor,
+                                 args.fOutputColor, args.fInputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {}
+};
+GrGLSLFragmentProcessor* GrPremulInputFragmentProcessor::onCreateGLSLInstance() const {
+    return new GrGLSLPremulInputFragmentProcessor();
+}
+void GrPremulInputFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                           GrProcessorKeyBuilder* b) const {}
+bool GrPremulInputFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrPremulInputFragmentProcessor& that = other.cast<GrPremulInputFragmentProcessor>();
+    (void)that;
+    return true;
+}
+GrPremulInputFragmentProcessor::GrPremulInputFragmentProcessor(
+        const GrPremulInputFragmentProcessor& src)
+        : INHERITED(kGrPremulInputFragmentProcessor_ClassID, src.optimizationFlags()) {}
+std::unique_ptr<GrFragmentProcessor> GrPremulInputFragmentProcessor::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrPremulInputFragmentProcessor(*this));
+}
diff --git a/src/gpu/effects/generated/GrPremulInputFragmentProcessor.h b/src/gpu/effects/generated/GrPremulInputFragmentProcessor.h
new file mode 100644
index 0000000..bfcfdb8
--- /dev/null
+++ b/src/gpu/effects/generated/GrPremulInputFragmentProcessor.h
@@ -0,0 +1,39 @@
+/*
+ * 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 GrPremulInputFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrPremulInputFragmentProcessor_DEFINED
+#define GrPremulInputFragmentProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrPremulInputFragmentProcessor : public GrFragmentProcessor {
+public:
+    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+        return SkColor4f{input.fR, input.fG, input.fB, input.fA}.premul();
+    }
+    static std::unique_ptr<GrFragmentProcessor> Make() {
+        return std::unique_ptr<GrFragmentProcessor>(new GrPremulInputFragmentProcessor());
+    }
+    GrPremulInputFragmentProcessor(const GrPremulInputFragmentProcessor& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "PremulInputFragmentProcessor"; }
+
+private:
+    GrPremulInputFragmentProcessor()
+            : INHERITED(kGrPremulInputFragmentProcessor_ClassID,
+                        (OptimizationFlags)kPreservesOpaqueInput_OptimizationFlag |
+                                kConstantOutputForConstantInput_OptimizationFlag) {}
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrRRectBlurEffect.cpp b/src/gpu/effects/generated/GrRRectBlurEffect.cpp
new file mode 100644
index 0000000..878678c
--- /dev/null
+++ b/src/gpu/effects/generated/GrRRectBlurEffect.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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 GrRRectBlurEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrRRectBlurEffect.h"
+
+std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrRecordingContext* context,
+                                                             float sigma,
+                                                             float xformedSigma,
+                                                             const SkRRect& srcRRect,
+                                                             const SkRRect& devRRect) {
+    SkASSERT(!SkRRectPriv::IsCircle(devRRect) &&
+             !devRRect.isRect());  // Should've been caught up-stream
+
+    // TODO: loosen this up
+    if (!SkRRectPriv::IsSimpleCircular(devRRect)) {
+        return nullptr;
+    }
+
+    // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
+    // sufficiently small relative to both the size of the corner radius and the
+    // width (and height) of the rrect.
+    SkRRect rrectToDraw;
+    SkISize size;
+    SkScalar ignored[kSkBlurRRectMaxDivisions];
+    int ignoredSize;
+    uint32_t ignored32;
+
+    bool ninePatchable = SkComputeBlurredRRectParams(
+            srcRRect, devRRect, SkRect::MakeEmpty(), sigma, xformedSigma, &rrectToDraw, &size,
+            ignored, ignored, ignored, ignored, &ignoredSize, &ignoredSize, &ignored32);
+    if (!ninePatchable) {
+        return nullptr;
+    }
+
+    sk_sp<GrTextureProxy> mask(
+            find_or_create_rrect_blur_mask(context, rrectToDraw, size, xformedSigma));
+    if (!mask) {
+        return nullptr;
+    }
+
+    return std::unique_ptr<GrFragmentProcessor>(
+            new GrRRectBlurEffect(xformedSigma, devRRect.getBounds(),
+                                  SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(mask)));
+}
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLRRectBlurEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLRRectBlurEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrRRectBlurEffect& _outer = args.fFp.cast<GrRRectBlurEffect>();
+        (void)_outer;
+        auto sigma = _outer.sigma;
+        (void)sigma;
+        auto rect = _outer.rect;
+        (void)rect;
+        auto cornerRadius = _outer.cornerRadius;
+        (void)cornerRadius;
+        cornerRadiusVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                           "cornerRadius");
+        proxyRectVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
+                                                        "proxyRect");
+        blurRadiusVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                         "blurRadius");
+        fragBuilder->codeAppendf(
+                "\nhalf2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy);\nhalf threshold = %s "
+                "+ 2.0 * %s;\nhalf2 middle = half2((%s.zw - %s.xy) - float(2.0 * threshold));\nif "
+                "(translatedFragPos.x >= threshold && translatedFragPos.x < middle.x + threshold) "
+                "{\n    translatedFragPos.x = threshold;\n} else if (translatedFragPos.x >= "
+                "middle.x + threshold) {\n    translatedFragPos.x -= middle.x - 1.0;\n}\nif "
+                "(translatedFragPos.y > threshold && translatedFragPos.y < middle.y + threshold) "
+                "{\n    translatedFragPos.y = threshold;",
+                args.fUniformHandler->getUniformCStr(proxyRectVar),
+                args.fUniformHandler->getUniformCStr(cornerRadiusVar),
+                args.fUniformHandler->getUniformCStr(blurRadiusVar),
+                args.fUniformHandler->getUniformCStr(proxyRectVar),
+                args.fUniformHandler->getUniformCStr(proxyRectVar));
+        fragBuilder->codeAppendf(
+                "\n} else if (translatedFragPos.y >= middle.y + threshold) {\n    "
+                "translatedFragPos.y -= middle.y - 1.0;\n}\nhalf2 proxyDims = half2(2.0 * "
+                "threshold + 1.0);\nhalf2 texCoord = translatedFragPos / proxyDims;\n%s = %s * "
+                "texture(%s, float2(texCoord)).%s;\n",
+                args.fOutputColor, args.fInputColor,
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrRRectBlurEffect& _outer = _proc.cast<GrRRectBlurEffect>();
+        { pdman.set1f(cornerRadiusVar, (_outer.cornerRadius)); }
+        auto sigma = _outer.sigma;
+        (void)sigma;
+        auto rect = _outer.rect;
+        (void)rect;
+        UniformHandle& cornerRadius = cornerRadiusVar;
+        (void)cornerRadius;
+        GrSurfaceProxy& ninePatchSamplerProxy = *_outer.textureSampler(0).proxy();
+        GrTexture& ninePatchSampler = *ninePatchSamplerProxy.peekTexture();
+        (void)ninePatchSampler;
+        UniformHandle& proxyRect = proxyRectVar;
+        (void)proxyRect;
+        UniformHandle& blurRadius = blurRadiusVar;
+        (void)blurRadius;
+
+        float blurRadiusValue = 3.f * SkScalarCeilToScalar(sigma - 1 / 6.0f);
+        pdman.set1f(blurRadius, blurRadiusValue);
+
+        SkRect outset = rect;
+        outset.outset(blurRadiusValue, blurRadiusValue);
+        pdman.set4f(proxyRect, outset.fLeft, outset.fTop, outset.fRight, outset.fBottom);
+    }
+    UniformHandle proxyRectVar;
+    UniformHandle blurRadiusVar;
+    UniformHandle cornerRadiusVar;
+};
+GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
+    return new GrGLSLRRectBlurEffect();
+}
+void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                              GrProcessorKeyBuilder* b) const {}
+bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrRRectBlurEffect& that = other.cast<GrRRectBlurEffect>();
+    (void)that;
+    if (sigma != that.sigma) return false;
+    if (rect != that.rect) return false;
+    if (cornerRadius != that.cornerRadius) return false;
+    if (ninePatchSampler != that.ninePatchSampler) return false;
+    return true;
+}
+GrRRectBlurEffect::GrRRectBlurEffect(const GrRRectBlurEffect& src)
+        : INHERITED(kGrRRectBlurEffect_ClassID, src.optimizationFlags())
+        , sigma(src.sigma)
+        , rect(src.rect)
+        , cornerRadius(src.cornerRadius)
+        , ninePatchSampler(src.ninePatchSampler) {
+    this->setTextureSamplerCnt(1);
+}
+std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrRRectBlurEffect(*this));
+}
+const GrFragmentProcessor::TextureSampler& GrRRectBlurEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, ninePatchSampler);
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
+    SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
+    SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
+    SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
+    SkScalar sigma = d->fRandom->nextRangeF(1.f, 10.f);
+    SkRRect rrect;
+    rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
+    return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrRRectBlurEffect.h b/src/gpu/effects/generated/GrRRectBlurEffect.h
new file mode 100644
index 0000000..7c7da9a
--- /dev/null
+++ b/src/gpu/effects/generated/GrRRectBlurEffect.h
@@ -0,0 +1,135 @@
+/*
+ * 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 GrRRectBlurEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrRRectBlurEffect_DEFINED
+#define GrRRectBlurEffect_DEFINED
+#include "SkTypes.h"
+
+#include "GrCaps.h"
+#include "GrClip.h"
+#include "GrContext.h"
+#include "GrPaint.h"
+#include "GrProxyProvider.h"
+#include "GrRecordingContext.h"
+#include "GrRecordingContextPriv.h"
+#include "GrRenderTargetContext.h"
+#include "GrStyle.h"
+#include "SkBlurMaskFilter.h"
+#include "SkBlurPriv.h"
+#include "SkGpuBlurUtils.h"
+#include "SkRRectPriv.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrRRectBlurEffect : public GrFragmentProcessor {
+public:
+    static sk_sp<GrTextureProxy> find_or_create_rrect_blur_mask(GrRecordingContext* context,
+                                                                const SkRRect& rrectToDraw,
+                                                                const SkISize& size,
+                                                                float xformedSigma) {
+        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+        GrUniqueKey key;
+        GrUniqueKey::Builder builder(&key, kDomain, 9, "RoundRect Blur Mask");
+        builder[0] = SkScalarCeilToInt(xformedSigma - 1 / 6.0f);
+
+        int index = 1;
+        for (auto c : {SkRRect::kUpperLeft_Corner, SkRRect::kUpperRight_Corner,
+                       SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner}) {
+            SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) &&
+                     SkScalarIsInt(rrectToDraw.radii(c).fY));
+            builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX);
+            builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY);
+        }
+        builder.finish();
+
+        GrProxyProvider* proxyProvider = context->priv().proxyProvider();
+
+        sk_sp<GrTextureProxy> mask(
+                proxyProvider->findOrCreateProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin));
+        if (!mask) {
+            GrBackendFormat format =
+                    context->priv().caps()->getBackendFormatFromColorType(kAlpha_8_SkColorType);
+            // TODO: this could be approx but the texture coords will need to be updated
+            sk_sp<GrRenderTargetContext> rtc(
+                    context->priv().makeDeferredRenderTargetContextWithFallback(
+                            format, SkBackingFit::kExact, size.fWidth, size.fHeight,
+                            kAlpha_8_GrPixelConfig, nullptr));
+            if (!rtc) {
+                return nullptr;
+            }
+
+            GrPaint paint;
+
+            rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
+                       GrRenderTargetContext::CanClearFullscreen::kYes);
+            rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw,
+                           GrStyle::SimpleFill());
+
+            sk_sp<GrTextureProxy> srcProxy(rtc->asTextureProxyRef());
+            if (!srcProxy) {
+                return nullptr;
+            }
+            sk_sp<GrRenderTargetContext> rtc2(
+                    SkGpuBlurUtils::GaussianBlur(context,
+                                                 std::move(srcProxy),
+                                                 nullptr,
+                                                 SkIRect::MakeWH(size.fWidth, size.fHeight),
+                                                 SkIRect::EmptyIRect(),
+                                                 xformedSigma,
+                                                 xformedSigma,
+                                                 GrTextureDomain::kIgnore_Mode,
+                                                 kPremul_SkAlphaType,
+                                                 SkBackingFit::kExact));
+            if (!rtc2) {
+                return nullptr;
+            }
+
+            mask = rtc2->asTextureProxyRef();
+            if (!mask) {
+                return nullptr;
+            }
+            SkASSERT(mask->origin() == kBottomLeft_GrSurfaceOrigin);
+            proxyProvider->assignUniqueKeyToProxy(key, mask.get());
+        }
+
+        return mask;
+    }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context,
+                                                     float sigma,
+                                                     float xformedSigma,
+                                                     const SkRRect& srcRRect,
+                                                     const SkRRect& devRRect);
+    GrRRectBlurEffect(const GrRRectBlurEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "RRectBlurEffect"; }
+    float sigma;
+    SkRect rect;
+    float cornerRadius;
+    TextureSampler ninePatchSampler;
+
+private:
+    GrRRectBlurEffect(float sigma, SkRect rect, float cornerRadius,
+                      sk_sp<GrTextureProxy> ninePatchSampler)
+            : INHERITED(kGrRRectBlurEffect_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , sigma(sigma)
+            , rect(rect)
+            , cornerRadius(cornerRadius)
+            , ninePatchSampler(std::move(ninePatchSampler)) {
+        this->setTextureSamplerCnt(1);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrRectBlurEffect.cpp b/src/gpu/effects/generated/GrRectBlurEffect.cpp
new file mode 100644
index 0000000..b03c8f9
--- /dev/null
+++ b/src/gpu/effects/generated/GrRectBlurEffect.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 GrRectBlurEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrRectBlurEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLRectBlurEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLRectBlurEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrRectBlurEffect& _outer = args.fFp.cast<GrRectBlurEffect>();
+        (void)_outer;
+        auto rect = _outer.rect;
+        (void)rect;
+        auto sigma = _outer.sigma;
+        (void)sigma;
+        highPrecision = ((((abs(rect.left()) > 16000.0 || abs(rect.top()) > 16000.0) ||
+                           abs(rect.right()) > 16000.0) ||
+                          abs(rect.bottom()) > 16000.0) ||
+                         abs(rect.right() - rect.left()) > 16000.0) ||
+                        abs(rect.bottom() - rect.top()) > 16000.0;
+        rectVar =
+                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, "rect");
+        if (!highPrecision) {
+            proxyRectHalfVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
+                                                                kHalf4_GrSLType, "proxyRectHalf");
+        }
+        if (highPrecision) {
+            proxyRectFloatVar = args.fUniformHandler->addUniform(
+                    kFragment_GrShaderFlag, kFloat4_GrSLType, "proxyRectFloat");
+        }
+        profileSizeVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                          "profileSize");
+        fragBuilder->codeAppendf(
+                "/* key */ bool highPrecision = %s;\n@if (highPrecision) {\n    float2 "
+                "translatedPos = sk_FragCoord.xy - %s.xy;\n    float width = %s.z - %s.x;\n    "
+                "float height = %s.w - %s.y;\n    float2 smallDims = float2(width - float(%s), "
+                "height - float(%s));\n    float center = float(2.0 * floor(%s / 2.0 + 0.25) - "
+                "1.0);\n    float2 wh = smallDims - float2(center, center);\n    half hcoord = "
+                "half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n    half "
+                "hlookup = texture(%s, float2(float(hcoord), 0.5)).",
+                (highPrecision ? "true" : "false"), args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str());
+        fragBuilder->codeAppendf(
+                "%s.w;\n    half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y) "
+                "/ float(%s));\n    half vlookup = texture(%s, float2(float(vcoord), 0.5)).%s.w;\n "
+                "   %s = (%s * hlookup) * vlookup;\n} else {\n    half2 translatedPos = "
+                "half2(sk_FragCoord.xy - %s.xy);\n    half width = half(%s.z - %s.x);\n    half "
+                "height = half(%s.w - %s.y);\n    half2 smallDims = half2(width - %s, height - "
+                "%s);\n    half center = 2.0 * floor(%s / 2.0 + 0.25) - 1.0;\n    half2 wh = "
+                "smallDims - half2(center, center);\n    half ",
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fOutputColor, args.fInputColor, args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(rectVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                args.fUniformHandler->getUniformCStr(profileSizeVar));
+        fragBuilder->codeAppendf(
+                "hcoord = (abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / %s;\n    half "
+                "hlookup = texture(%s, float2(float(hcoord), 0.5)).%s.w;\n    half vcoord = "
+                "(abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y) / %s;\n    half vlookup = "
+                "texture(%s, float2(float(vcoord), 0.5)).%s.w;\n    %s = (%s * hlookup) * "
+                "vlookup;\n}\n",
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fUniformHandler->getUniformCStr(profileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fOutputColor, args.fInputColor);
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrRectBlurEffect& _outer = _proc.cast<GrRectBlurEffect>();
+        { pdman.set4fv(rectVar, 1, reinterpret_cast<const float*>(&(_outer.rect))); }
+        UniformHandle& rect = rectVar;
+        (void)rect;
+        auto sigma = _outer.sigma;
+        (void)sigma;
+        GrSurfaceProxy& blurProfileProxy = *_outer.textureSampler(0).proxy();
+        GrTexture& blurProfile = *blurProfileProxy.peekTexture();
+        (void)blurProfile;
+        UniformHandle& proxyRectHalf = proxyRectHalfVar;
+        (void)proxyRectHalf;
+        UniformHandle& proxyRectFloat = proxyRectFloatVar;
+        (void)proxyRectFloat;
+        UniformHandle& profileSize = profileSizeVar;
+        (void)profileSize;
+
+        pdman.set1f(profileSize, SkScalarCeilToScalar(6 * sigma));
+    }
+    bool highPrecision = false;
+    UniformHandle proxyRectHalfVar;
+    UniformHandle proxyRectFloatVar;
+    UniformHandle profileSizeVar;
+    UniformHandle rectVar;
+};
+GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
+    return new GrGLSLRectBlurEffect();
+}
+void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                             GrProcessorKeyBuilder* b) const {}
+bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrRectBlurEffect& that = other.cast<GrRectBlurEffect>();
+    (void)that;
+    if (rect != that.rect) return false;
+    if (sigma != that.sigma) return false;
+    if (blurProfile != that.blurProfile) return false;
+    return true;
+}
+GrRectBlurEffect::GrRectBlurEffect(const GrRectBlurEffect& src)
+        : INHERITED(kGrRectBlurEffect_ClassID, src.optimizationFlags())
+        , rect(src.rect)
+        , sigma(src.sigma)
+        , blurProfile(src.blurProfile) {
+    this->setTextureSamplerCnt(1);
+}
+std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(*this));
+}
+const GrFragmentProcessor::TextureSampler& GrRectBlurEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, blurProfile);
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* data) {
+    float sigma = data->fRandom->nextRangeF(3, 8);
+    float width = data->fRandom->nextRangeF(200, 300);
+    float height = data->fRandom->nextRangeF(200, 300);
+    return GrRectBlurEffect::Make(data->proxyProvider(), *data->caps()->shaderCaps(),
+                                  SkRect::MakeWH(width, height), sigma);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrRectBlurEffect.h b/src/gpu/effects/generated/GrRectBlurEffect.h
new file mode 100644
index 0000000..6e09aae
--- /dev/null
+++ b/src/gpu/effects/generated/GrRectBlurEffect.h
@@ -0,0 +1,118 @@
+/*
+ * 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 GrRectBlurEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrRectBlurEffect_DEFINED
+#define GrRectBlurEffect_DEFINED
+#include "SkTypes.h"
+
+#include "GrProxyProvider.h"
+#include "GrShaderCaps.h"
+#include "SkBlurMask.h"
+#include "SkScalar.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrRectBlurEffect : public GrFragmentProcessor {
+public:
+    static sk_sp<GrTextureProxy> CreateBlurProfileTexture(GrProxyProvider* proxyProvider,
+                                                          float sigma) {
+        unsigned int profileSize = SkScalarCeilToInt(6 * sigma);
+
+        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+        GrUniqueKey key;
+        GrUniqueKey::Builder builder(&key, kDomain, 1, "Rect Blur Mask");
+        builder[0] = profileSize;
+        builder.finish();
+
+        sk_sp<GrTextureProxy> blurProfile(
+                proxyProvider->findOrCreateProxyByUniqueKey(key, kTopLeft_GrSurfaceOrigin));
+        if (!blurProfile) {
+            SkImageInfo ii = SkImageInfo::MakeA8(profileSize, 1);
+
+            SkBitmap bitmap;
+            if (!bitmap.tryAllocPixels(ii)) {
+                return nullptr;
+            }
+
+            SkBlurMask::ComputeBlurProfile(bitmap.getAddr8(0, 0), profileSize, sigma);
+            bitmap.setImmutable();
+
+            sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+            if (!image) {
+                return nullptr;
+            }
+
+            blurProfile =
+                    proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
+                                                      SkBudgeted::kYes, SkBackingFit::kExact);
+            if (!blurProfile) {
+                return nullptr;
+            }
+
+            SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
+            proxyProvider->assignUniqueKeyToProxy(key, blurProfile.get());
+        }
+
+        return blurProfile;
+    }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(GrProxyProvider* proxyProvider,
+                                                     const GrShaderCaps& caps, const SkRect& rect,
+                                                     float sigma) {
+        if (!caps.floatIs32Bits()) {
+            // We promote the rect uniform from half to float when it has large values for
+            // precision. If we don't have full float then fail.
+            if (SkScalarAbs(rect.fLeft) > 16000.f || SkScalarAbs(rect.fTop) > 16000.f ||
+                SkScalarAbs(rect.fRight) > 16000.f || SkScalarAbs(rect.fBottom) > 16000.f ||
+                SkScalarAbs(rect.width()) > 16000.f || SkScalarAbs(rect.height()) > 16000.f) {
+                return nullptr;
+            }
+        }
+        int doubleProfileSize = SkScalarCeilToInt(12 * sigma);
+
+        if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
+            // if the blur sigma is too large so the gaussian overlaps the whole
+            // rect in either direction, fall back to CPU path for now.
+            return nullptr;
+        }
+
+        sk_sp<GrTextureProxy> blurProfile(CreateBlurProfileTexture(proxyProvider, sigma));
+        if (!blurProfile) {
+            return nullptr;
+        }
+
+        return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(
+                rect, sigma, std::move(blurProfile),
+                GrSamplerState(GrSamplerState::WrapMode::kClamp, GrSamplerState::Filter::kBilerp)));
+    }
+    GrRectBlurEffect(const GrRectBlurEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "RectBlurEffect"; }
+    SkRect rect;
+    float sigma;
+    TextureSampler blurProfile;
+
+private:
+    GrRectBlurEffect(SkRect rect, float sigma, sk_sp<GrTextureProxy> blurProfile,
+                     GrSamplerState samplerParams)
+            : INHERITED(kGrRectBlurEffect_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , rect(rect)
+            , sigma(sigma)
+            , blurProfile(std::move(blurProfile), samplerParams) {
+        this->setTextureSamplerCnt(1);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/effects/generated/GrSimpleTextureEffect.cpp b/src/gpu/effects/generated/GrSimpleTextureEffect.cpp
new file mode 100644
index 0000000..8236ebc
--- /dev/null
+++ b/src/gpu/effects/generated/GrSimpleTextureEffect.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 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 GrSimpleTextureEffect.fp; do not modify.
+ **************************************************************************************************/
+#include "GrSimpleTextureEffect.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLSimpleTextureEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLSimpleTextureEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrSimpleTextureEffect& _outer = args.fFp.cast<GrSimpleTextureEffect>();
+        (void)_outer;
+        auto matrix = _outer.matrix;
+        (void)matrix;
+        SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
+        fragBuilder->codeAppendf(
+                "%s = %s * texture(%s, %s).%s;\n", args.fOutputColor, args.fInputColor,
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                sk_TransformedCoords2D_0.c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {}
+};
+GrGLSLFragmentProcessor* GrSimpleTextureEffect::onCreateGLSLInstance() const {
+    return new GrGLSLSimpleTextureEffect();
+}
+void GrSimpleTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                  GrProcessorKeyBuilder* b) const {}
+bool GrSimpleTextureEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrSimpleTextureEffect& that = other.cast<GrSimpleTextureEffect>();
+    (void)that;
+    if (image != that.image) return false;
+    if (matrix != that.matrix) return false;
+    return true;
+}
+GrSimpleTextureEffect::GrSimpleTextureEffect(const GrSimpleTextureEffect& src)
+        : INHERITED(kGrSimpleTextureEffect_ClassID, src.optimizationFlags())
+        , imageCoordTransform(src.imageCoordTransform)
+        , image(src.image)
+        , matrix(src.matrix) {
+    this->setTextureSamplerCnt(1);
+    this->addCoordTransform(&imageCoordTransform);
+}
+std::unique_ptr<GrFragmentProcessor> GrSimpleTextureEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrSimpleTextureEffect(*this));
+}
+const GrFragmentProcessor::TextureSampler& GrSimpleTextureEffect::onTextureSampler(
+        int index) const {
+    return IthTextureSampler(index, image);
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSimpleTextureEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrSimpleTextureEffect::TestCreate(
+        GrProcessorTestData* testData) {
+    int texIdx = testData->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
+                                               : GrProcessorUnitTest::kAlphaTextureIdx;
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(testData->fRandom, wrapModes);
+    if (!testData->caps()->npotTextureTileSupport()) {
+        // Performing repeat sampling on npot textures will cause asserts on HW
+        // that lacks support.
+        wrapModes[0] = GrSamplerState::WrapMode::kClamp;
+        wrapModes[1] = GrSamplerState::WrapMode::kClamp;
+    }
+
+    GrSamplerState params(wrapModes, testData->fRandom->nextBool()
+                                             ? GrSamplerState::Filter::kBilerp
+                                             : GrSamplerState::Filter::kNearest);
+
+    const SkMatrix& matrix = GrTest::TestMatrix(testData->fRandom);
+    return GrSimpleTextureEffect::Make(testData->textureProxy(texIdx), matrix, params);
+}
+#endif
diff --git a/src/gpu/effects/generated/GrSimpleTextureEffect.h b/src/gpu/effects/generated/GrSimpleTextureEffect.h
new file mode 100644
index 0000000..ac54e6a
--- /dev/null
+++ b/src/gpu/effects/generated/GrSimpleTextureEffect.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017 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 GrSimpleTextureEffect.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrSimpleTextureEffect_DEFINED
+#define GrSimpleTextureEffect_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrSimpleTextureEffect : public GrFragmentProcessor {
+public:
+    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
+                                                     const SkMatrix& matrix) {
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrSimpleTextureEffect(std::move(proxy), matrix,
+                                          GrSamplerState(GrSamplerState::WrapMode::kClamp,
+                                                         GrSamplerState::Filter::kNearest)));
+    }
+
+    /* clamp mode */
+    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
+                                                     const SkMatrix& matrix,
+                                                     GrSamplerState::Filter filter) {
+        return std::unique_ptr<GrFragmentProcessor>(new GrSimpleTextureEffect(
+                std::move(proxy), matrix,
+                GrSamplerState(GrSamplerState::WrapMode::kClamp, filter)));
+    }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
+                                                     const SkMatrix& matrix,
+                                                     const GrSamplerState& p) {
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrSimpleTextureEffect(std::move(proxy), matrix, p));
+    }
+    GrSimpleTextureEffect(const GrSimpleTextureEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "SimpleTextureEffect"; }
+    GrCoordTransform imageCoordTransform;
+    TextureSampler image;
+    SkMatrix44 matrix;
+
+private:
+    GrSimpleTextureEffect(sk_sp<GrTextureProxy> image, SkMatrix44 matrix,
+                          GrSamplerState samplerParams)
+            : INHERITED(kGrSimpleTextureEffect_ClassID,
+                        (OptimizationFlags)ModulateForSamplerOptFlags(
+                                image->config(),
+                                samplerParams.wrapModeX() ==
+                                                GrSamplerState::WrapMode::kClampToBorder ||
+                                        samplerParams.wrapModeY() ==
+                                                GrSamplerState::WrapMode::kClampToBorder))
+            , imageCoordTransform(matrix, image.get())
+            , image(std::move(image), samplerParams)
+            , matrix(matrix) {
+        this->setTextureSamplerCnt(1);
+        this->addCoordTransform(&imageCoordTransform);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif