Move ProgramImpl definitions into Processor subclass headers.

Move ProgramImpl function definitions into Processor subclass cpp files.

Delete separate h/cpp files.

Modify GrGLSLVaryingHandler::addPassThroughAttribute to break #include
cycle. It now takes a ShaderVar rather than a GP::Attribute, making
it slightly more flexible as the input can be any variable defined
in the vertex shader.

Bug: skia:11358
Change-Id: I94ee8cd44d29e194216592ecae5fd28de785c975
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438596
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp
index c844c8c..6300b06 100644
--- a/src/core/SkBlurMF.cpp
+++ b/src/core/SkBlurMF.cpp
@@ -36,7 +36,6 @@
 #include "src/gpu/effects/GrSkSLFP.h"
 #include "src/gpu/effects/GrTextureEffect.h"
 #include "src/gpu/geometry/GrStyledShape.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 3876f7f..e0e1cb8 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -108,7 +108,6 @@
 #include "src/gpu/GrRecordingContextPriv.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 
 class ColorTableEffect : public GrFragmentProcessor {
diff --git a/src/effects/imagefilters/SkDisplacementMapImageFilter.cpp b/src/effects/imagefilters/SkDisplacementMapImageFilter.cpp
index fc0d856..920195f 100644
--- a/src/effects/imagefilters/SkDisplacementMapImageFilter.cpp
+++ b/src/effects/imagefilters/SkDisplacementMapImageFilter.cpp
@@ -18,13 +18,13 @@
 #include "include/gpu/GrRecordingContext.h"
 #include "src/gpu/GrCaps.h"
 #include "src/gpu/GrColorSpaceXform.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrRecordingContextPriv.h"
 #include "src/gpu/GrTexture.h"
 #include "src/gpu/GrTextureProxy.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/SurfaceFillContext.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/effects/imagefilters/SkLightingImageFilter.cpp b/src/effects/imagefilters/SkLightingImageFilter.cpp
index a05e4a4..ca42f53 100644
--- a/src/effects/imagefilters/SkLightingImageFilter.cpp
+++ b/src/effects/imagefilters/SkLightingImageFilter.cpp
@@ -27,7 +27,6 @@
 #include "src/gpu/SkGr.h"
 #include "src/gpu/SurfaceFillContext.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/effects/imagefilters/SkMorphologyImageFilter.cpp b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
index ca3c55d..3ee3cd8 100644
--- a/src/effects/imagefilters/SkMorphologyImageFilter.cpp
+++ b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
@@ -18,13 +18,13 @@
 #if SK_SUPPORT_GPU
 #include "include/gpu/GrRecordingContext.h"
 #include "src/gpu/GrDirectContextPriv.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrRecordingContextPriv.h"
 #include "src/gpu/GrTexture.h"
 #include "src/gpu/GrTextureProxy.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/SurfaceFillContext.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/gpu/GrColorSpaceXform.cpp b/src/gpu/GrColorSpaceXform.cpp
index e1af8fa..701665d 100644
--- a/src/gpu/GrColorSpaceXform.cpp
+++ b/src/gpu/GrColorSpaceXform.cpp
@@ -11,7 +11,6 @@
 #include "src/core/SkColorSpacePriv.h"
 #include "src/gpu/GrColorInfo.h"
 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 
 sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkAlphaType srcAT,
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 587814a..27c0965 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -10,8 +10,8 @@
 #include "include/core/SkRefCnt.h"
 #include "src/core/SkArenaAlloc.h"
 #include "src/gpu/GrCaps.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
@@ -163,7 +163,7 @@
             // Setup coverage as pass through
             if (gp.hasVertexCoverage() && !tweakAlpha) {
                 fragBuilder->codeAppendf("half alpha = 1.0;");
-                varyingHandler->addPassThroughAttribute(gp.fInCoverage, "alpha");
+                varyingHandler->addPassThroughAttribute(gp.fInCoverage.asShaderVar(), "alpha");
                 if (coverageNeedsSaturate) {
                     fragBuilder->codeAppendf("half4 %s = half4(saturate(alpha));",
                                              args.fOutputCoverage);
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index edc5850..856e011 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -5,15 +5,17 @@
 * found in the LICENSE file.
 */
 
-#include "src/core/SkRuntimeEffectPriv.h"
 #include "src/gpu/GrFragmentProcessor.h"
+
+#include "src/core/SkRuntimeEffectPriv.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrProcessorAnalysis.h"
+#include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
 #include "src/gpu/effects/GrSkSLFP.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 
@@ -925,3 +927,132 @@
 
     return HighPrecisionFragmentProcessor::Make(std::move(fp));
 }
+
+//////////////////////////////////////////////////////////////////////////////
+
+using ProgramImpl = GrFragmentProcessor::ProgramImpl;
+
+void ProgramImpl::setData(const GrGLSLProgramDataManager& pdman,
+                          const GrFragmentProcessor& processor) {
+    this->onSetData(pdman, processor);
+}
+
+void ProgramImpl::emitChildFunctions(EmitArgs& args) {
+    for (int i = 0; i < this->numChildProcessors(); ++i) {
+        ProgramImpl* childGLSLFP = this->childProcessor(i);
+        if (!childGLSLFP) {
+            continue;
+        }
+
+        const GrFragmentProcessor* childFP = args.fFp.childProcessor(i);
+        SkASSERT(childFP);
+
+        EmitArgs childArgs(args.fFragBuilder,
+                           args.fUniformHandler,
+                           args.fShaderCaps,
+                           *childFP,
+                           childFP->isBlendFunction() ? "_src" : "_input",
+                           "_dst",
+                           "_coords");
+        args.fFragBuilder->writeProcessorFunction(childGLSLFP, childArgs);
+    }
+}
+
+SkString ProgramImpl::invokeChild(int childIndex,
+                                  const char* inputColor,
+                                  const char* destColor,
+                                  EmitArgs& args,
+                                  SkSL::String skslCoords) {
+    SkASSERT(childIndex >= 0);
+
+    if (!inputColor) {
+        inputColor = args.fInputColor;
+    }
+
+    const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
+    if (!childProc) {
+        // If no child processor is provided, return the input color as-is.
+        return SkString(inputColor);
+    }
+
+    auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
+                                     inputColor);
+
+    if (childProc->isBlendFunction()) {
+        if (!destColor) {
+            destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
+        }
+        invocation.appendf(", %s", destColor);
+    }
+
+    // Assert that the child has no sample matrix. A uniform matrix sample call would go through
+    // invokeChildWithMatrix, not here.
+    SkASSERT(!childProc->sampleUsage().isUniformMatrix());
+
+    if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
+        SkASSERT(!childProc->sampleUsage().isFragCoord() || skslCoords == "sk_FragCoord.xy");
+        // The child's function takes a half4 color and a float2 coordinate
+        invocation.appendf(", %s", skslCoords.empty() ? args.fSampleCoord : skslCoords.c_str());
+    }
+
+    invocation.append(")");
+    return invocation;
+}
+
+SkString ProgramImpl::invokeChildWithMatrix(int childIndex,
+                                            const char* inputColor,
+                                            const char* destColor,
+                                            EmitArgs& args) {
+    SkASSERT(childIndex >= 0);
+
+    if (!inputColor) {
+        inputColor = args.fInputColor;
+    }
+
+    const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
+    if (!childProc) {
+        // If no child processor is provided, return the input color as-is.
+        return SkString(inputColor);
+    }
+
+    SkASSERT(childProc->sampleUsage().isUniformMatrix());
+
+    // Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
+    GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
+            args.fFp, SkString(SkSL::SampleUsage::MatrixUniformName()));
+    SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
+    const SkString& matrixName(uniform.getName());
+
+    auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
+                                     inputColor);
+
+    if (childProc->isBlendFunction()) {
+        if (!destColor) {
+            destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
+        }
+        invocation.appendf(", %s", destColor);
+    }
+
+    // Produce a string containing the call to the helper function. We have a uniform variable
+    // containing our transform (matrixName). If the parent coords were produced by uniform
+    // transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
+    // and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
+    // function signature will not take in coords.
+    //
+    // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
+    // the function.
+    if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
+        // Only check perspective for this specific matrix transform, not the aggregate FP property.
+        // Any parent perspective will have already been applied when evaluated in the FS.
+        if (childProc->sampleUsage().hasPerspective()) {
+            invocation.appendf(", proj((%s) * %s.xy1)", matrixName.c_str(), args.fSampleCoord);
+        } else if (args.fShaderCaps->nonsquareMatrixSupport()) {
+            invocation.appendf(", float3x2(%s) * %s.xy1", matrixName.c_str(), args.fSampleCoord);
+        } else {
+            invocation.appendf(", ((%s) * %s.xy1).xy", matrixName.c_str(), args.fSampleCoord);
+        }
+    }
+
+    invocation.append(")");
+    return invocation;
+}
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h
index 759aae1..1a49197 100644
--- a/src/gpu/GrFragmentProcessor.h
+++ b/src/gpu/GrFragmentProcessor.h
@@ -8,11 +8,15 @@
 #ifndef GrFragmentProcessor_DEFINED
 #define GrFragmentProcessor_DEFINED
 
+#include "include/private/SkSLSampleUsage.h"
+#include "include/private/SkSLString.h"
+#include "src/gpu/GrProcessor.h"
+#include "src/gpu/glsl/GrGLSLUniformHandler.h"
+
 #include <tuple>
 
-#include "include/private/SkSLSampleUsage.h"
-#include "src/gpu/GrProcessor.h"
-
+class GrGLSLFPFragmentBuilder;
+class GrGLSLProgramDataManager;
 class GrPaint;
 class GrPipeline;
 class GrProcessorKeyBuilder;
@@ -488,6 +492,192 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+class GrFragmentProcessor::ProgramImpl {
+public:
+    ProgramImpl() = default;
+
+    virtual ~ProgramImpl() = default;
+
+    using UniformHandle = GrGLSLUniformHandler::UniformHandle;
+    using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+
+    /** Called when the program stage should insert its code into the shaders. The code in each
+        shader will be in its own block ({}) and so locally scoped names will not collide across
+        stages.
+
+        @param fragBuilder       Interface used to emit code in the shaders.
+        @param uniformHandler    Interface used for accessing information about our uniforms
+        @param caps              The capabilities of the GPU which will render this FP
+        @param fp                The processor that generated this program stage.
+        @param inputColor        A half4 that holds the input color to the stage in the FS (or the
+                                 source color, for blend processors). nullptr inputs are converted
+                                 to "half4(1.0)" (solid white) during construction.
+                                 TODO: Better system for communicating optimization info
+                                 (e.g. input color is solid white, trans black, known to be opaque,
+                                 etc.) that allows the processor to communicate back similar known
+                                 info about its output.
+        @param destColor         A half4 that holds the dest color to the stage. Only meaningful
+                                 when the "is blend processor" FP flag is set.
+        @param sampleCoord       The name of a local coord reference to a float2 variable. Only
+                                 meaningful when the "references sample coords" FP flag is set.
+     */
+    struct EmitArgs {
+        EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
+                 GrGLSLUniformHandler* uniformHandler,
+                 const GrShaderCaps* caps,
+                 const GrFragmentProcessor& fp,
+                 const char* inputColor,
+                 const char* destColor,
+                 const char* sampleCoord)
+                : fFragBuilder(fragBuilder)
+                , fUniformHandler(uniformHandler)
+                , fShaderCaps(caps)
+                , fFp(fp)
+                , fInputColor(inputColor ? inputColor : "half4(1.0)")
+                , fDestColor(destColor)
+                , fSampleCoord(sampleCoord) {}
+        GrGLSLFPFragmentBuilder* fFragBuilder;
+        GrGLSLUniformHandler* fUniformHandler;
+        const GrShaderCaps* fShaderCaps;
+        const GrFragmentProcessor& fFp;
+        const char* fInputColor;
+        const char* fDestColor;
+        const char* fSampleCoord;
+    };
+
+    virtual void emitCode(EmitArgs&) = 0;
+
+    // This does not recurse to any attached child processors. Recursing the entire processor tree
+    // is the responsibility of the caller.
+    void setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor);
+
+    int numChildProcessors() const { return fChildProcessors.count(); }
+
+    ProgramImpl* childProcessor(int index) const { return fChildProcessors[index].get(); }
+
+    void setFunctionName(SkString name) {
+        SkASSERT(fFunctionName.isEmpty());
+        fFunctionName = std::move(name);
+    }
+
+    const char* functionName() const {
+        SkASSERT(!fFunctionName.isEmpty());
+        return fFunctionName.c_str();
+    }
+
+    void emitChildFunctions(EmitArgs& parentArgs);
+
+    // Invoke the child with the default input and destination colors (solid white)
+    inline SkString invokeChild(int childIndex,
+                                EmitArgs& parentArgs,
+                                SkSL::String skslCoords = "") {
+        return this->invokeChild(childIndex,
+                                 /*inputColor=*/nullptr,
+                                 /*destColor=*/nullptr,
+                                 parentArgs,
+                                 skslCoords);
+    }
+
+    inline SkString invokeChildWithMatrix(int childIndex, EmitArgs& parentArgs) {
+        return this->invokeChildWithMatrix(childIndex,
+                                           /*inputColor=*/nullptr,
+                                           /*destColor=*/nullptr,
+                                           parentArgs);
+    }
+
+    // Invoke the child with the default destination color (solid white)
+    inline SkString invokeChild(int childIndex,
+                                const char* inputColor,
+                                EmitArgs& parentArgs,
+                                SkSL::String skslCoords = "") {
+        return this->invokeChild(childIndex,
+                                 inputColor,
+                                 /*destColor=*/nullptr,
+                                 parentArgs,
+                                 skslCoords);
+    }
+
+    inline SkString invokeChildWithMatrix(int childIndex,
+                                          const char* inputColor,
+                                          EmitArgs& parentArgs) {
+        return this->invokeChildWithMatrix(childIndex,
+                                           inputColor,
+                                           /*destColor=*/nullptr,
+                                           parentArgs);
+    }
+
+    /** Invokes a child proc in its own scope. Pass in the parent's EmitArgs and invokeChild will
+     *  automatically extract the coords and samplers of that child and pass them on to the child's
+     *  emitCode(). Also, any uniforms or functions emitted by the child will have their names
+     *  mangled to prevent redefinitions. The returned string contains the output color (as a call
+     *  to the child's helper function). It is legal to pass nullptr as inputColor, since all
+     *  fragment processors are required to work without an input color.
+     *
+     *  When skslCoords is empty, invokeChild corresponds to a call to "sample(child, color)"
+     *  in SkSL. When skslCoords is not empty, invokeChild corresponds to a call to
+     *  "sample(child, color, float2)", where skslCoords is an SkSL expression that evaluates to a
+     *  float2 and is passed in as the 3rd argument.
+     */
+    SkString invokeChild(int childIndex,
+                         const char* inputColor,
+                         const char* destColor,
+                         EmitArgs& parentArgs,
+                         SkSL::String skslCoords = "");
+
+    /**
+     * As invokeChild, but transforms the coordinates according to the matrix expression attached
+     * to the child's SampleUsage object. This is only valid if the child is sampled with a
+     * const-uniform matrix.
+     */
+    SkString invokeChildWithMatrix(int childIndex,
+                                   const char* inputColor,
+                                   const char* destColor,
+                                   EmitArgs& parentArgs);
+
+    /**
+     * Pre-order traversal of a GLSLFP hierarchy, or of multiple trees with roots in an array of
+     * GLSLFPS. If initialized with an array color followed by coverage processors installed in a
+     * program thenthe iteration order will agree with a GrFragmentProcessor::Iter initialized with
+     * a GrPipeline that produces the same program key.
+     */
+    class Iter {
+    public:
+        Iter(std::unique_ptr<ProgramImpl> fps[], int cnt);
+        Iter(ProgramImpl& fp) { fFPStack.push_back(&fp); }
+
+        ProgramImpl& operator*() const;
+        ProgramImpl* operator->() const;
+        Iter& operator++();
+        operator bool() const { return !fFPStack.empty(); }
+
+        // Because each iterator carries a stack we want to avoid copies.
+        Iter(const Iter&) = delete;
+        Iter& operator=(const Iter&) = delete;
+
+    private:
+        SkSTArray<4, ProgramImpl*, true> fFPStack;
+    };
+
+private:
+    /**
+     * A ProgramImpl instance can be reused with any GrFragmentProcessor that produces the same
+     * the same key; this function reads data from a GrFragmentProcessor and uploads any
+     * uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor
+     * parameter is guaranteed to be of the same type that created this ProgramImpl and
+     * to have an identical key as the one that created this ProgramImpl.
+     */
+    virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {}
+
+    // The (mangled) name of our entry-point function
+    SkString fFunctionName;
+
+    SkTArray<std::unique_ptr<ProgramImpl>, true> fChildProcessors;
+
+    friend class GrFragmentProcessor;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
 GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
 
 static inline GrFPResult GrFPFailure(std::unique_ptr<GrFragmentProcessor> fp) {
diff --git a/src/gpu/GrGeometryProcessor.cpp b/src/gpu/GrGeometryProcessor.cpp
index 61f46f3..d87ee46 100644
--- a/src/gpu/GrGeometryProcessor.cpp
+++ b/src/gpu/GrGeometryProcessor.cpp
@@ -7,8 +7,14 @@
 
 #include "src/gpu/GrGeometryProcessor.h"
 
-#include "src/gpu/GrFragmentProcessor.h"
+#include "src/core/SkMatrixPriv.h"
+#include "src/gpu/GrPipeline.h"
+#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
+#include "src/gpu/glsl/GrGLSLUniformHandler.h"
+#include "src/gpu/glsl/GrGLSLVarying.h"
 
+#include <queue>
 
 GrGeometryProcessor::GrGeometryProcessor(ClassID classID) : GrProcessor(classID) {}
 
@@ -52,3 +58,443 @@
     fSwizzle = swizzle;
     fIsInitialized = true;
 }
+
+//////////////////////////////////////////////////////////////////////////////
+
+using ProgramImpl = GrGeometryProcessor::ProgramImpl;
+
+ProgramImpl::FPCoordsMap ProgramImpl::emitCode(EmitArgs& args, const GrPipeline& pipeline) {
+    GrGPArgs gpArgs;
+    this->onEmitCode(args, &gpArgs);
+
+    GrShaderVar positionVar = gpArgs.fPositionVar;
+    // skia:12198
+    if (args.fGeomProc.willUseGeoShader() || args.fGeomProc.willUseTessellationShaders()) {
+        positionVar = {};
+    }
+    FPCoordsMap transformMap = this->collectTransforms(args.fVertBuilder,
+                                                       args.fVaryingHandler,
+                                                       args.fUniformHandler,
+                                                       gpArgs.fLocalCoordVar,
+                                                       positionVar,
+                                                       pipeline);
+
+    if (args.fGeomProc.willUseTessellationShaders()) {
+        // Tessellation shaders are temporarily responsible for integrating their own code strings
+        // while we work out full support.
+        return transformMap;
+    }
+
+    GrGLSLVertexBuilder* vBuilder = args.fVertBuilder;
+    if (!args.fGeomProc.willUseGeoShader()) {
+        // Emit the vertex position to the hardware in the normalized window coordinates it expects.
+        SkASSERT(kFloat2_GrSLType == gpArgs.fPositionVar.getType() ||
+                 kFloat3_GrSLType == gpArgs.fPositionVar.getType());
+        vBuilder->emitNormalizedSkPosition(gpArgs.fPositionVar.c_str(),
+                                           gpArgs.fPositionVar.getType());
+        if (kFloat2_GrSLType == gpArgs.fPositionVar.getType()) {
+            args.fVaryingHandler->setNoPerspective();
+        }
+    } else {
+        // Since we have a geometry shader, leave the vertex position in Skia device space for now.
+        // The geometry Shader will operate in device space, and then convert the final positions to
+        // normalized hardware window coordinates under the hood, once everything else has finished.
+        // The subclass must call setNoPerspective on the varying handler, if applicable.
+        vBuilder->codeAppendf("sk_Position = float4(%s", gpArgs.fPositionVar.c_str());
+        switch (gpArgs.fPositionVar.getType()) {
+            case kFloat_GrSLType:
+                vBuilder->codeAppend(", 0");
+                [[fallthrough]];
+            case kFloat2_GrSLType:
+                vBuilder->codeAppend(", 0");
+                [[fallthrough]];
+            case kFloat3_GrSLType:
+                vBuilder->codeAppend(", 1");
+                [[fallthrough]];
+            case kFloat4_GrSLType:
+                vBuilder->codeAppend(");");
+                break;
+            default:
+                SK_ABORT("Invalid position var type");
+                break;
+        }
+    }
+    return transformMap;
+}
+
+ProgramImpl::FPCoordsMap ProgramImpl::collectTransforms(GrGLSLVertexBuilder* vb,
+                                                        GrGLSLVaryingHandler* varyingHandler,
+                                                        GrGLSLUniformHandler* uniformHandler,
+                                                        const GrShaderVar& localCoordsVar,
+                                                        const GrShaderVar& positionVar,
+                                                        const GrPipeline& pipeline) {
+    SkASSERT(localCoordsVar.getType() == kFloat2_GrSLType ||
+             localCoordsVar.getType() == kFloat3_GrSLType ||
+             localCoordsVar.getType() == kVoid_GrSLType);
+    SkASSERT(positionVar.getType() == kFloat2_GrSLType ||
+             positionVar.getType() == kFloat3_GrSLType ||
+             positionVar.getType() == kVoid_GrSLType);
+
+    enum class BaseCoord { kNone, kLocal, kPosition };
+
+    auto baseLocalCoordFSVar = [&, baseLocalCoord = GrGLSLVarying()]() mutable {
+        SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType()));
+        if (baseLocalCoord.type() == kVoid_GrSLType) {
+            // Initialize to the GP provided coordinate
+            baseLocalCoord = GrGLSLVarying(localCoordsVar.getType());
+            varyingHandler->addVarying("LocalCoord", &baseLocalCoord);
+            vb->codeAppendf("%s = %s;\n", baseLocalCoord.vsOut(), localCoordsVar.getName().c_str());
+        }
+        return baseLocalCoord.fsInVar();
+    };
+
+    bool canUsePosition = positionVar.getType() != kVoid_GrSLType;
+
+    FPCoordsMap result;
+    // Performs a pre-order traversal of FP hierarchy rooted at fp and identifies FPs that are
+    // sampled with a series of matrices applied to local coords. For each such FP a varying is
+    // added to the varying handler and added to 'result'.
+    auto liftTransforms = [&, traversalIndex = 0](
+                                  auto& self,
+                                  const GrFragmentProcessor& fp,
+                                  bool hasPerspective,
+                                  const GrFragmentProcessor* lastMatrixFP = nullptr,
+                                  int lastMatrixTraversalIndex = -1,
+                                  BaseCoord baseCoord = BaseCoord::kLocal) mutable -> void {
+        ++traversalIndex;
+        switch (fp.sampleUsage().kind()) {
+            case SkSL::SampleUsage::Kind::kNone:
+                // This should only happen at the root. Otherwise how did this FP get added?
+                SkASSERT(!fp.parent());
+                break;
+            case SkSL::SampleUsage::Kind::kPassThrough:
+                break;
+            case SkSL::SampleUsage::Kind::kUniformMatrix:
+                // Update tracking of last matrix and matrix props.
+                hasPerspective |= fp.sampleUsage().hasPerspective();
+                lastMatrixFP = &fp;
+                lastMatrixTraversalIndex = traversalIndex;
+                break;
+            case SkSL::SampleUsage::Kind::kFragCoord:
+                hasPerspective = positionVar.getType() == kFloat3_GrSLType;
+                lastMatrixFP = nullptr;
+                lastMatrixTraversalIndex = -1;
+                baseCoord = BaseCoord::kPosition;
+                break;
+            case SkSL::SampleUsage::Kind::kExplicit:
+                baseCoord = BaseCoord::kNone;
+                break;
+        }
+
+        auto& [varyingFSVar, hasCoordsParam] = result[&fp];
+        hasCoordsParam = fp.usesSampleCoordsDirectly();
+
+        // We add a varying if we're in a chain of matrices multiplied by local or device coords.
+        // If the coord is the untransformed local coord we add a varying. We don't if it is
+        // untransformed device coords since it doesn't save us anything over "sk_FragCoord.xy". Of
+        // course, if the FP doesn't directly use its coords then we don't add a varying.
+        if (fp.usesSampleCoordsDirectly() &&
+            (baseCoord == BaseCoord::kLocal ||
+             (baseCoord == BaseCoord::kPosition && lastMatrixFP && canUsePosition))) {
+            // Associate the varying with the highest possible node in the FP tree that shares the
+            // same coordinates so that multiple FPs in a subtree can share. If there are no matrix
+            // sample nodes on the way up the tree then directly use the local coord.
+            if (!lastMatrixFP) {
+                varyingFSVar = baseLocalCoordFSVar();
+            } else {
+                // If there is an already a varying that incorporates all matrices from the root to
+                // lastMatrixFP just use it. Otherwise, we add it.
+                auto& [varying, inputCoords, varyingIdx] = fTransformVaryingsMap[lastMatrixFP];
+                if (varying.type() == kVoid_GrSLType) {
+                    varying = GrGLSLVarying(hasPerspective ? kFloat3_GrSLType : kFloat2_GrSLType);
+                    SkString strVaryingName = SkStringPrintf("TransformedCoords_%d",
+                                                             lastMatrixTraversalIndex);
+                    varyingHandler->addVarying(strVaryingName.c_str(), &varying);
+                    inputCoords = baseCoord == BaseCoord::kLocal ? localCoordsVar : positionVar;
+                    varyingIdx = lastMatrixTraversalIndex;
+                }
+                SkASSERT(varyingIdx == lastMatrixTraversalIndex);
+                // The FP will use the varying in the fragment shader as its coords.
+                varyingFSVar = varying.fsInVar();
+            }
+            hasCoordsParam = false;
+        }
+
+        for (int c = 0; c < fp.numChildProcessors(); ++c) {
+            if (auto* child = fp.childProcessor(c)) {
+                self(self,
+                     *child,
+                     hasPerspective,
+                     lastMatrixFP,
+                     lastMatrixTraversalIndex,
+                     baseCoord);
+                // If we have a varying then we never need a param. Otherwise, if one of our
+                // children takes a non-explicit coord then we'll need our coord.
+                hasCoordsParam |= varyingFSVar.getType() == kVoid_GrSLType &&
+                                  !child->sampleUsage().isExplicit()       &&
+                                  !child->sampleUsage().isFragCoord()      &&
+                                  result[child].hasCoordsParam;
+            }
+        }
+    };
+
+    bool hasPerspective = GrSLTypeVecLength(localCoordsVar.getType()) == 3;
+    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
+        liftTransforms(liftTransforms, pipeline.getFragmentProcessor(i), hasPerspective);
+    }
+    return result;
+}
+
+void ProgramImpl::emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler) {
+    // Because descendant varyings may be computed using the varyings of ancestor FPs we make
+    // sure to visit the varyings according to FP pre-order traversal by dumping them into a
+    // priority queue.
+    using FPAndInfo = std::tuple<const GrFragmentProcessor*, TransformInfo>;
+    auto compare = [](const FPAndInfo& a, const FPAndInfo& b) {
+        return std::get<1>(a).traversalOrder > std::get<1>(b).traversalOrder;
+    };
+    std::priority_queue<FPAndInfo, std::vector<FPAndInfo>, decltype(compare)> pq(compare);
+    std::for_each(fTransformVaryingsMap.begin(), fTransformVaryingsMap.end(), [&pq](auto entry) {
+        pq.push(entry);
+    });
+    for (; !pq.empty(); pq.pop()) {
+        const auto& [fp, info] = pq.top();
+        // If we recorded a transform info, its sample matrix must be uniform
+        SkASSERT(fp->sampleUsage().isUniformMatrix());
+        GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
+                *fp->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
+        // Start with this matrix and accumulate additional matrices as we walk up the FP tree
+        // to either the base coords or an ancestor FP that has an associated varying.
+        SkString transformExpression = uniform.getName();
+
+        // If we hit an ancestor with a varying on our walk up then save off the varying as the
+        // input to our accumulated transformExpression. Start off assuming we'll reach the root.
+        GrShaderVar inputCoords = info.inputCoords;
+
+        for (const auto* base = fp->parent(); base; base = base->parent()) {
+            if (auto iter = fTransformVaryingsMap.find(base); iter != fTransformVaryingsMap.end()) {
+                // Can stop here, as this varying already holds all transforms from higher FPs
+                // We'll apply the residual transformExpression we've accumulated up from our
+                // starting FP to this varying.
+                inputCoords = iter->second.varying.vsOutVar();
+                break;
+            } else if (base->sampleUsage().isUniformMatrix()) {
+                // Accumulate any matrices along the path to either the original local/device coords
+                // or a parent varying. Getting here means this FP was sampled with a uniform matrix
+                // but all uses of coords below here in the FP hierarchy are beneath additional
+                // matrix samples and thus this node wasn't assigned a varying.
+                GrShaderVar parentUniform = uniformHandler->liftUniformToVertexShader(
+                        *base->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
+                transformExpression.appendf(" * %s", parentUniform.getName().c_str());
+            } else if (base->sampleUsage().isFragCoord()) {
+                // Our chain of matrices starts here and is based on the device space position.
+                break;
+            } else {
+                // This intermediate FP is just a pass through and doesn't need to be built
+                // in to the expression, but we must visit its parents in case they add transforms.
+                SkASSERT(base->sampleUsage().isPassThrough() || !base->sampleUsage().isSampled());
+            }
+        }
+
+        SkString inputStr;
+        if (inputCoords.getType() == kFloat2_GrSLType) {
+            inputStr = SkStringPrintf("%s.xy1", inputCoords.getName().c_str());
+        } else {
+            SkASSERT(inputCoords.getType() == kFloat3_GrSLType);
+            inputStr = inputCoords.getName();
+        }
+
+        vb->codeAppend("{\n");
+        if (info.varying.type() == kFloat2_GrSLType) {
+            if (vb->getProgramBuilder()->shaderCaps()->nonsquareMatrixSupport()) {
+                vb->codeAppendf("%s = float3x2(%s) * %s",
+                                info.varying.vsOut(),
+                                transformExpression.c_str(),
+                                inputStr.c_str());
+            } else {
+                vb->codeAppendf("%s = (%s * %s).xy",
+                                info.varying.vsOut(),
+                                transformExpression.c_str(),
+                                inputStr.c_str());
+            }
+        } else {
+            SkASSERT(info.varying.type() == kFloat3_GrSLType);
+            vb->codeAppendf("%s = %s * %s",
+                            info.varying.vsOut(),
+                            transformExpression.c_str(),
+                            inputStr.c_str());
+        }
+        vb->codeAppend(";\n");
+        vb->codeAppend("}\n");
+    }
+    // We don't need this map anymore.
+    fTransformVaryingsMap.clear();
+}
+
+void ProgramImpl::setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
+                                    GrGLSLUniformHandler* uniformHandler,
+                                    const char* outputName,
+                                    UniformHandle* colorUniform) {
+    SkASSERT(colorUniform);
+    const char* stagedLocalVarName;
+    *colorUniform = uniformHandler->addUniform(nullptr,
+                                               kFragment_GrShaderFlag,
+                                               kHalf4_GrSLType,
+                                               "Color",
+                                               &stagedLocalVarName);
+    fragBuilder->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
+    if (fragBuilder->getProgramBuilder()->shaderCaps()->mustObfuscateUniformColor()) {
+        fragBuilder->codeAppendf("%s = max(%s, half4(0));", outputName, outputName);
+    }
+}
+
+void ProgramImpl::SetTransform(const GrGLSLProgramDataManager& pdman,
+                               const GrShaderCaps& shaderCaps,
+                               const UniformHandle& uniform,
+                               const SkMatrix& matrix,
+                               SkMatrix* state) {
+    if (!uniform.isValid() || (state && SkMatrixPriv::CheapEqual(*state, matrix))) {
+        // No update needed
+        return;
+    }
+    if (state) {
+        *state = matrix;
+    }
+    if (matrix.isScaleTranslate() && !shaderCaps.reducedShaderMode()) {
+        // ComputeMatrixKey and writeX() assume the uniform is a float4 (can't assert since nothing
+        // is exposed on a handle, but should be caught lower down).
+        float values[4] = {matrix.getScaleX(), matrix.getTranslateX(),
+                           matrix.getScaleY(), matrix.getTranslateY()};
+        pdman.set4fv(uniform, 1, values);
+    } else {
+        pdman.setSkMatrix(uniform, matrix);
+    }
+}
+
+static void write_passthrough_vertex_position(GrGLSLVertexBuilder* vertBuilder,
+                                              const GrShaderVar& inPos,
+                                              GrShaderVar* outPos) {
+    SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType);
+    SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
+    outPos->set(inPos.getType(), outName.c_str());
+    vertBuilder->codeAppendf("float%d %s = %s;",
+                             GrSLTypeVecLength(inPos.getType()),
+                             outName.c_str(),
+                             inPos.getName().c_str());
+}
+
+static void write_vertex_position(GrGLSLVertexBuilder* vertBuilder,
+                                  GrGLSLUniformHandler* uniformHandler,
+                                  const GrShaderCaps& shaderCaps,
+                                  const GrShaderVar& inPos,
+                                  const SkMatrix& matrix,
+                                  const char* matrixName,
+                                  GrShaderVar* outPos,
+                                  ProgramImpl::UniformHandle* matrixUniform) {
+    SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType);
+    SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
+
+    if (matrix.isIdentity() && !shaderCaps.reducedShaderMode()) {
+        write_passthrough_vertex_position(vertBuilder, inPos, outPos);
+        return;
+    }
+    SkASSERT(matrixUniform);
+
+    bool useCompactTransform = matrix.isScaleTranslate() && !shaderCaps.reducedShaderMode();
+    const char* mangledMatrixName;
+    *matrixUniform = uniformHandler->addUniform(nullptr,
+                                                kVertex_GrShaderFlag,
+                                                useCompactTransform ? kFloat4_GrSLType
+                                                                    : kFloat3x3_GrSLType,
+                                                matrixName,
+                                                &mangledMatrixName);
+
+    if (inPos.getType() == kFloat3_GrSLType) {
+        // A float3 stays a float3 whether or not the matrix adds perspective
+        if (useCompactTransform) {
+            vertBuilder->codeAppendf("float3 %s = %s.xz1 * %s + %s.yw0;\n",
+                                     outName.c_str(),
+                                     mangledMatrixName,
+                                     inPos.getName().c_str(),
+                                     mangledMatrixName);
+        } else {
+            vertBuilder->codeAppendf("float3 %s = %s * %s;\n",
+                                     outName.c_str(),
+                                     mangledMatrixName,
+                                     inPos.getName().c_str());
+        }
+        outPos->set(kFloat3_GrSLType, outName.c_str());
+        return;
+    }
+    if (matrix.hasPerspective()) {
+        // A float2 is promoted to a float3 if we add perspective via the matrix
+        SkASSERT(!useCompactTransform);
+        vertBuilder->codeAppendf("float3 %s = (%s * %s.xy1);",
+                                 outName.c_str(),
+                                 mangledMatrixName,
+                                 inPos.getName().c_str());
+        outPos->set(kFloat3_GrSLType, outName.c_str());
+        return;
+    }
+    if (useCompactTransform) {
+        vertBuilder->codeAppendf("float2 %s = %s.xz * %s + %s.yw;\n",
+                                 outName.c_str(),
+                                 mangledMatrixName,
+                                 inPos.getName().c_str(),
+                                 mangledMatrixName);
+    } else if (shaderCaps.nonsquareMatrixSupport()) {
+        vertBuilder->codeAppendf("float2 %s = float3x2(%s) * %s.xy1;\n",
+                                 outName.c_str(),
+                                 mangledMatrixName,
+                                 inPos.getName().c_str());
+    } else {
+        vertBuilder->codeAppendf("float2 %s = (%s * %s.xy1).xy;\n",
+                                 outName.c_str(),
+                                 mangledMatrixName,
+                                 inPos.getName().c_str());
+    }
+    outPos->set(kFloat2_GrSLType, outName.c_str());
+}
+
+void ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
+                                      GrGPArgs* gpArgs,
+                                      const char* posName) {
+    // writeOutputPosition assumes the incoming pos name points to a float2 variable
+    GrShaderVar inPos(posName, kFloat2_GrSLType);
+    write_passthrough_vertex_position(vertBuilder, inPos, &gpArgs->fPositionVar);
+}
+
+void ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
+                                      GrGLSLUniformHandler* uniformHandler,
+                                      const GrShaderCaps& shaderCaps,
+                                      GrGPArgs* gpArgs,
+                                      const char* posName,
+                                      const SkMatrix& mat,
+                                      UniformHandle* viewMatrixUniform) {
+    GrShaderVar inPos(posName, kFloat2_GrSLType);
+    write_vertex_position(vertBuilder,
+                          uniformHandler,
+                          shaderCaps,
+                          inPos,
+                          mat,
+                          "viewMatrix",
+                          &gpArgs->fPositionVar,
+                          viewMatrixUniform);
+}
+
+void ProgramImpl::WriteLocalCoord(GrGLSLVertexBuilder* vertBuilder,
+                                  GrGLSLUniformHandler* uniformHandler,
+                                  const GrShaderCaps& shaderCaps,
+                                  GrGPArgs* gpArgs,
+                                  GrShaderVar localVar,
+                                  const SkMatrix& localMatrix,
+                                  UniformHandle* localMatrixUniform) {
+    write_vertex_position(vertBuilder,
+                          uniformHandler,
+                          shaderCaps,
+                          localVar,
+                          localMatrix,
+                          "localMatrix",
+                          &gpArgs->fLocalCoordVar,
+                          localMatrixUniform);
+}
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 37138f9..733b5ad 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -9,12 +9,23 @@
 #define GrGeometryProcessor_DEFINED
 
 #include "src/gpu/GrColor.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrNonAtomicRef.h"
 #include "src/gpu/GrProcessor.h"
+#include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/GrShaderVar.h"
 #include "src/gpu/GrSwizzle.h"
+#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
+#include "src/gpu/glsl/GrGLSLUniformHandler.h"
+#include "src/gpu/glsl/GrGLSLVarying.h"
 
+#include <unordered_map>
+
+class GrGLSLFPFragmentBuilder;
+class GrGLSLGeometryBuilder;
+class GrGLSLVaryingHandler;
 class GrGLSLUniformHandler;
+class GrGLSLVertexBuilder;
 
 /**
  * The GrGeometryProcessor represents some kind of geometric primitive.  This includes the shape
@@ -273,6 +284,216 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+class GrGeometryProcessor::ProgramImpl {
+public:
+    using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
+    using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+    /**
+     * Struct of optional varying that replaces the input coords and bool indicating whether the FP
+     * should take a coord param as an argument. The latter may be false if the coords are simply
+     * unused or if the GP has lifted their computation to a varying emitted by the VS.
+     */
+    struct FPCoords {GrShaderVar coordsVarying; bool hasCoordsParam;};
+    using FPCoordsMap = std::unordered_map<const GrFragmentProcessor*, FPCoords>;
+
+    virtual ~ProgramImpl() = default;
+
+    struct EmitArgs {
+        EmitArgs(GrGLSLVertexBuilder* vertBuilder,
+                 GrGLSLGeometryBuilder* geomBuilder,
+                 GrGLSLFPFragmentBuilder* fragBuilder,
+                 GrGLSLVaryingHandler* varyingHandler,
+                 GrGLSLUniformHandler* uniformHandler,
+                 const GrShaderCaps* caps,
+                 const GrGeometryProcessor& geomProc,
+                 const char* outputColor,
+                 const char* outputCoverage,
+                 const SamplerHandle* texSamplers)
+                : fVertBuilder(vertBuilder)
+                , fGeomBuilder(geomBuilder)
+                , fFragBuilder(fragBuilder)
+                , fVaryingHandler(varyingHandler)
+                , fUniformHandler(uniformHandler)
+                , fShaderCaps(caps)
+                , fGeomProc(geomProc)
+                , fOutputColor(outputColor)
+                , fOutputCoverage(outputCoverage)
+                , fTexSamplers(texSamplers) {}
+        GrGLSLVertexBuilder* fVertBuilder;
+        GrGLSLGeometryBuilder* fGeomBuilder;
+        GrGLSLFPFragmentBuilder* fFragBuilder;
+        GrGLSLVaryingHandler* fVaryingHandler;
+        GrGLSLUniformHandler* fUniformHandler;
+        const GrShaderCaps* fShaderCaps;
+        const GrGeometryProcessor& fGeomProc;
+        const char* fOutputColor;
+        const char* fOutputCoverage;
+        const SamplerHandle* fTexSamplers;
+    };
+
+    /**
+     * Emits the code from this geometry processor into the shaders. For any FP in the pipeline that
+     * has its input coords implemented by the GP as a varying, the varying will be accessible in
+     * the returned map and should be used when the FP code is emitted.
+     **/
+    FPCoordsMap emitCode(EmitArgs&, const GrPipeline& pipeline);
+
+    /**
+     * Called after all effect emitCode() functions, to give the processor a chance to write out
+     * additional transformation code now that all uniforms have been emitted.
+     * It generates the final code for assigning transformed coordinates to the varyings recorded
+     * in the call to collectTransforms(). This must happen after FP code emission so that it has
+     * access to any uniforms the FPs registered for uniform sample matrix invocations.
+     */
+    void emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler);
+
+    /**
+     * A ProgramImpl instance can be reused with any GrGeometryProcessor that produces the same key.
+     * This function reads data from a GrGeometryProcessor and updates any uniform variables
+     * required by the shaders created in emitCode(). The GrGeometryProcessor parameter is
+     * guaranteed to be of the same type and to have an identical processor key as the
+     * GrGeometryProcessor that created this ProgramImpl.
+     */
+    virtual void setData(const GrGLSLProgramDataManager&,
+                         const GrShaderCaps&,
+                         const GrGeometryProcessor&) = 0;
+
+    // We use these methods as a temporary back door to inject OpenGL tessellation code. Once
+    // tessellation is supported by SkSL we can remove these.
+    virtual SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
+                                              const char* versionAndExtensionDecls,
+                                              const GrGLSLUniformHandler&,
+                                              const GrShaderCaps&) const {
+        SK_ABORT("Not implemented.");
+    }
+    virtual SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
+                                                 const char* versionAndExtensionDecls,
+                                                 const GrGLSLUniformHandler&,
+                                                 const GrShaderCaps&) const {
+        SK_ABORT("Not implemented.");
+    }
+
+    // GPs that use writeOutputPosition and/or writeLocalCoord must incorporate the matrix type
+    // into their key, and should use this function or one of the other related helpers.
+    static uint32_t ComputeMatrixKey(const GrShaderCaps& caps, const SkMatrix& mat) {
+        if (!caps.reducedShaderMode()) {
+            if (mat.isIdentity()) {
+                return 0b00;
+            }
+            if (mat.isScaleTranslate()) {
+                return 0b01;
+            }
+        }
+        if (!mat.hasPerspective()) {
+            return 0b10;
+        }
+        return 0b11;
+    }
+
+    static uint32_t ComputeMatrixKeys(const GrShaderCaps& shaderCaps,
+                                      const SkMatrix& viewMatrix,
+                                      const SkMatrix& localMatrix) {
+        return (ComputeMatrixKey(shaderCaps, viewMatrix) << kMatrixKeyBits) |
+               ComputeMatrixKey(shaderCaps, localMatrix);
+    }
+
+    static uint32_t AddMatrixKeys(const GrShaderCaps& shaderCaps,
+                                  uint32_t flags,
+                                  const SkMatrix& viewMatrix,
+                                  const SkMatrix& localMatrix) {
+        // Shifting to make room for the matrix keys shouldn't lose bits
+        SkASSERT(((flags << (2 * kMatrixKeyBits)) >> (2 * kMatrixKeyBits)) == flags);
+        return (flags << (2 * kMatrixKeyBits)) |
+               ComputeMatrixKeys(shaderCaps, viewMatrix, localMatrix);
+    }
+    static constexpr int kMatrixKeyBits = 2;
+
+protected:
+    void setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
+                           GrGLSLUniformHandler* uniformHandler,
+                           const char* outputName,
+                           UniformHandle* colorUniform);
+
+    // A helper for setting the matrix on a uniform handle initialized through
+    // writeOutputPosition or writeLocalCoord. Automatically handles elided uniforms,
+    // scale+translate matrices, and state tracking (if provided state pointer is non-null).
+    static void SetTransform(const GrGLSLProgramDataManager&,
+                             const GrShaderCaps&,
+                             const UniformHandle& uniform,
+                             const SkMatrix& matrix,
+                             SkMatrix* state = nullptr);
+
+    struct GrGPArgs {
+        // Used to specify the output variable used by the GP to store its device position. It can
+        // either be a float2 or a float3 (in order to handle perspective). The subclass sets this
+        // in its onEmitCode().
+        GrShaderVar fPositionVar;
+        // Used to specify the variable storing the draw's local coordinates. It can be either a
+        // float2, float3, or void. It can only be void when no FP needs local coordinates. This
+        // variable can be an attribute or local variable, but should not itself be a varying.
+        // ProgramImpl automatically determines if this must be passed to a FS.
+        GrShaderVar fLocalCoordVar;
+    };
+
+    // Helpers for adding code to write the transformed vertex position. The first simple version
+    // just writes a variable named by 'posName' into the position output variable with the
+    // assumption that the position is 2D. The second version transforms the input position by a
+    // view matrix and the output variable is 2D or 3D depending on whether the view matrix is
+    // perspective. Both versions declare the output position variable and will set
+    // GrGPArgs::fPositionVar.
+    static void WriteOutputPosition(GrGLSLVertexBuilder*, GrGPArgs*, const char* posName);
+    static void WriteOutputPosition(GrGLSLVertexBuilder*,
+                                    GrGLSLUniformHandler*,
+                                    const GrShaderCaps&,
+                                    GrGPArgs*,
+                                    const char* posName,
+                                    const SkMatrix& viewMatrix,
+                                    UniformHandle* viewMatrixUniform);
+
+    // Helper to transform an existing variable by a given local matrix (e.g. the inverse view
+    // matrix). It will declare the transformed local coord variable and will set
+    // GrGPArgs::fLocalCoordVar.
+    static void WriteLocalCoord(GrGLSLVertexBuilder*,
+                                GrGLSLUniformHandler*,
+                                const GrShaderCaps&,
+                                GrGPArgs*,
+                                GrShaderVar localVar,
+                                const SkMatrix& localMatrix,
+                                UniformHandle* localMatrixUniform);
+
+private:
+    virtual void onEmitCode(EmitArgs&, GrGPArgs*) = 0;
+
+    // Iterates over the FPs beginning with the passed iter to register additional varyings and
+    // uniforms to support VS-promoted local coord evaluation for the FPs.
+    //
+    // This must happen before FP code emission so that the FPs can find the appropriate varying
+    // handles they use in place of explicit coord sampling; it is automatically called after
+    // onEmitCode() returns using the value stored in GpArgs::fLocalCoordVar and
+    // GpArgs::fPositionVar.
+    FPCoordsMap collectTransforms(GrGLSLVertexBuilder* vb,
+                                  GrGLSLVaryingHandler* varyingHandler,
+                                  GrGLSLUniformHandler* uniformHandler,
+                                  const GrShaderVar& localCoordsVar,
+                                  const GrShaderVar& positionVar,
+                                  const GrPipeline& pipeline);
+    struct TransformInfo {
+        // The varying that conveys the coordinates to one or more FPs in the FS.
+        GrGLSLVarying varying;
+        // The coordinate to be transformed. varying is computed from this.
+        GrShaderVar   inputCoords;
+        // Used to sort so that ancestor FP varyings are initialized before descendant FP varyings.
+        int           traversalOrder;
+    };
+    // Populated by collectTransforms() for use in emitTransformCode(). When we lift the computation
+    // of a FP's input coord to a varying we propagate that varying up the FP tree to the highest
+    // node that shares the same coordinates. This allows multiple FPs in a subtree to share a
+    // varying.
+    std::unordered_map<const GrFragmentProcessor*, TransformInfo> fTransformVaryingsMap;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
 /**
  * Used to capture the properties of the GrTextureProxies required/expected by a primitiveProcessor
  * along with an associated GrSamplerState. The actual proxies used are stored in either the
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index a8ebd02..8ef9f08 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -9,6 +9,7 @@
 
 #include "include/private/SkChecksum.h"
 #include "include/private/SkTo.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrProcessor.h"
@@ -17,7 +18,6 @@
 #include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/GrTexture.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 
 enum {
diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp
index d6574f7..c36048a 100644
--- a/src/gpu/GrXferProcessor.cpp
+++ b/src/gpu/GrXferProcessor.cpp
@@ -9,6 +9,8 @@
 
 #include "src/gpu/GrCaps.h"
 #include "src/gpu/GrPipeline.h"
+#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 
 GrXferProcessor::GrXferProcessor(ClassID classID)
         : INHERITED(classID)
@@ -184,3 +186,124 @@
         return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps);
     }
 }
+
+//////////////////////////////////////////////////////////////////////////////
+
+using ProgramImpl = GrXferProcessor::ProgramImpl;
+
+// This is only called for cases where we are doing LCD coverage and not using in shader blending.
+// For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha
+// coverage since src alpha will always be greater than or equal to dst alpha.
+static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder,
+                                    const char* srcCoverage,
+                                    const GrXferProcessor& proc) {
+    if (srcCoverage && proc.isLCD()) {
+        fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);",
+                                 srcCoverage,
+                                 srcCoverage,
+                                 srcCoverage,
+                                 srcCoverage);
+    }
+}
+
+void ProgramImpl::emitCode(const EmitArgs& args) {
+    if (!args.fXP.willReadDstColor()) {
+        adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP);
+        this->emitOutputsForBlendState(args);
+    } else {
+        GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
+        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
+        const char* dstColor = fragBuilder->dstColor();
+
+        bool needsLocalOutColor = false;
+
+        if (args.fDstTextureSamplerHandle.isValid()) {
+            if (args.fInputCoverage) {
+                // We don't think any shaders actually output negative coverage, but just as a
+                // safety check for floating point precision errors, we compare with <= here. We
+                // just check the RGB values of the coverage, since the alpha may not have been set
+                // when using LCD. If we are using single-channel coverage, alpha will be equal to
+                // RGB anyway.
+                //
+                // The discard here also helps for batching text-draws together, which need to read
+                // from a dst copy for blends. However, this only helps the case where the outer
+                // bounding boxes of each letter overlap and not two actually parts of the text.
+                fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {"
+                                         "    discard;"
+                                         "}",
+                                         args.fInputCoverage);
+            }
+        } else {
+            needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch();
+        }
+
+        const char* outColor = "_localColorOut";
+        if (!needsLocalOutColor) {
+            outColor = args.fOutputPrimary;
+        } else {
+            fragBuilder->codeAppendf("half4 %s;", outColor);
+        }
+
+        this->emitBlendCodeForDstRead(fragBuilder,
+                                      uniformHandler,
+                                      args.fInputColor,
+                                      args.fInputCoverage,
+                                      dstColor,
+                                      outColor,
+                                      args.fOutputSecondary,
+                                      args.fXP);
+        if (needsLocalOutColor) {
+            fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor);
+        }
+    }
+
+    // Swizzle the fragment shader outputs if necessary.
+    this->emitWriteSwizzle(args.fXPFragBuilder,
+                           args.fWriteSwizzle,
+                           args.fOutputPrimary,
+                           args.fOutputSecondary);
+}
+
+void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x,
+                                   const GrSwizzle& swizzle,
+                                   const char* outColor,
+                                   const char* outColorSecondary) const {
+    if (GrSwizzle::RGBA() != swizzle) {
+        x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str());
+        if (outColorSecondary) {
+            x->codeAppendf("%s = %s.%s;",
+                           outColorSecondary,
+                           outColorSecondary,
+                           swizzle.asString().c_str());
+        }
+    }
+}
+
+void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
+    this->onSetData(pdm, xp);
+}
+
+void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
+                                            const char* srcCoverage,
+                                            const char* dstColor,
+                                            const char* outColor,
+                                            const char* outColorSecondary,
+                                            const GrXferProcessor& proc) {
+    if (srcCoverage) {
+        if (proc.isLCD()) {
+            fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);",
+                                     dstColor,
+                                     outColor,
+                                     srcCoverage);
+        }
+        fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;",
+                                 outColor,
+                                 srcCoverage,
+                                 outColor,
+                                 srcCoverage,
+                                 dstColor);
+        if (proc.isLCD()) {
+            fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor);
+        }
+    }
+}
diff --git a/src/gpu/GrXferProcessor.h b/src/gpu/GrXferProcessor.h
index 3dea132..439895d 100644
--- a/src/gpu/GrXferProcessor.h
+++ b/src/gpu/GrXferProcessor.h
@@ -14,8 +14,10 @@
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/GrProcessorAnalysis.h"
 #include "src/gpu/GrSurfaceProxyView.h"
+#include "src/gpu/glsl/GrGLSLUniformHandler.h"
 
-class GrProcessorSet;
+class GrGLSLXPFragmentBuilder;
+class GrGLSLProgramDataManager;
 class GrShaderCaps;
 
 /**
@@ -275,4 +277,106 @@
 
 GR_MAKE_BITFIELD_CLASS_OPS(GrXPFactory::AnalysisProperties)
 
+//////////////////////////////////////////////////////////////////////////////
+
+class GrXferProcessor::ProgramImpl {
+public:
+    virtual ~ProgramImpl() = default;
+
+    using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+
+    struct EmitArgs {
+        EmitArgs(GrGLSLXPFragmentBuilder* fragBuilder,
+                 GrGLSLUniformHandler* uniformHandler,
+                 const GrShaderCaps* caps,
+                 const GrXferProcessor& xp,
+                 const char* inputColor,
+                 const char* inputCoverage,
+                 const char* outputPrimary,
+                 const char* outputSecondary,
+                 const SamplerHandle dstTextureSamplerHandle,
+                 GrSurfaceOrigin dstTextureOrigin,
+                 const GrSwizzle& writeSwizzle)
+                : fXPFragBuilder(fragBuilder)
+                , fUniformHandler(uniformHandler)
+                , fShaderCaps(caps)
+                , fXP(xp)
+                , fInputColor(inputColor ? inputColor : "half4(1.0)")
+                , fInputCoverage(inputCoverage)
+                , fOutputPrimary(outputPrimary)
+                , fOutputSecondary(outputSecondary)
+                , fDstTextureSamplerHandle(dstTextureSamplerHandle)
+                , fDstTextureOrigin(dstTextureOrigin)
+                , fWriteSwizzle(writeSwizzle) {}
+        GrGLSLXPFragmentBuilder* fXPFragBuilder;
+        GrGLSLUniformHandler* fUniformHandler;
+        const GrShaderCaps* fShaderCaps;
+        const GrXferProcessor& fXP;
+        const char* fInputColor;
+        const char* fInputCoverage;
+        const char* fOutputPrimary;
+        const char* fOutputSecondary;
+        const SamplerHandle fDstTextureSamplerHandle;
+        GrSurfaceOrigin fDstTextureOrigin;
+        GrSwizzle fWriteSwizzle;
+    };
+    /**
+     * This is similar to emitCode() in the base class, except it takes a full shader builder.
+     * This allows the effect subclass to emit vertex code.
+     */
+    void emitCode(const EmitArgs&);
+
+    /** A ProgramImpl instance can be reused with any GrXferProcessor that produces the same key.
+        This function reads data from a GrXferProcessor and uploads any uniform variables required
+        by the shaders created in emitCode(). The GrXferProcessor parameter is guaranteed to be of
+        the same type that created this ProgramImpl and to have an identical processor key as the
+        one that created this ProgramImpl. This function calls onSetData on the subclass of
+        ProgramImpl.
+     */
+    void setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp);
+
+protected:
+    ProgramImpl() = default;
+
+    static void DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
+                                          const char* srcCoverage,
+                                          const char* dstColor,
+                                          const char* outColor,
+                                          const char* outColorSecondary,
+                                          const GrXferProcessor& proc);
+
+private:
+    /**
+     * Called by emitCode() when the XP will not be performing a dst read. This method is
+     * responsible for both blending and coverage. A subclass only needs to implement this method if
+     * it can construct a GrXferProcessor that will not read the dst color.
+     */
+    virtual void emitOutputsForBlendState(const EmitArgs&) {
+        SK_ABORT("emitOutputsForBlendState not implemented.");
+    }
+
+    /**
+     * Called by emitCode() when the XP will perform a dst read. This method only needs to supply
+     * the blending logic. The base class applies coverage. A subclass only needs to implement this
+     * method if it can construct a GrXferProcessor that reads the dst color.
+     */
+    virtual void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder*,
+                                         GrGLSLUniformHandler*,
+                                         const char* srcColor,
+                                         const char* srcCoverage,
+                                         const char* dstColor,
+                                         const char* outColor,
+                                         const char* outColorSecondary,
+                                         const GrXferProcessor&) {
+        SK_ABORT("emitBlendCodeForDstRead not implemented.");
+    }
+
+    virtual void emitWriteSwizzle(GrGLSLXPFragmentBuilder*,
+                                  const GrSwizzle&,
+                                  const char* outColor,
+                                  const char* outColorSecondary) const;
+
+    virtual void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) {}
+};
+
 #endif
diff --git a/src/gpu/d3d/GrD3DPipelineState.cpp b/src/gpu/d3d/GrD3DPipelineState.cpp
index a23b2f7..9db5ddf 100644
--- a/src/gpu/d3d/GrD3DPipelineState.cpp
+++ b/src/gpu/d3d/GrD3DPipelineState.cpp
@@ -8,17 +8,17 @@
 #include "src/gpu/d3d/GrD3DPipelineState.h"
 
 #include "include/private/SkTemplates.h"
+#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrProgramInfo.h"
 #include "src/gpu/GrStencilSettings.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/d3d/GrD3DBuffer.h"
 #include "src/gpu/d3d/GrD3DGpu.h"
 #include "src/gpu/d3d/GrD3DPipeline.h"
 #include "src/gpu/d3d/GrD3DRootSignature.h"
 #include "src/gpu/d3d/GrD3DTexture.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
 GrD3DPipelineState::GrD3DPipelineState(
         sk_sp<GrD3DPipeline> pipeline,
diff --git a/src/gpu/effects/GrAtlasedShaderHelpers.h b/src/gpu/effects/GrAtlasedShaderHelpers.h
index 960a57a..ec45610 100644
--- a/src/gpu/effects/GrAtlasedShaderHelpers.h
+++ b/src/gpu/effects/GrAtlasedShaderHelpers.h
@@ -11,7 +11,6 @@
 #include "src/gpu/GrDrawOpAtlas.h"
 #include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 3af009e..150992b 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -8,7 +8,6 @@
 #include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/effects/GrBezierEffect.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index a98a6e5..c193300 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -8,7 +8,7 @@
 #ifndef GrBicubicTextureEffect_DEFINED
 #define GrBicubicTextureEffect_DEFINED
 
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/GrFragmentProcessor.h"
 
 class GrInvariantOutput;
 
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 4961b8a..1603e8d 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -12,7 +12,6 @@
 #include "src/gpu/GrTexture.h"
 #include "src/gpu/effects/GrAtlasedShaderHelpers.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
@@ -70,7 +69,7 @@
         // Setup pass through color
         fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
         if (btgp.hasVertexColor()) {
-            varyingHandler->addPassThroughAttribute(btgp.fInColor, args.fOutputColor);
+            varyingHandler->addPassThroughAttribute(btgp.fInColor.asShaderVar(), args.fOutputColor);
         } else {
             this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
                                     &fColorUniform);
diff --git a/src/gpu/effects/GrBlendFragmentProcessor.cpp b/src/gpu/effects/GrBlendFragmentProcessor.cpp
index 833ade4..75defca 100644
--- a/src/gpu/effects/GrBlendFragmentProcessor.cpp
+++ b/src/gpu/effects/GrBlendFragmentProcessor.cpp
@@ -10,7 +10,6 @@
 #include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/glsl/GrGLSLBlend.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 
 // Some of the CPU implementations of blend modes differ from the GPU enough that
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index 9e1a44f..8a8fe39 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -7,7 +7,6 @@
 
 #include "src/core/SkPathPriv.h"
 #include "src/gpu/effects/GrConvexPolyEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp
index 64d7db0..9bf5bd4 100644
--- a/src/gpu/effects/GrCoverageSetOpXP.cpp
+++ b/src/gpu/effects/GrCoverageSetOpXP.cpp
@@ -5,15 +5,15 @@
  * found in the LICENSE file.
  */
 
+#include "src/gpu/effects/GrCoverageSetOpXP.h"
+
 #include "src/gpu/GrCaps.h"
 #include "src/gpu/GrColor.h"
 #include "src/gpu/GrPipeline.h"
-#include "src/gpu/GrProcessor.h"
-#include "src/gpu/effects/GrCoverageSetOpXP.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/glsl/GrGLSLBlend.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
 class CoverageSetOpXP : public GrXferProcessor {
 public:
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index 9ef3961..043485a 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -12,12 +12,11 @@
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/GrShaderCaps.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/glsl/GrGLSLBlend.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
 bool GrCustomXfermode::IsSupportedMode(SkBlendMode mode) {
     return (int)mode  > (int)SkBlendMode::kLastCoeffMode &&
diff --git a/src/gpu/effects/GrDisableColorXP.cpp b/src/gpu/effects/GrDisableColorXP.cpp
index d59e920..cab527e 100644
--- a/src/gpu/effects/GrDisableColorXP.cpp
+++ b/src/gpu/effects/GrDisableColorXP.cpp
@@ -5,13 +5,14 @@
  * found in the LICENSE file.
  */
 
+#include "src/gpu/effects/GrDisableColorXP.h"
+
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/GrShaderCaps.h"
-#include "src/gpu/effects/GrDisableColorXP.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
 /**
  * This xfer processor disables color writing. Thus color and coverage and ignored and no blending
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index e4f0e96..d125cc6 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -12,7 +12,6 @@
 #include "src/gpu/effects/GrAtlasedShaderHelpers.h"
 #include "src/gpu/effects/GrDistanceFieldGeoProc.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
@@ -78,7 +77,8 @@
 
         // Setup pass through color
         fragBuilder->codeAppendf("half4 %s;\n", args.fOutputColor);
-        varyingHandler->addPassThroughAttribute(dfTexEffect.fInColor, args.fOutputColor);
+        varyingHandler->addPassThroughAttribute(dfTexEffect.fInColor.asShaderVar(),
+                                                args.fOutputColor);
 
         // Setup position
         gpArgs->fPositionVar = dfTexEffect.fInPosition.asShaderVar();
@@ -366,7 +366,8 @@
 
         // setup pass through color
         fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-        varyingHandler->addPassThroughAttribute(dfPathEffect.fInColor, args.fOutputColor);
+        varyingHandler->addPassThroughAttribute(dfPathEffect.fInColor.asShaderVar(),
+                                                args.fOutputColor);
 
         if (dfPathEffect.fMatrix.hasPerspective()) {
             // Setup position (output position is transformed, local coords are pass through)
@@ -624,7 +625,8 @@
 
         // setup pass through color
         fragBuilder->codeAppendf("half4 %s;\n", args.fOutputColor);
-        varyingHandler->addPassThroughAttribute(dfTexEffect.fInColor, args.fOutputColor);
+        varyingHandler->addPassThroughAttribute(dfTexEffect.fInColor.asShaderVar(),
+                                                args.fOutputColor);
 
         // Setup position
         gpArgs->fPositionVar = dfTexEffect.fInPosition.asShaderVar();
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
index 755b372..ed4b5a5 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
@@ -11,7 +11,6 @@
 #include "src/gpu/GrTexture.h"
 #include "src/gpu/GrTextureProxy.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index ae16a49..ba8b973 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -15,7 +15,6 @@
 #include "src/gpu/GrThreadSafeCache.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/gpu/effects/GrMatrixEffect.cpp b/src/gpu/effects/GrMatrixEffect.cpp
index 8d2ad7b..5ba70ae 100644
--- a/src/gpu/effects/GrMatrixEffect.cpp
+++ b/src/gpu/effects/GrMatrixEffect.cpp
@@ -9,7 +9,6 @@
 
 #include "src/gpu/GrTexture.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 #include "src/sksl/SkSLUtil.h"
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 99dfad3..d9da5aa 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -19,7 +19,6 @@
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
 /**
  * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 03a651b..7b8258c 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -13,7 +13,6 @@
 #include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/effects/GrConvexPolyEffect.h"
 #include "src/gpu/effects/GrOvalEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/gpu/effects/GrShadowGeoProc.cpp b/src/gpu/effects/GrShadowGeoProc.cpp
index 3af4a84..4d2528f 100644
--- a/src/gpu/effects/GrShadowGeoProc.cpp
+++ b/src/gpu/effects/GrShadowGeoProc.cpp
@@ -9,7 +9,6 @@
 
 #include "src/gpu/GrSurfaceProxyView.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
@@ -30,11 +29,12 @@
         // emit attributes
         varyingHandler->emitAttributes(rsgp);
         fragBuilder->codeAppend("half3 shadowParams;");
-        varyingHandler->addPassThroughAttribute(rsgp.inShadowParams(), "shadowParams");
+        varyingHandler->addPassThroughAttribute(rsgp.inShadowParams().asShaderVar(),
+                                                "shadowParams");
 
         // setup pass through color
         fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-        varyingHandler->addPassThroughAttribute(rsgp.inColor(), args.fOutputColor);
+        varyingHandler->addPassThroughAttribute(rsgp.inColor().asShaderVar(), args.fOutputColor);
 
         // Setup position
         WriteOutputPosition(vertBuilder, gpArgs, rsgp.inPosition().name());
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index 3db9740..3239ec4 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -15,14 +15,12 @@
 #include "src/gpu/GrBaseContextPriv.h"
 #include "src/gpu/GrColorInfo.h"
 #include "src/gpu/GrTexture.h"
+#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 #include "src/sksl/SkSLUtil.h"
 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
 #include "src/sksl/ir/SkSLVarDeclarations.h"
 
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
-
 class GrSkSLFP::Impl : public ProgramImpl {
 public:
     void emitCode(EmitArgs& args) override {
diff --git a/src/gpu/effects/GrTextureEffect.h b/src/gpu/effects/GrTextureEffect.h
index 5b1c2d5..71c8040 100644
--- a/src/gpu/effects/GrTextureEffect.h
+++ b/src/gpu/effects/GrTextureEffect.h
@@ -12,7 +12,6 @@
 #include "include/core/SkMatrix.h"
 #include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrSurfaceProxyView.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 
 class GrTextureEffect : public GrFragmentProcessor {
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 69bb1ec..61abd4c 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -13,7 +13,6 @@
 #include "src/gpu/GrYUVATextureProxies.h"
 #include "src/gpu/effects/GrMatrixEffect.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 #include "src/sksl/SkSLUtil.h"
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index 9ee1b80..dbdac14 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -12,10 +12,10 @@
 #include "include/gpu/GrContextOptions.h"
 #include "include/gpu/GrDirectContext.h"
 #include "src/gpu/GrDirectContextPriv.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/GrProgramDesc.h"
 #include "src/gpu/gl/builders/GrGLProgramBuilder.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 
 struct GrGLGpu::ProgramCache::Entry {
     Entry(sk_sp<GrGLProgram> program)
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 6c43a18..b590d8c 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -7,6 +7,8 @@
 
 #include "src/gpu/gl/GrGLProgram.h"
 
+#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/GrProgramInfo.h"
@@ -15,9 +17,6 @@
 #include "src/gpu/effects/GrTextureEffect.h"
 #include "src/gpu/gl/GrGLBuffer.h"
 #include "src/gpu/gl/GrGLGpu.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 #include "src/sksl/SkSLCompiler.h"
 
 #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 3df3fe0..0a570f8 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -15,21 +15,21 @@
 #include "src/core/SkWriteBuffer.h"
 #include "src/gpu/GrAutoLocaleSetter.h"
 #include "src/gpu/GrDirectContextPriv.h"
+#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrPersistentCacheUtils.h"
 #include "src/gpu/GrProgramDesc.h"
 #include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/GrShaderUtils.h"
 #include "src/gpu/GrSwizzle.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/gl/GrGLGpu.h"
 #include "src/gpu/gl/GrGLProgram.h"
 #include "src/gpu/gl/builders/GrGLProgramBuilder.h"
 
 #include <memory>
 #include "src/gpu/gl/builders/GrGLShaderStringBuilder.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
deleted file mode 100644
index a9d4e81..0000000
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-
-#include "src/gpu/GrFragmentProcessor.h"
-#include "src/gpu/GrProcessor.h"
-#include "src/gpu/GrShaderCaps.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
-#include "src/gpu/glsl/GrGLSLUniformHandler.h"
-
-using ProgramImpl = GrFragmentProcessor::ProgramImpl;
-
-void ProgramImpl::setData(const GrGLSLProgramDataManager& pdman,
-                          const GrFragmentProcessor& processor) {
-    this->onSetData(pdman, processor);
-}
-
-void ProgramImpl::emitChildFunctions(EmitArgs& args) {
-    for (int i = 0; i < this->numChildProcessors(); ++i) {
-        ProgramImpl* childGLSLFP = this->childProcessor(i);
-        if (!childGLSLFP) {
-            continue;
-        }
-
-        const GrFragmentProcessor* childFP = args.fFp.childProcessor(i);
-        SkASSERT(childFP);
-
-        EmitArgs childArgs(args.fFragBuilder,
-                           args.fUniformHandler,
-                           args.fShaderCaps,
-                           *childFP,
-                           childFP->isBlendFunction() ? "_src" : "_input",
-                           "_dst",
-                           "_coords");
-        args.fFragBuilder->writeProcessorFunction(childGLSLFP, childArgs);
-    }
-}
-
-SkString ProgramImpl::invokeChild(int childIndex,
-                                  const char* inputColor,
-                                  const char* destColor,
-                                  EmitArgs& args,
-                                  SkSL::String skslCoords) {
-    SkASSERT(childIndex >= 0);
-
-    if (!inputColor) {
-        inputColor = args.fInputColor;
-    }
-
-    const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
-    if (!childProc) {
-        // If no child processor is provided, return the input color as-is.
-        return SkString(inputColor);
-    }
-
-    auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
-                                              inputColor);
-
-    if (childProc->isBlendFunction()) {
-        if (!destColor) {
-            destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
-        }
-        invocation.appendf(", %s", destColor);
-    }
-
-    // Assert that the child has no sample matrix. A uniform matrix sample call would go through
-    // invokeChildWithMatrix, not here.
-    SkASSERT(!childProc->sampleUsage().isUniformMatrix());
-
-    if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
-        SkASSERT(!childProc->sampleUsage().isFragCoord() || skslCoords == "sk_FragCoord.xy");
-        // The child's function takes a half4 color and a float2 coordinate
-        invocation.appendf(", %s", skslCoords.empty() ? args.fSampleCoord : skslCoords.c_str());
-    }
-
-    invocation.append(")");
-    return invocation;
-}
-
-SkString ProgramImpl::invokeChildWithMatrix(int childIndex,
-                                            const char* inputColor,
-                                            const char* destColor,
-                                            EmitArgs& args) {
-    SkASSERT(childIndex >= 0);
-
-    if (!inputColor) {
-        inputColor = args.fInputColor;
-    }
-
-    const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
-    if (!childProc) {
-        // If no child processor is provided, return the input color as-is.
-        return SkString(inputColor);
-    }
-
-    SkASSERT(childProc->sampleUsage().isUniformMatrix());
-
-    // Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
-    GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
-            args.fFp, SkString(SkSL::SampleUsage::MatrixUniformName()));
-    SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
-    const SkString& matrixName(uniform.getName());
-
-    auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
-                                              inputColor);
-
-    if (childProc->isBlendFunction()) {
-        if (!destColor) {
-            destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
-        }
-        invocation.appendf(", %s", destColor);
-    }
-
-    // Produce a string containing the call to the helper function. We have a uniform variable
-    // containing our transform (matrixName). If the parent coords were produced by uniform
-    // transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
-    // and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
-    // function signature will not take in coords.
-    //
-    // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
-    // the function.
-    if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
-        // Only check perspective for this specific matrix transform, not the aggregate FP property.
-        // Any parent perspective will have already been applied when evaluated in the FS.
-        if (childProc->sampleUsage().hasPerspective()) {
-            invocation.appendf(", proj((%s) * %s.xy1)", matrixName.c_str(), args.fSampleCoord);
-        } else if (args.fShaderCaps->nonsquareMatrixSupport()) {
-            invocation.appendf(", float3x2(%s) * %s.xy1", matrixName.c_str(), args.fSampleCoord);
-        } else {
-            invocation.appendf(", ((%s) * %s.xy1).xy", matrixName.c_str(), args.fSampleCoord);
-        }
-    }
-
-    invocation.append(")");
-    return invocation;
-}
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
deleted file mode 100644
index 8839702..0000000
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrGLSLFragmentProcessor_DEFINED
-#define GrGLSLFragmentProcessor_DEFINED
-
-#include "include/private/SkSLString.h"
-#include "src/gpu/GrFragmentProcessor.h"
-#include "src/gpu/GrShaderVar.h"
-#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
-#include "src/gpu/glsl/GrGLSLUniformHandler.h"
-
-class GrGLSLFPFragmentBuilder;
-
-class GrFragmentProcessor::ProgramImpl {
-public:
-    ProgramImpl() = default;
-
-    virtual ~ProgramImpl() = default;
-
-    using UniformHandle      = GrGLSLUniformHandler::UniformHandle;
-    using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
-
-    /** Called when the program stage should insert its code into the shaders. The code in each
-        shader will be in its own block ({}) and so locally scoped names will not collide across
-        stages.
-
-        @param fragBuilder       Interface used to emit code in the shaders.
-        @param uniformHandler    Interface used for accessing information about our uniforms
-        @param caps              The capabilities of the GPU which will render this FP
-        @param fp                The processor that generated this program stage.
-        @param inputColor        A half4 that holds the input color to the stage in the FS (or the
-                                 source color, for blend processors). nullptr inputs are converted
-                                 to "half4(1.0)" (solid white) during construction.
-                                 TODO: Better system for communicating optimization info
-                                 (e.g. input color is solid white, trans black, known to be opaque,
-                                 etc.) that allows the processor to communicate back similar known
-                                 info about its output.
-        @param destColor         A half4 that holds the dest color to the stage. Only meaningful
-                                 when the "is blend processor" FP flag is set.
-        @param sampleCoord       The name of a local coord reference to a float2 variable. Only
-                                 meaningful when the "references sample coords" FP flag is set.
-     */
-    struct EmitArgs {
-        EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
-                 GrGLSLUniformHandler* uniformHandler,
-                 const GrShaderCaps* caps,
-                 const GrFragmentProcessor& fp,
-                 const char* inputColor,
-                 const char* destColor,
-                 const char* sampleCoord)
-                : fFragBuilder(fragBuilder)
-                , fUniformHandler(uniformHandler)
-                , fShaderCaps(caps)
-                , fFp(fp)
-                , fInputColor(inputColor ? inputColor : "half4(1.0)")
-                , fDestColor(destColor)
-                , fSampleCoord(sampleCoord) {}
-        GrGLSLFPFragmentBuilder* fFragBuilder;
-        GrGLSLUniformHandler* fUniformHandler;
-        const GrShaderCaps* fShaderCaps;
-        const GrFragmentProcessor& fFp;
-        const char* fInputColor;
-        const char* fDestColor;
-        const char* fSampleCoord;
-    };
-
-    virtual void emitCode(EmitArgs&) = 0;
-
-    // This does not recurse to any attached child processors. Recursing the entire processor tree
-    // is the responsibility of the caller.
-    void setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor);
-
-    int numChildProcessors() const { return fChildProcessors.count(); }
-
-    ProgramImpl* childProcessor(int index) const { return fChildProcessors[index].get(); }
-
-    void setFunctionName(SkString name) {
-        SkASSERT(fFunctionName.isEmpty());
-        fFunctionName = std::move(name);
-    }
-
-    const char* functionName() const {
-        SkASSERT(!fFunctionName.isEmpty());
-        return fFunctionName.c_str();
-    }
-
-    void emitChildFunctions(EmitArgs& parentArgs);
-
-    // Invoke the child with the default input and destination colors (solid white)
-    inline SkString invokeChild(int childIndex, EmitArgs& parentArgs,
-                                SkSL::String skslCoords = "") {
-        return this->invokeChild(childIndex, /*inputColor=*/nullptr, /*destColor=*/nullptr,
-                                 parentArgs, skslCoords);
-    }
-
-    inline SkString invokeChildWithMatrix(int childIndex, EmitArgs& parentArgs) {
-        return this->invokeChildWithMatrix(childIndex, /*inputColor=*/nullptr,
-                                           /*destColor=*/nullptr, parentArgs);
-    }
-
-    // Invoke the child with the default destination color (solid white)
-    inline SkString invokeChild(int childIndex, const char* inputColor, EmitArgs& parentArgs,
-                                SkSL::String skslCoords = "") {
-        return this->invokeChild(childIndex, inputColor, /*destColor=*/nullptr, parentArgs,
-                                 skslCoords);
-    }
-
-    inline SkString invokeChildWithMatrix(int childIndex, const char* inputColor,
-                                          EmitArgs& parentArgs) {
-        return this->invokeChildWithMatrix(childIndex, inputColor, /*destColor=*/nullptr,
-                                           parentArgs);
-    }
-
-    /** Invokes a child proc in its own scope. Pass in the parent's EmitArgs and invokeChild will
-     *  automatically extract the coords and samplers of that child and pass them on to the child's
-     *  emitCode(). Also, any uniforms or functions emitted by the child will have their names
-     *  mangled to prevent redefinitions. The returned string contains the output color (as a call
-     *  to the child's helper function). It is legal to pass nullptr as inputColor, since all
-     *  fragment processors are required to work without an input color.
-     *
-     *  When skslCoords is empty, invokeChild corresponds to a call to "sample(child, color)"
-     *  in SkSL. When skslCoords is not empty, invokeChild corresponds to a call to
-     *  "sample(child, color, float2)", where skslCoords is an SkSL expression that evaluates to a
-     *  float2 and is passed in as the 3rd argument.
-     */
-    SkString invokeChild(int childIndex, const char* inputColor, const char* destColor,
-                         EmitArgs& parentArgs, SkSL::String skslCoords = "");
-
-    /**
-     * As invokeChild, but transforms the coordinates according to the matrix expression attached
-     * to the child's SampleUsage object. This is only valid if the child is sampled with a
-     * const-uniform matrix.
-     */
-    SkString invokeChildWithMatrix(int childIndex, const char* inputColor, const char* destColor,
-                                   EmitArgs& parentArgs);
-
-    /**
-     * Pre-order traversal of a GLSLFP hierarchy, or of multiple trees with roots in an array of
-     * GLSLFPS. If initialized with an array color followed by coverage processors installed in a
-     * program thenthe iteration order will agree with a GrFragmentProcessor::Iter initialized with
-     * a GrPipeline that produces the same program key.
-     */
-    class Iter {
-    public:
-        Iter(std::unique_ptr<ProgramImpl> fps[], int cnt);
-        Iter(ProgramImpl& fp) { fFPStack.push_back(&fp); }
-
-        ProgramImpl& operator*() const;
-        ProgramImpl* operator->() const;
-        Iter& operator++();
-        operator bool() const { return !fFPStack.empty(); }
-
-        // Because each iterator carries a stack we want to avoid copies.
-        Iter(const Iter&) = delete;
-        Iter& operator=(const Iter&) = delete;
-
-    private:
-        SkSTArray<4, ProgramImpl*, true> fFPStack;
-    };
-
-private:
-    /**
-     * A ProgramImpl instance can be reused with any GrFragmentProcessor that produces the same
-     * the same key; this function reads data from a GrFragmentProcessor and uploads any
-     * uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor
-     * parameter is guaranteed to be of the same type that created this ProgramImpl and
-     * to have an identical key as the one that created this ProgramImpl.
-     */
-    virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {}
-
-    // The (mangled) name of our entry-point function
-    SkString fFunctionName;
-
-    SkTArray<std::unique_ptr<ProgramImpl>, true> fChildProcessors;
-
-    friend class GrFragmentProcessor;
-};
-
-#endif
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index bfb0375..bfde859 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -9,8 +9,8 @@
 #define GrGLSLFragmentShaderBuilder_DEFINED
 
 #include "src/gpu/GrBlend.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrProcessor.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLShaderBuilder.h"
 
 class GrRenderTarget;
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
deleted file mode 100644
index 4111753..0000000
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
-
-#include "src/core/SkMatrixPriv.h"
-#include "src/gpu/GrPipeline.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
-#include "src/gpu/glsl/GrGLSLUniformHandler.h"
-#include "src/gpu/glsl/GrGLSLVarying.h"
-#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
-
-#include <queue>
-
-using ProgramImpl = GrGeometryProcessor::ProgramImpl;
-
-ProgramImpl::FPCoordsMap ProgramImpl::emitCode(EmitArgs& args, const GrPipeline& pipeline) {
-    GrGPArgs gpArgs;
-    this->onEmitCode(args, &gpArgs);
-
-    GrShaderVar positionVar = gpArgs.fPositionVar;
-    // skia:12198
-    if (args.fGeomProc.willUseGeoShader() || args.fGeomProc.willUseTessellationShaders()) {
-        positionVar = {};
-    }
-    FPCoordsMap transformMap = this->collectTransforms(args.fVertBuilder,
-                                                       args.fVaryingHandler,
-                                                       args.fUniformHandler,
-                                                       gpArgs.fLocalCoordVar,
-                                                       positionVar,
-                                                       pipeline);
-
-    if (args.fGeomProc.willUseTessellationShaders()) {
-        // Tessellation shaders are temporarily responsible for integrating their own code strings
-        // while we work out full support.
-        return transformMap;
-    }
-
-    GrGLSLVertexBuilder* vBuilder = args.fVertBuilder;
-    if (!args.fGeomProc.willUseGeoShader()) {
-        // Emit the vertex position to the hardware in the normalized window coordinates it expects.
-        SkASSERT(kFloat2_GrSLType == gpArgs.fPositionVar.getType() ||
-                 kFloat3_GrSLType == gpArgs.fPositionVar.getType());
-        vBuilder->emitNormalizedSkPosition(gpArgs.fPositionVar.c_str(),
-                                           gpArgs.fPositionVar.getType());
-        if (kFloat2_GrSLType == gpArgs.fPositionVar.getType()) {
-            args.fVaryingHandler->setNoPerspective();
-        }
-    } else {
-        // Since we have a geometry shader, leave the vertex position in Skia device space for now.
-        // The geometry Shader will operate in device space, and then convert the final positions to
-        // normalized hardware window coordinates under the hood, once everything else has finished.
-        // The subclass must call setNoPerspective on the varying handler, if applicable.
-        vBuilder->codeAppendf("sk_Position = float4(%s", gpArgs.fPositionVar.c_str());
-        switch (gpArgs.fPositionVar.getType()) {
-            case kFloat_GrSLType:
-                vBuilder->codeAppend(", 0");
-                [[fallthrough]];
-            case kFloat2_GrSLType:
-                vBuilder->codeAppend(", 0");
-                [[fallthrough]];
-            case kFloat3_GrSLType:
-                vBuilder->codeAppend(", 1");
-                [[fallthrough]];
-            case kFloat4_GrSLType:
-                vBuilder->codeAppend(");");
-                break;
-            default:
-                SK_ABORT("Invalid position var type");
-                break;
-        }
-    }
-    return transformMap;
-}
-
-ProgramImpl::FPCoordsMap ProgramImpl::collectTransforms(GrGLSLVertexBuilder* vb,
-                                                        GrGLSLVaryingHandler* varyingHandler,
-                                                        GrGLSLUniformHandler* uniformHandler,
-                                                        const GrShaderVar& localCoordsVar,
-                                                        const GrShaderVar& positionVar,
-                                                        const GrPipeline& pipeline) {
-    SkASSERT(localCoordsVar.getType() == kFloat2_GrSLType ||
-             localCoordsVar.getType() == kFloat3_GrSLType ||
-             localCoordsVar.getType() == kVoid_GrSLType);
-    SkASSERT(positionVar.getType() == kFloat2_GrSLType ||
-             positionVar.getType() == kFloat3_GrSLType ||
-             positionVar.getType() == kVoid_GrSLType);
-
-    enum class BaseCoord { kNone, kLocal, kPosition };
-
-    auto baseLocalCoordFSVar = [&, baseLocalCoord = GrGLSLVarying()]() mutable {
-        SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType()));
-        if (baseLocalCoord.type() == kVoid_GrSLType) {
-            // Initialize to the GP provided coordinate
-            baseLocalCoord = GrGLSLVarying(localCoordsVar.getType());
-            varyingHandler->addVarying("LocalCoord", &baseLocalCoord);
-            vb->codeAppendf("%s = %s;\n", baseLocalCoord.vsOut(), localCoordsVar.getName().c_str());
-        }
-        return baseLocalCoord.fsInVar();
-    };
-
-    bool canUsePosition = positionVar.getType() != kVoid_GrSLType;
-
-    FPCoordsMap result;
-    // Performs a pre-order traversal of FP hierarchy rooted at fp and identifies FPs that are
-    // sampled with a series of matrices applied to local coords. For each such FP a varying is
-    // added to the varying handler and added to 'result'.
-    auto liftTransforms = [&, traversalIndex = 0](
-                                  auto& self,
-                                  const GrFragmentProcessor& fp,
-                                  bool hasPerspective,
-                                  const GrFragmentProcessor* lastMatrixFP = nullptr,
-                                  int lastMatrixTraversalIndex = -1,
-                                  BaseCoord baseCoord = BaseCoord::kLocal) mutable -> void {
-        ++traversalIndex;
-        switch (fp.sampleUsage().kind()) {
-            case SkSL::SampleUsage::Kind::kNone:
-                // This should only happen at the root. Otherwise how did this FP get added?
-                SkASSERT(!fp.parent());
-                break;
-            case SkSL::SampleUsage::Kind::kPassThrough:
-                break;
-            case SkSL::SampleUsage::Kind::kUniformMatrix:
-                // Update tracking of last matrix and matrix props.
-                hasPerspective |= fp.sampleUsage().hasPerspective();
-                lastMatrixFP = &fp;
-                lastMatrixTraversalIndex = traversalIndex;
-                break;
-            case SkSL::SampleUsage::Kind::kFragCoord:
-                hasPerspective = positionVar.getType() == kFloat3_GrSLType;
-                lastMatrixFP = nullptr;
-                lastMatrixTraversalIndex = -1;
-                baseCoord = BaseCoord::kPosition;
-                break;
-            case SkSL::SampleUsage::Kind::kExplicit:
-                baseCoord = BaseCoord::kNone;
-                break;
-        }
-
-        auto& [varyingFSVar, hasCoordsParam] = result[&fp];
-        hasCoordsParam = fp.usesSampleCoordsDirectly();
-
-        // We add a varying if we're in a chain of matrices multiplied by local or device coords.
-        // If the coord is the untransformed local coord we add a varying. We don't if it is
-        // untransformed device coords since it doesn't save us anything over "sk_FragCoord.xy". Of
-        // course, if the FP doesn't directly use its coords then we don't add a varying.
-        if (fp.usesSampleCoordsDirectly() &&
-            (baseCoord == BaseCoord::kLocal ||
-             (baseCoord == BaseCoord::kPosition && lastMatrixFP && canUsePosition))) {
-            // Associate the varying with the highest possible node in the FP tree that shares the
-            // same coordinates so that multiple FPs in a subtree can share. If there are no matrix
-            // sample nodes on the way up the tree then directly use the local coord.
-            if (!lastMatrixFP) {
-                varyingFSVar = baseLocalCoordFSVar();
-            } else {
-                // If there is an already a varying that incorporates all matrices from the root to
-                // lastMatrixFP just use it. Otherwise, we add it.
-                auto& [varying, inputCoords, varyingIdx] = fTransformVaryingsMap[lastMatrixFP];
-                if (varying.type() == kVoid_GrSLType) {
-                    varying = GrGLSLVarying(hasPerspective ? kFloat3_GrSLType : kFloat2_GrSLType);
-                    SkString strVaryingName = SkStringPrintf("TransformedCoords_%d",
-                                                             lastMatrixTraversalIndex);
-                    varyingHandler->addVarying(strVaryingName.c_str(), &varying);
-                    inputCoords = baseCoord == BaseCoord::kLocal ? localCoordsVar : positionVar;
-                    varyingIdx = lastMatrixTraversalIndex;
-                }
-                SkASSERT(varyingIdx == lastMatrixTraversalIndex);
-                // The FP will use the varying in the fragment shader as its coords.
-                varyingFSVar = varying.fsInVar();
-            }
-            hasCoordsParam = false;
-        }
-
-        for (int c = 0; c < fp.numChildProcessors(); ++c) {
-            if (auto* child = fp.childProcessor(c)) {
-                self(self,
-                     *child,
-                     hasPerspective,
-                     lastMatrixFP,
-                     lastMatrixTraversalIndex,
-                     baseCoord);
-                // If we have a varying then we never need a param. Otherwise, if one of our
-                // children takes a non-explicit coord then we'll need our coord.
-                hasCoordsParam |= varyingFSVar.getType() == kVoid_GrSLType &&
-                                  !child->sampleUsage().isExplicit()       &&
-                                  !child->sampleUsage().isFragCoord()      &&
-                                  result[child].hasCoordsParam;
-            }
-        }
-    };
-
-    bool hasPerspective = GrSLTypeVecLength(localCoordsVar.getType()) == 3;
-    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
-        liftTransforms(liftTransforms, pipeline.getFragmentProcessor(i), hasPerspective);
-    }
-    return result;
-}
-
-void ProgramImpl::emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler) {
-    // Because descendant varyings may be computed using the varyings of ancestor FPs we make
-    // sure to visit the varyings according to FP pre-order traversal by dumping them into a
-    // priority queue.
-    using FPAndInfo = std::tuple<const GrFragmentProcessor*, TransformInfo>;
-    auto compare = [](const FPAndInfo& a, const FPAndInfo& b) {
-        return std::get<1>(a).traversalOrder > std::get<1>(b).traversalOrder;
-    };
-    std::priority_queue<FPAndInfo, std::vector<FPAndInfo>, decltype(compare)> pq(compare);
-    std::for_each(fTransformVaryingsMap.begin(), fTransformVaryingsMap.end(), [&pq](auto entry) {
-        pq.push(entry);
-    });
-    for (; !pq.empty(); pq.pop()) {
-        const auto& [fp, info] = pq.top();
-        // If we recorded a transform info, its sample matrix must be uniform
-        SkASSERT(fp->sampleUsage().isUniformMatrix());
-        GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
-                *fp->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
-        // Start with this matrix and accumulate additional matrices as we walk up the FP tree
-        // to either the base coords or an ancestor FP that has an associated varying.
-        SkString transformExpression = uniform.getName();
-
-        // If we hit an ancestor with a varying on our walk up then save off the varying as the
-        // input to our accumulated transformExpression. Start off assuming we'll reach the root.
-        GrShaderVar inputCoords = info.inputCoords;
-
-        for (const auto* base = fp->parent(); base; base = base->parent()) {
-            if (auto iter = fTransformVaryingsMap.find(base); iter != fTransformVaryingsMap.end()) {
-                // Can stop here, as this varying already holds all transforms from higher FPs
-                // We'll apply the residual transformExpression we've accumulated up from our
-                // starting FP to this varying.
-                inputCoords = iter->second.varying.vsOutVar();
-                break;
-            } else if (base->sampleUsage().isUniformMatrix()) {
-                // Accumulate any matrices along the path to either the original local/device coords
-                // or a parent varying. Getting here means this FP was sampled with a uniform matrix
-                // but all uses of coords below here in the FP hierarchy are beneath additional
-                // matrix samples and thus this node wasn't assigned a varying.
-                GrShaderVar parentUniform = uniformHandler->liftUniformToVertexShader(
-                        *base->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
-                transformExpression.appendf(" * %s", parentUniform.getName().c_str());
-            } else if (base->sampleUsage().isFragCoord()) {
-                // Our chain of matrices starts here and is based on the device space position.
-                break;
-            } else {
-                // This intermediate FP is just a pass through and doesn't need to be built
-                // in to the expression, but we must visit its parents in case they add transforms.
-                SkASSERT(base->sampleUsage().isPassThrough() || !base->sampleUsage().isSampled());
-            }
-        }
-
-        SkString inputStr;
-        if (inputCoords.getType() == kFloat2_GrSLType) {
-            inputStr = SkStringPrintf("%s.xy1", inputCoords.getName().c_str());
-        } else {
-            SkASSERT(inputCoords.getType() == kFloat3_GrSLType);
-            inputStr = inputCoords.getName();
-        }
-
-        vb->codeAppend("{\n");
-        if (info.varying.type() == kFloat2_GrSLType) {
-            if (vb->getProgramBuilder()->shaderCaps()->nonsquareMatrixSupport()) {
-                vb->codeAppendf("%s = float3x2(%s) * %s", info.varying.vsOut(),
-                                                          transformExpression.c_str(),
-                                                          inputStr.c_str());
-            } else {
-                vb->codeAppendf("%s = (%s * %s).xy", info.varying.vsOut(),
-                                                     transformExpression.c_str(),
-                                                     inputStr.c_str());
-            }
-        } else {
-            SkASSERT(info.varying.type() == kFloat3_GrSLType);
-            vb->codeAppendf("%s = %s * %s", info.varying.vsOut(),
-                                            transformExpression.c_str(),
-                                            inputStr.c_str());
-        }
-        vb->codeAppend(";\n");
-        vb->codeAppend("}\n");
-    }
-    // We don't need this map anymore.
-    fTransformVaryingsMap.clear();
-}
-
-void ProgramImpl::setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
-                                    GrGLSLUniformHandler* uniformHandler,
-                                    const char* outputName,
-                                    UniformHandle* colorUniform) {
-    SkASSERT(colorUniform);
-    const char* stagedLocalVarName;
-    *colorUniform = uniformHandler->addUniform(nullptr,
-                                               kFragment_GrShaderFlag,
-                                               kHalf4_GrSLType,
-                                               "Color",
-                                               &stagedLocalVarName);
-    fragBuilder->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
-    if (fragBuilder->getProgramBuilder()->shaderCaps()->mustObfuscateUniformColor()) {
-        fragBuilder->codeAppendf("%s = max(%s, half4(0));", outputName, outputName);
-    }
-}
-
-void ProgramImpl::SetTransform(const GrGLSLProgramDataManager& pdman,
-                               const GrShaderCaps& shaderCaps,
-                               const UniformHandle& uniform,
-                               const SkMatrix& matrix,
-                               SkMatrix* state) {
-    if (!uniform.isValid() || (state && SkMatrixPriv::CheapEqual(*state, matrix))) {
-        // No update needed
-        return;
-    }
-    if (state) {
-        *state = matrix;
-    }
-    if (matrix.isScaleTranslate() && !shaderCaps.reducedShaderMode()) {
-        // ComputeMatrixKey and writeX() assume the uniform is a float4 (can't assert since nothing
-        // is exposed on a handle, but should be caught lower down).
-        float values[4] = {matrix.getScaleX(), matrix.getTranslateX(),
-                           matrix.getScaleY(), matrix.getTranslateY()};
-        pdman.set4fv(uniform, 1, values);
-    } else {
-        pdman.setSkMatrix(uniform, matrix);
-    }
-}
-
-static void write_passthrough_vertex_position(GrGLSLVertexBuilder* vertBuilder,
-                                              const GrShaderVar& inPos,
-                                              GrShaderVar* outPos) {
-    SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType);
-    SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
-    outPos->set(inPos.getType(), outName.c_str());
-    vertBuilder->codeAppendf("float%d %s = %s;",
-                             GrSLTypeVecLength(inPos.getType()),
-                             outName.c_str(),
-                             inPos.getName().c_str());
-}
-
-static void write_vertex_position(GrGLSLVertexBuilder* vertBuilder,
-                                  GrGLSLUniformHandler* uniformHandler,
-                                  const GrShaderCaps& shaderCaps,
-                                  const GrShaderVar& inPos,
-                                  const SkMatrix& matrix,
-                                  const char* matrixName,
-                                  GrShaderVar* outPos,
-                                  ProgramImpl::UniformHandle* matrixUniform) {
-    SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType);
-    SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
-
-    if (matrix.isIdentity() && !shaderCaps.reducedShaderMode()) {
-        write_passthrough_vertex_position(vertBuilder, inPos, outPos);
-        return;
-    }
-    SkASSERT(matrixUniform);
-
-    bool useCompactTransform = matrix.isScaleTranslate() && !shaderCaps.reducedShaderMode();
-    const char* mangledMatrixName;
-    *matrixUniform = uniformHandler->addUniform(nullptr,
-                                                kVertex_GrShaderFlag,
-                                                useCompactTransform ? kFloat4_GrSLType
-                                                                    : kFloat3x3_GrSLType,
-                                                matrixName,
-                                                &mangledMatrixName);
-
-    if (inPos.getType() == kFloat3_GrSLType) {
-        // A float3 stays a float3 whether or not the matrix adds perspective
-        if (useCompactTransform) {
-            vertBuilder->codeAppendf("float3 %s = %s.xz1 * %s + %s.yw0;\n",
-                                     outName.c_str(),
-                                     mangledMatrixName,
-                                     inPos.getName().c_str(),
-                                     mangledMatrixName);
-        } else {
-            vertBuilder->codeAppendf("float3 %s = %s * %s;\n",
-                                     outName.c_str(),
-                                     mangledMatrixName,
-                                     inPos.getName().c_str());
-        }
-        outPos->set(kFloat3_GrSLType, outName.c_str());
-        return;
-    }
-    if (matrix.hasPerspective()) {
-        // A float2 is promoted to a float3 if we add perspective via the matrix
-        SkASSERT(!useCompactTransform);
-        vertBuilder->codeAppendf("float3 %s = (%s * %s.xy1);",
-                                 outName.c_str(),
-                                 mangledMatrixName,
-                                 inPos.getName().c_str());
-        outPos->set(kFloat3_GrSLType, outName.c_str());
-        return;
-    }
-    if (useCompactTransform) {
-        vertBuilder->codeAppendf("float2 %s = %s.xz * %s + %s.yw;\n",
-                                 outName.c_str(),
-                                 mangledMatrixName,
-                                 inPos.getName().c_str(),
-                                 mangledMatrixName);
-    } else if (shaderCaps.nonsquareMatrixSupport()) {
-        vertBuilder->codeAppendf("float2 %s = float3x2(%s) * %s.xy1;\n",
-                                 outName.c_str(),
-                                 mangledMatrixName,
-                                 inPos.getName().c_str());
-    } else {
-        vertBuilder->codeAppendf("float2 %s = (%s * %s.xy1).xy;\n",
-                                 outName.c_str(),
-                                 mangledMatrixName,
-                                 inPos.getName().c_str());
-    }
-    outPos->set(kFloat2_GrSLType, outName.c_str());
-}
-
-void ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
-                                      GrGPArgs* gpArgs,
-                                      const char* posName) {
-    // writeOutputPosition assumes the incoming pos name points to a float2 variable
-    GrShaderVar inPos(posName, kFloat2_GrSLType);
-    write_passthrough_vertex_position(vertBuilder, inPos, &gpArgs->fPositionVar);
-}
-
-void ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
-                                      GrGLSLUniformHandler* uniformHandler,
-                                      const GrShaderCaps& shaderCaps,
-                                      GrGPArgs* gpArgs,
-                                      const char* posName,
-                                      const SkMatrix& mat,
-                                      UniformHandle* viewMatrixUniform) {
-    GrShaderVar inPos(posName, kFloat2_GrSLType);
-    write_vertex_position(vertBuilder,
-                          uniformHandler,
-                          shaderCaps,
-                          inPos,
-                          mat,
-                          "viewMatrix",
-                          &gpArgs->fPositionVar,
-                          viewMatrixUniform);
-}
-
-void ProgramImpl::WriteLocalCoord(GrGLSLVertexBuilder* vertBuilder,
-                                  GrGLSLUniformHandler* uniformHandler,
-                                  const GrShaderCaps& shaderCaps,
-                                  GrGPArgs* gpArgs,
-                                  GrShaderVar localVar,
-                                  const SkMatrix& localMatrix,
-                                  UniformHandle* localMatrixUniform) {
-    write_vertex_position(vertBuilder,
-                          uniformHandler,
-                          shaderCaps,
-                          localVar,
-                          localMatrix,
-                          "localMatrix",
-                          &gpArgs->fLocalCoordVar,
-                          localMatrixUniform);
-}
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.h b/src/gpu/glsl/GrGLSLGeometryProcessor.h
deleted file mode 100644
index 8e1b96f..0000000
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrGLSLGeometryProcessor_DEFINED
-#define GrGLSLGeometryProcessor_DEFINED
-
-#include "src/gpu/GrFragmentProcessor.h"
-#include "src/gpu/GrGeometryProcessor.h"
-#include "src/gpu/GrShaderCaps.h"
-#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
-#include "src/gpu/glsl/GrGLSLUniformHandler.h"
-#include "src/gpu/glsl/GrGLSLVarying.h"
-
-#include <unordered_map>
-
-class GrGeometryProcessor;
-class GrGLSLFPFragmentBuilder;
-class GrGLSLGeometryBuilder;
-class GrGLSLVaryingHandler;
-class GrGLSLVertexBuilder;
-class GrShaderCaps;
-
-class GrGeometryProcessor::ProgramImpl {
-public:
-    using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
-    using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
-    /**
-     * Struct of optional varying that replaces the input coords and bool indicating whether the FP
-     * should take a coord param as an argument. The latter may be false if the coords are simply
-     * unused or if the GP has lifted their computation to a varying emitted by the VS.
-     */
-    struct FPCoords {GrShaderVar coordsVarying; bool hasCoordsParam;};
-    using FPCoordsMap = std::unordered_map<const GrFragmentProcessor*, FPCoords>;
-
-    virtual ~ProgramImpl() = default;
-
-    struct EmitArgs {
-        EmitArgs(GrGLSLVertexBuilder* vertBuilder,
-                 GrGLSLGeometryBuilder* geomBuilder,
-                 GrGLSLFPFragmentBuilder* fragBuilder,
-                 GrGLSLVaryingHandler* varyingHandler,
-                 GrGLSLUniformHandler* uniformHandler,
-                 const GrShaderCaps* caps,
-                 const GrGeometryProcessor& geomProc,
-                 const char* outputColor,
-                 const char* outputCoverage,
-                 const SamplerHandle* texSamplers)
-                : fVertBuilder(vertBuilder)
-                , fGeomBuilder(geomBuilder)
-                , fFragBuilder(fragBuilder)
-                , fVaryingHandler(varyingHandler)
-                , fUniformHandler(uniformHandler)
-                , fShaderCaps(caps)
-                , fGeomProc(geomProc)
-                , fOutputColor(outputColor)
-                , fOutputCoverage(outputCoverage)
-                , fTexSamplers(texSamplers) {}
-        GrGLSLVertexBuilder* fVertBuilder;
-        GrGLSLGeometryBuilder* fGeomBuilder;
-        GrGLSLFPFragmentBuilder* fFragBuilder;
-        GrGLSLVaryingHandler* fVaryingHandler;
-        GrGLSLUniformHandler* fUniformHandler;
-        const GrShaderCaps* fShaderCaps;
-        const GrGeometryProcessor& fGeomProc;
-        const char* fOutputColor;
-        const char* fOutputCoverage;
-        const SamplerHandle* fTexSamplers;
-    };
-
-    /**
-     * Emits the code from this geometry processor into the shaders. For any FP in the pipeline that
-     * has its input coords implemented by the GP as a varying, the varying will be accessible in
-     * the returned map and should be used when the FP code is emitted.
-     **/
-    FPCoordsMap emitCode(EmitArgs&, const GrPipeline& pipeline);
-
-    /**
-     * Called after all effect emitCode() functions, to give the processor a chance to write out
-     * additional transformation code now that all uniforms have been emitted.
-     * It generates the final code for assigning transformed coordinates to the varyings recorded
-     * in the call to collectTransforms(). This must happen after FP code emission so that it has
-     * access to any uniforms the FPs registered for uniform sample matrix invocations.
-     */
-    void emitTransformCode(GrGLSLVertexBuilder* vb,
-                           GrGLSLUniformHandler* uniformHandler);
-
-    /**
-     * A ProgramImpl instance can be reused with any GrGeometryProcessor that produces the same key.
-     * This function reads data from a GrGeometryProcessor and updates any uniform variables
-     * required by the shaders created in emitCode(). The GrGeometryProcessor parameter is
-     * guaranteed to be of the same type and to have an identical processor key as the
-     * GrGeometryProcessor that created this ProgramImpl.
-     */
-    virtual void setData(const GrGLSLProgramDataManager&,
-                         const GrShaderCaps&,
-                         const GrGeometryProcessor&) = 0;
-
-    // We use these methods as a temporary back door to inject OpenGL tessellation code. Once
-    // tessellation is supported by SkSL we can remove these.
-    virtual SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
-                                              const char* versionAndExtensionDecls,
-                                              const GrGLSLUniformHandler&,
-                                              const GrShaderCaps&) const {
-        SK_ABORT("Not implemented.");
-    }
-    virtual SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
-                                                 const char* versionAndExtensionDecls,
-                                                 const GrGLSLUniformHandler&,
-                                                 const GrShaderCaps&) const {
-        SK_ABORT("Not implemented.");
-    }
-
-    // GPs that use writeOutputPosition and/or writeLocalCoord must incorporate the matrix type
-    // into their key, and should use this function or one of the other related helpers.
-    static uint32_t ComputeMatrixKey(const GrShaderCaps& caps, const SkMatrix& mat) {
-        if (!caps.reducedShaderMode()) {
-            if (mat.isIdentity()) {
-                return 0b00;
-            }
-            if (mat.isScaleTranslate()) {
-                return 0b01;
-            }
-        }
-        if (!mat.hasPerspective()) {
-            return 0b10;
-        }
-        return 0b11;
-    }
-
-    static uint32_t ComputeMatrixKeys(const GrShaderCaps& shaderCaps,
-                                      const SkMatrix& viewMatrix,
-                                      const SkMatrix& localMatrix) {
-        return (ComputeMatrixKey(shaderCaps, viewMatrix ) << kMatrixKeyBits) |
-                ComputeMatrixKey(shaderCaps, localMatrix);
-    }
-
-    static uint32_t AddMatrixKeys(const GrShaderCaps& shaderCaps,
-                                  uint32_t flags,
-                                  const SkMatrix& viewMatrix,
-                                  const SkMatrix& localMatrix) {
-        // Shifting to make room for the matrix keys shouldn't lose bits
-        SkASSERT(((flags << (2 * kMatrixKeyBits)) >> (2 * kMatrixKeyBits)) == flags);
-        return (flags << (2 * kMatrixKeyBits)) |
-               ComputeMatrixKeys(shaderCaps, viewMatrix, localMatrix);
-    }
-    static constexpr int kMatrixKeyBits = 2;
-
-protected:
-    void setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
-                           GrGLSLUniformHandler* uniformHandler,
-                           const char* outputName,
-                           UniformHandle* colorUniform);
-
-    // A helper for setting the matrix on a uniform handle initialized through
-    // writeOutputPosition or writeLocalCoord. Automatically handles elided uniforms,
-    // scale+translate matrices, and state tracking (if provided state pointer is non-null).
-    static void SetTransform(const GrGLSLProgramDataManager&,
-                             const GrShaderCaps&,
-                             const UniformHandle& uniform,
-                             const SkMatrix& matrix,
-                             SkMatrix* state = nullptr);
-
-    struct GrGPArgs {
-        // Used to specify the output variable used by the GP to store its device position. It can
-        // either be a float2 or a float3 (in order to handle perspective). The subclass sets this
-        // in its onEmitCode().
-        GrShaderVar fPositionVar;
-        // Used to specify the variable storing the draw's local coordinates. It can be either a
-        // float2, float3, or void. It can only be void when no FP needs local coordinates. This
-        // variable can be an attribute or local variable, but should not itself be a varying.
-        // ProgramImpl automatically determines if this must be passed to a FS.
-        GrShaderVar fLocalCoordVar;
-    };
-
-    // Helpers for adding code to write the transformed vertex position. The first simple version
-    // just writes a variable named by 'posName' into the position output variable with the
-    // assumption that the position is 2D. The second version transforms the input position by a
-    // view matrix and the output variable is 2D or 3D depending on whether the view matrix is
-    // perspective. Both versions declare the output position variable and will set
-    // GrGPArgs::fPositionVar.
-    static void WriteOutputPosition(GrGLSLVertexBuilder*, GrGPArgs*, const char* posName);
-    static void WriteOutputPosition(GrGLSLVertexBuilder*,
-                                    GrGLSLUniformHandler*,
-                                    const GrShaderCaps&,
-                                    GrGPArgs*,
-                                    const char* posName,
-                                    const SkMatrix& viewMatrix,
-                                    UniformHandle* viewMatrixUniform);
-
-    // Helper to transform an existing variable by a given local matrix (e.g. the inverse view
-    // matrix). It will declare the transformed local coord variable and will set
-    // GrGPArgs::fLocalCoordVar.
-    static void WriteLocalCoord(GrGLSLVertexBuilder*,
-                                GrGLSLUniformHandler*,
-                                const GrShaderCaps&,
-                                GrGPArgs*,
-                                GrShaderVar localVar,
-                                const SkMatrix& localMatrix,
-                                UniformHandle* localMatrixUniform);
-
-private:
-    virtual void onEmitCode(EmitArgs&, GrGPArgs*) = 0;
-
-    // Iterates over the FPs beginning with the passed iter to register additional varyings and
-    // uniforms to support VS-promoted local coord evaluation for the FPs.
-    //
-    // This must happen before FP code emission so that the FPs can find the appropriate varying
-    // handles they use in place of explicit coord sampling; it is automatically called after
-    // onEmitCode() returns using the value stored in GpArgs::fLocalCoordVar and
-    // GpArgs::fPositionVar.
-    FPCoordsMap collectTransforms(GrGLSLVertexBuilder* vb,
-                                  GrGLSLVaryingHandler* varyingHandler,
-                                  GrGLSLUniformHandler* uniformHandler,
-                                  const GrShaderVar& localCoordsVar,
-                                  const GrShaderVar& positionVar,
-                                  const GrPipeline& pipeline);
-    struct TransformInfo {
-        // The varying that conveys the coordinates to one or more FPs in the FS.
-        GrGLSLVarying varying;
-        // The coordinate to be transformed. varying is computed from this.
-        GrShaderVar   inputCoords;
-        // Used to sort so that ancestor FP varyings are initialized before descendant FP varyings.
-        int           traversalOrder;
-    };
-    // Populated by collectTransforms() for use in emitTransformCode(). When we lift the computation
-    // of a FP's input coord to a varying we propagate that varying up the FP tree to the highest
-    // node that shares the same coordinates. This allows multiple FPs in a subtree to share a
-    // varying.
-    std::unordered_map<const GrFragmentProcessor*, TransformInfo> fTransformVaryingsMap;
-};
-
-#endif
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index c9cbc93..8a75f0a 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -10,15 +10,15 @@
 #include <memory>
 
 #include "src/gpu/GrCaps.h"
+#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrRenderTarget.h"
 #include "src/gpu/GrShaderCaps.h"
 #include "src/gpu/GrTexture.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 #include "src/sksl/SkSLCompiler.h"
 #include "src/sksl/dsl/priv/DSLFPs.h"
 
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index a0c1d30..fba0236 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -9,15 +9,14 @@
 #define GrGLSLProgramBuilder_DEFINED
 
 #include "src/gpu/GrCaps.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrProgramInfo.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 #include "src/sksl/SkSLCompiler.h"
 
 #include <vector>
diff --git a/src/gpu/glsl/GrGLSLVarying.cpp b/src/gpu/glsl/GrGLSLVarying.cpp
index 4670fcc..a334d63 100644
--- a/src/gpu/glsl/GrGLSLVarying.cpp
+++ b/src/gpu/glsl/GrGLSLVarying.cpp
@@ -9,14 +9,14 @@
 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 
-void GrGLSLVaryingHandler::addPassThroughAttribute(const GrGeometryProcessor::Attribute& input,
+void GrGLSLVaryingHandler::addPassThroughAttribute(const GrShaderVar& vsVar,
                                                    const char* output,
                                                    Interpolation interpolation) {
-    SkASSERT(input.isInitialized());
+    SkASSERT(vsVar.getType() != kVoid_GrSLType);
     SkASSERT(!fProgramBuilder->geometryProcessor().willUseGeoShader());
-    GrGLSLVarying v(input.gpuType());
-    this->addVarying(input.name(), &v, interpolation);
-    fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), input.name());
+    GrGLSLVarying v(vsVar.getType());
+    this->addVarying(vsVar.c_str(), &v, interpolation);
+    fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), vsVar.c_str());
     fProgramBuilder->fFS.codeAppendf("%s = %s;", output, v.fsIn());
 }
 
diff --git a/src/gpu/glsl/GrGLSLVarying.h b/src/gpu/glsl/GrGLSLVarying.h
index 5a489e7..148a651 100644
--- a/src/gpu/glsl/GrGLSLVarying.h
+++ b/src/gpu/glsl/GrGLSLVarying.h
@@ -9,11 +9,11 @@
 #define GrGLSLVarying_DEFINED
 
 #include "include/private/GrTypesPriv.h"
-#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrShaderVar.h"
 #include "src/gpu/GrTBlockList.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 
+class GrGeometryProcessor;
 class GrGLSLProgramBuilder;
 
 #ifdef SK_DEBUG
@@ -104,7 +104,7 @@
 
     virtual ~GrGLSLVaryingHandler() {}
 
-    /*
+    /**
      * Notifies the varying handler that this shader will never emit geometry in perspective and
      * therefore does not require perspective-correct interpolation. When supported, this allows
      * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for
@@ -118,7 +118,7 @@
         kMustBeFlat // Use "flat" even if it is known to be slow.
     };
 
-    /*
+    /**
      * addVarying allows fine grained control for setting up varyings between stages. Calling this
      * function will make sure all necessary decls are setup for the client. The client however is
      * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an
@@ -129,15 +129,15 @@
     void addVarying(const char* name, GrGLSLVarying* varying,
                     Interpolation = Interpolation::kInterpolated);
 
-    /*
-     * The GP can use these calls to pass an attribute through all shaders directly to 'output' in
-     * the fragment shader.  Though these calls affect both the vertex shader and fragment shader,
-     * they expect 'output' to be defined in the fragment shader before the call is made. If there
-     * is a geometry shader, we will simply take the value of the varying from the first vertex and
-     * that will be set as the output varying for all emitted vertices.
+    /**
+     * The GP can use these calls to pass a vertex shader variable directly to 'output' in the
+     * fragment shader. Though this adds code to vertex and fragment stages, 'output' is expected to
+     * be defined in the fragment shader before the call is made. This cannot be used with a
+     * geometry shader.
      * TODO it might be nicer behavior to have a flag to declare output inside these calls
      */
-    void addPassThroughAttribute(const GrGeometryProcessor::Attribute&, const char* output,
+    void addPassThroughAttribute(const GrShaderVar& vsVar,
+                                 const char* output,
                                  Interpolation = Interpolation::kInterpolated);
 
     void emitAttributes(const GrGeometryProcessor&);
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.cpp b/src/gpu/glsl/GrGLSLXferProcessor.cpp
deleted file mode 100644
index c981232..0000000
--- a/src/gpu/glsl/GrGLSLXferProcessor.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
-
-#include "src/gpu/GrShaderCaps.h"
-#include "src/gpu/GrTexture.h"
-#include "src/gpu/GrXferProcessor.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
-#include "src/gpu/glsl/GrGLSLUniformHandler.h"
-
-using ProgramImpl = GrXferProcessor::ProgramImpl;
-
-// This is only called for cases where we are doing LCD coverage and not using in shader blending.
-// For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha
-// coverage since src alpha will always be greater than or equal to dst alpha.
-static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder,
-                                    const char* srcCoverage,
-                                    const GrXferProcessor& proc) {
-    if (srcCoverage && proc.isLCD()) {
-        fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);",
-                                 srcCoverage, srcCoverage, srcCoverage, srcCoverage);
-    }
-}
-
-void ProgramImpl::emitCode(const EmitArgs& args) {
-    if (!args.fXP.willReadDstColor()) {
-        adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP);
-        this->emitOutputsForBlendState(args);
-    } else {
-        GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
-        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
-        const char* dstColor = fragBuilder->dstColor();
-
-        bool needsLocalOutColor = false;
-
-        if (args.fDstTextureSamplerHandle.isValid()) {
-            if (args.fInputCoverage) {
-                // We don't think any shaders actually output negative coverage, but just as a
-                // safety check for floating point precision errors, we compare with <= here. We
-                // just check the RGB values of the coverage, since the alpha may not have been set
-                // when using LCD. If we are using single-channel coverage, alpha will be equal to
-                // RGB anyway.
-                //
-                // The discard here also helps for batching text-draws together, which need to read
-                // from a dst copy for blends. However, this only helps the case where the outer
-                // bounding boxes of each letter overlap and not two actually parts of the text.
-                fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {"
-                                         "    discard;"
-                                         "}", args.fInputCoverage);
-            }
-        } else {
-            needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch();
-        }
-
-        const char* outColor = "_localColorOut";
-        if (!needsLocalOutColor) {
-            outColor = args.fOutputPrimary;
-        } else {
-            fragBuilder->codeAppendf("half4 %s;", outColor);
-        }
-
-        this->emitBlendCodeForDstRead(fragBuilder,
-                                      uniformHandler,
-                                      args.fInputColor,
-                                      args.fInputCoverage,
-                                      dstColor,
-                                      outColor,
-                                      args.fOutputSecondary,
-                                      args.fXP);
-        if (needsLocalOutColor) {
-            fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor);
-        }
-    }
-
-    // Swizzle the fragment shader outputs if necessary.
-    this->emitWriteSwizzle(args.fXPFragBuilder, args.fWriteSwizzle, args.fOutputPrimary,
-                           args.fOutputSecondary);
-}
-
-void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x,
-                                   const GrSwizzle& swizzle,
-                                   const char* outColor,
-                                   const char* outColorSecondary) const {
-    if (GrSwizzle::RGBA() != swizzle) {
-        x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str());
-        if (outColorSecondary) {
-            x->codeAppendf("%s = %s.%s;", outColorSecondary, outColorSecondary,
-                           swizzle.asString().c_str());
-        }
-    }
-}
-
-void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
-    this->onSetData(pdm, xp);
-}
-
-void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
-                                            const char* srcCoverage,
-                                            const char* dstColor,
-                                            const char* outColor,
-                                            const char* outColorSecondary,
-                                            const GrXferProcessor& proc) {
-    if (srcCoverage) {
-        if (proc.isLCD()) {
-            fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);",
-                                     dstColor, outColor, srcCoverage);
-        }
-        fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;",
-                                 outColor, srcCoverage, outColor, srcCoverage, dstColor);
-        if (proc.isLCD()) {
-            fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor);
-        }
-    }
-}
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.h b/src/gpu/glsl/GrGLSLXferProcessor.h
deleted file mode 100644
index f063440..0000000
--- a/src/gpu/glsl/GrGLSLXferProcessor.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrGLSLXferProcessor_DEFINED
-#define GrGLSLXferProcessor_DEFINED
-
-#include "include/core/SkPoint.h"
-#include "src/gpu/GrXferProcessor.h"
-#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
-#include "src/gpu/glsl/GrGLSLUniformHandler.h"
-
-class GrXferProcessor;
-class GrGLSLXPFragmentBuilder;
-class GrShaderCaps;
-class GrTexture;
-
-class GrXferProcessor::ProgramImpl {
-public:
-    virtual ~ProgramImpl() = default;
-
-    using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
-
-    struct EmitArgs {
-        EmitArgs(GrGLSLXPFragmentBuilder* fragBuilder,
-                 GrGLSLUniformHandler* uniformHandler,
-                 const GrShaderCaps* caps,
-                 const GrXferProcessor& xp,
-                 const char* inputColor,
-                 const char* inputCoverage,
-                 const char* outputPrimary,
-                 const char* outputSecondary,
-                 const SamplerHandle dstTextureSamplerHandle,
-                 GrSurfaceOrigin dstTextureOrigin,
-                 const GrSwizzle& writeSwizzle)
-                : fXPFragBuilder(fragBuilder)
-                , fUniformHandler(uniformHandler)
-                , fShaderCaps(caps)
-                , fXP(xp)
-                , fInputColor(inputColor ? inputColor : "half4(1.0)")
-                , fInputCoverage(inputCoverage)
-                , fOutputPrimary(outputPrimary)
-                , fOutputSecondary(outputSecondary)
-                , fDstTextureSamplerHandle(dstTextureSamplerHandle)
-                , fDstTextureOrigin(dstTextureOrigin)
-                , fWriteSwizzle(writeSwizzle) {}
-        GrGLSLXPFragmentBuilder* fXPFragBuilder;
-        GrGLSLUniformHandler* fUniformHandler;
-        const GrShaderCaps* fShaderCaps;
-        const GrXferProcessor& fXP;
-        const char* fInputColor;
-        const char* fInputCoverage;
-        const char* fOutputPrimary;
-        const char* fOutputSecondary;
-        const SamplerHandle fDstTextureSamplerHandle;
-        GrSurfaceOrigin fDstTextureOrigin;
-        GrSwizzle fWriteSwizzle;
-    };
-    /**
-     * This is similar to emitCode() in the base class, except it takes a full shader builder.
-     * This allows the effect subclass to emit vertex code.
-     */
-    void emitCode(const EmitArgs&);
-
-    /** A ProgramImpl instance can be reused with any GrXferProcessor that produces the same key.
-        This function reads data from a GrXferProcessor and uploads any uniform variables required
-        by the shaders created in emitCode(). The GrXferProcessor parameter is guaranteed to be of
-        the same type that created this ProgramImpl and to have an identical processor key as the
-        one that created this ProgramImpl. This function calls onSetData on the subclass of
-        ProgramImpl.
-     */
-    void setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp);
-
-protected:
-    ProgramImpl() = default;
-
-    static void DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
-                                          const char* srcCoverage,
-                                          const char* dstColor,
-                                          const char* outColor,
-                                          const char* outColorSecondary,
-                                          const GrXferProcessor& proc);
-
-private:
-    /**
-     * Called by emitCode() when the XP will not be performing a dst read. This method is
-     * responsible for both blending and coverage. A subclass only needs to implement this method if
-     * it can construct a GrXferProcessor that will not read the dst color.
-     */
-    virtual void emitOutputsForBlendState(const EmitArgs&) {
-        SK_ABORT("emitOutputsForBlendState not implemented.");
-    }
-
-    /**
-     * Called by emitCode() when the XP will perform a dst read. This method only needs to supply
-     * the blending logic. The base class applies coverage. A subclass only needs to implement this
-     * method if it can construct a GrXferProcessor that reads the dst color.
-     */
-    virtual void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder*,
-                                         GrGLSLUniformHandler*,
-                                         const char* srcColor,
-                                         const char* srcCoverage,
-                                         const char* dstColor,
-                                         const char* outColor,
-                                         const char* outColorSecondary,
-                                         const GrXferProcessor&) {
-        SK_ABORT("emitBlendCodeForDstRead not implemented.");
-    }
-
-    virtual void emitWriteSwizzle(GrGLSLXPFragmentBuilder*,
-                                  const GrSwizzle&,
-                                  const char* outColor,
-                                  const char* outColorSecondary) const;
-
-    virtual void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) {}
-};
-#endif
diff --git a/src/gpu/mtl/GrMtlPipelineState.mm b/src/gpu/mtl/GrMtlPipelineState.mm
index cb371fe..fd581d4 100644
--- a/src/gpu/mtl/GrMtlPipelineState.mm
+++ b/src/gpu/mtl/GrMtlPipelineState.mm
@@ -8,13 +8,12 @@
 #include "src/gpu/mtl/GrMtlPipelineState.h"
 
 #include "src/gpu/GrBackendUtils.h"
-#include "src/gpu/GrPipeline.h"
+#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrRenderTarget.h"
 #include "src/gpu/GrTexture.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 #include "src/gpu/mtl/GrMtlBuffer.h"
 #include "src/gpu/mtl/GrMtlFramebuffer.h"
 #include "src/gpu/mtl/GrMtlGpu.h"
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp
index 58d5bd2..9b98913 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -21,7 +21,6 @@
 #include "src/gpu/geometry/GrPathUtils.h"
 #include "src/gpu/geometry/GrStyledShape.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
@@ -624,7 +623,7 @@
 
             // Setup pass through color
             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-            varyingHandler->addPassThroughAttribute(qe.fInColor, args.fOutputColor);
+            varyingHandler->addPassThroughAttribute(qe.fInColor.asShaderVar(), args.fOutputColor);
 
             // Setup position
             WriteOutputPosition(vertBuilder, gpArgs, qe.fInPosition.name());
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
index 7576d58..9a48f83 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -21,7 +21,6 @@
 #include "src/gpu/GrVertexWriter.h"
 #include "src/gpu/geometry/GrPathUtils.h"
 #include "src/gpu/geometry/GrStyledShape.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/ops/GrAAConvexTessellator.h"
 #include "src/gpu/ops/GrAALinearizingConvexPathRenderer.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
diff --git a/src/gpu/ops/GrAtlasInstancedHelper.h b/src/gpu/ops/GrAtlasInstancedHelper.h
index 8a20934..b7ca2de 100644
--- a/src/gpu/ops/GrAtlasInstancedHelper.h
+++ b/src/gpu/ops/GrAtlasInstancedHelper.h
@@ -11,7 +11,6 @@
 #include "src/core/SkIPoint16.h"
 #include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrSurfaceProxyView.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 
 struct GrVertexWriter;
diff --git a/src/gpu/ops/GrDashOp.cpp b/src/gpu/ops/GrDashOp.cpp
index 72ecaf6..86d2433 100644
--- a/src/gpu/ops/GrDashOp.cpp
+++ b/src/gpu/ops/GrDashOp.cpp
@@ -23,7 +23,6 @@
 #include "src/gpu/SkGr.h"
 #include "src/gpu/geometry/GrQuad.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
diff --git a/src/gpu/ops/GrDrawAtlasPathOp.cpp b/src/gpu/ops/GrDrawAtlasPathOp.cpp
index fc4c2fb..eb5b74b 100644
--- a/src/gpu/ops/GrDrawAtlasPathOp.cpp
+++ b/src/gpu/ops/GrDrawAtlasPathOp.cpp
@@ -7,13 +7,13 @@
 
 #include "src/gpu/ops/GrDrawAtlasPathOp.h"
 
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrOpsRenderPass.h"
 #include "src/gpu/GrProgramInfo.h"
 #include "src/gpu/GrResourceProvider.h"
 #include "src/gpu/GrVertexWriter.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 
@@ -104,7 +104,8 @@
 
         args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
         args.fVaryingHandler->addPassThroughAttribute(
-                shader.fAttribs[shader.colorAttribIdx()], args.fOutputColor,
+                shader.fAttribs[shader.colorAttribIdx()].asShaderVar(),
+                args.fOutputColor,
                 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
     }
 
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index 1eea29a..894fc40 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -5,22 +5,23 @@
  * found in the LICENSE file.
  */
 
+#include "src/gpu/ops/GrDrawVerticesOp.h"
+
 #include "include/core/SkM44.h"
 #include "include/effects/SkRuntimeEffect.h"
 #include "src/core/SkArenaAlloc.h"
 #include "src/core/SkDevice.h"
 #include "src/core/SkMatrixPriv.h"
 #include "src/core/SkVerticesPriv.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrProgramInfo.h"
 #include "src/gpu/GrVertexWriter.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
-#include "src/gpu/ops/GrDrawVerticesOp.h"
 #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
 
 namespace {
diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h
index bd5cfa3..bd9e304 100644
--- a/src/gpu/ops/GrDrawVerticesOp.h
+++ b/src/gpu/ops/GrDrawVerticesOp.h
@@ -10,6 +10,7 @@
 
 #include "include/core/SkRefCnt.h"
 #include "include/private/GrTypesPriv.h"
+#include "src/gpu/ops/GrOp.h"
 
 class GrColorSpaceXform;
 class GrDrawOp;
diff --git a/src/gpu/ops/GrFillRRectOp.cpp b/src/gpu/ops/GrFillRRectOp.cpp
index eab0c8e..5464a8e 100644
--- a/src/gpu/ops/GrFillRRectOp.cpp
+++ b/src/gpu/ops/GrFillRRectOp.cpp
@@ -10,6 +10,7 @@
 #include "include/gpu/GrRecordingContext.h"
 #include "src/core/SkRRectPriv.h"
 #include "src/gpu/GrCaps.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrMemoryPool.h"
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrOpsRenderPass.h"
@@ -20,7 +21,6 @@
 #include "src/gpu/GrVx.h"
 #include "src/gpu/geometry/GrShape.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
@@ -585,7 +585,8 @@
         GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
         varyings->emitAttributes(proc);
         f->codeAppendf("half4 %s;", args.fOutputColor);
-        varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
+        varyings->addPassThroughAttribute(proc.fColorAttrib->asShaderVar(),
+                                          args.fOutputColor,
                                           GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
 
         // Emit the vertex shader.
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index b8ab4a3..8d9ecc5 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -19,7 +19,6 @@
 #include "src/gpu/geometry/GrQuadBuffer.h"
 #include "src/gpu/geometry/GrQuadUtils.h"
 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
 #include "src/gpu/ops/GrQuadPerEdgeAA.h"
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index 91138dc..5e5e956 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -5,11 +5,14 @@
  * found in the LICENSE file.
  */
 
+#include "src/gpu/ops/GrLatticeOp.h"
+
 #include "include/core/SkBitmap.h"
 #include "include/core/SkRect.h"
 #include "src/core/SkLatticeIter.h"
 #include "src/core/SkMatrixPriv.h"
 #include "src/gpu/GrDrawOpTest.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrGpu.h"
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrProgramInfo.h"
@@ -19,9 +22,7 @@
 #include "src/gpu/SkGr.h"
 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
-#include "src/gpu/ops/GrLatticeOp.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
 #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
 
@@ -67,13 +68,16 @@
                 gpArgs->fLocalCoordVar = latticeGP.fInTextureCoords.asShaderVar();
 
                 args.fFragBuilder->codeAppend("float2 textureCoords;");
-                args.fVaryingHandler->addPassThroughAttribute(latticeGP.fInTextureCoords,
-                                                              "textureCoords");
+                args.fVaryingHandler->addPassThroughAttribute(
+                        latticeGP.fInTextureCoords.asShaderVar(),
+                        "textureCoords");
                 args.fFragBuilder->codeAppend("float4 textureDomain;");
                 args.fVaryingHandler->addPassThroughAttribute(
-                        latticeGP.fInTextureDomain, "textureDomain", Interpolation::kCanBeFlat);
+                        latticeGP.fInTextureDomain.asShaderVar(),
+                        "textureDomain",
+                        Interpolation::kCanBeFlat);
                 args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-                args.fVaryingHandler->addPassThroughAttribute(latticeGP.fInColor,
+                args.fVaryingHandler->addPassThroughAttribute(latticeGP.fInColor.asShaderVar(),
                                                               args.fOutputColor,
                                                               Interpolation::kCanBeFlat);
                 args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
diff --git a/src/gpu/ops/GrLatticeOp.h b/src/gpu/ops/GrLatticeOp.h
index 9bceccf..559dbb0 100644
--- a/src/gpu/ops/GrLatticeOp.h
+++ b/src/gpu/ops/GrLatticeOp.h
@@ -11,6 +11,7 @@
 #include <memory>
 #include "include/core/SkRefCnt.h"
 #include "src/gpu/GrSamplerState.h"
+#include "src/gpu/ops/GrOp.h"
 
 class GrColorSpaceXform;
 class GrDrawOp;
diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp
index a43a452..1c7cee1 100644
--- a/src/gpu/ops/GrOvalOpFactory.cpp
+++ b/src/gpu/ops/GrOvalOpFactory.cpp
@@ -19,7 +19,6 @@
 #include "src/gpu/GrStyle.h"
 #include "src/gpu/GrVertexWriter.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
@@ -141,24 +140,28 @@
             // emit attributes
             varyingHandler->emitAttributes(cgp);
             fragBuilder->codeAppend("float4 circleEdge;");
-            varyingHandler->addPassThroughAttribute(cgp.fInCircleEdge, "circleEdge");
+            varyingHandler->addPassThroughAttribute(cgp.fInCircleEdge.asShaderVar(), "circleEdge");
             if (cgp.fInClipPlane.isInitialized()) {
                 fragBuilder->codeAppend("half3 clipPlane;");
-                varyingHandler->addPassThroughAttribute(cgp.fInClipPlane, "clipPlane");
+                varyingHandler->addPassThroughAttribute(cgp.fInClipPlane.asShaderVar(),
+                                                        "clipPlane");
             }
             if (cgp.fInIsectPlane.isInitialized()) {
                 fragBuilder->codeAppend("half3 isectPlane;");
-                varyingHandler->addPassThroughAttribute(cgp.fInIsectPlane, "isectPlane");
+                varyingHandler->addPassThroughAttribute(cgp.fInIsectPlane.asShaderVar(),
+                                                        "isectPlane");
             }
             if (cgp.fInUnionPlane.isInitialized()) {
                 SkASSERT(cgp.fInClipPlane.isInitialized());
                 fragBuilder->codeAppend("half3 unionPlane;");
-                varyingHandler->addPassThroughAttribute(cgp.fInUnionPlane, "unionPlane");
+                varyingHandler->addPassThroughAttribute(cgp.fInUnionPlane.asShaderVar(),
+                                                        "unionPlane");
             }
             GrGLSLVarying capRadius(kFloat_GrSLType);
             if (cgp.fInRoundCapCenters.isInitialized()) {
                 fragBuilder->codeAppend("float4 roundCapCenters;");
-                varyingHandler->addPassThroughAttribute(cgp.fInRoundCapCenters, "roundCapCenters");
+                varyingHandler->addPassThroughAttribute(cgp.fInRoundCapCenters.asShaderVar(),
+                                                        "roundCapCenters");
                 varyingHandler->addVarying("capRadius", &capRadius,
                                            GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
                 // This is the cap radius in normalized space where the outer radius is 1 and
@@ -169,7 +172,7 @@
 
             // setup pass through color
             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-            varyingHandler->addPassThroughAttribute(cgp.fInColor, args.fOutputColor);
+            varyingHandler->addPassThroughAttribute(cgp.fInColor.asShaderVar(), args.fOutputColor);
 
             // Setup position
             WriteOutputPosition(vertBuilder, gpArgs, cgp.fInPosition.name());
@@ -318,11 +321,13 @@
             // emit attributes
             varyingHandler->emitAttributes(bcscgp);
             fragBuilder->codeAppend("float4 circleEdge;");
-            varyingHandler->addPassThroughAttribute(bcscgp.fInCircleEdge, "circleEdge");
+            varyingHandler->addPassThroughAttribute(bcscgp.fInCircleEdge.asShaderVar(),
+                                                    "circleEdge");
 
             fragBuilder->codeAppend("float4 dashParams;");
             varyingHandler->addPassThroughAttribute(
-                    bcscgp.fInDashParams, "dashParams",
+                    bcscgp.fInDashParams.asShaderVar(),
+                    "dashParams",
                     GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
             GrGLSLVarying wrapDashes(kHalf4_GrSLType);
             varyingHandler->addVarying("wrapDashes", &wrapDashes,
@@ -393,7 +398,8 @@
             // setup pass through color
             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
             varyingHandler->addPassThroughAttribute(
-                    bcscgp.fInColor, args.fOutputColor,
+                    bcscgp.fInColor.asShaderVar(),
+                    args.fOutputColor,
                     GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
 
             // Setup position
@@ -587,7 +593,7 @@
             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
             // setup pass through color
             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-            varyingHandler->addPassThroughAttribute(egp.fInColor, args.fOutputColor);
+            varyingHandler->addPassThroughAttribute(egp.fInColor.asShaderVar(), args.fOutputColor);
 
             // Setup position
             WriteOutputPosition(vertBuilder, gpArgs, egp.fInPosition.name());
@@ -785,7 +791,8 @@
 
             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-            varyingHandler->addPassThroughAttribute(diegp.fInColor, args.fOutputColor);
+            varyingHandler->addPassThroughAttribute(diegp.fInColor.asShaderVar(),
+                                                    args.fOutputColor);
 
             // Setup position
             WriteOutputPosition(vertBuilder,
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index e95663c..6e62009 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -14,7 +14,6 @@
 #include "src/gpu/geometry/GrQuadUtils.h"
 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 
@@ -650,9 +649,12 @@
                     SkASSERT(gp.fCoverageMode != CoverageMode::kWithColor || !gp.fNeedsPerspective);
                     // The color cannot be flat if the varying coverage has been modulated into it
                     args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
-                    args.fVaryingHandler->addPassThroughAttribute(gp.fColor, args.fOutputColor,
-                            gp.fCoverageMode == CoverageMode::kWithColor ?
-                            Interpolation::kInterpolated : Interpolation::kCanBeFlat);
+                    args.fVaryingHandler->addPassThroughAttribute(
+                            gp.fColor.asShaderVar(),
+                            args.fOutputColor,
+                            gp.fCoverageMode == CoverageMode::kWithColor
+                                    ? Interpolation::kInterpolated
+                                    : Interpolation::kCanBeFlat);
                     blendDst = args.fOutputColor;
                 } else {
                     // Output color must be initialized to something
@@ -675,13 +677,15 @@
                         args.fFragBuilder->codeAppendf("texCoord = %s.xy / %s.z;",
                                                        v.fsIn(), v.fsIn());
                     } else {
-                        args.fVaryingHandler->addPassThroughAttribute(gp.fLocalCoord, "texCoord");
+                        args.fVaryingHandler->addPassThroughAttribute(gp.fLocalCoord.asShaderVar(),
+                                                                      "texCoord");
                     }
 
                     // Clamp the now 2D localCoordName variable by the subset if it is provided
                     if (gp.fTexSubset.isInitialized()) {
                         args.fFragBuilder->codeAppend("float4 subset;");
-                        args.fVaryingHandler->addPassThroughAttribute(gp.fTexSubset, "subset",
+                        args.fVaryingHandler->addPassThroughAttribute(gp.fTexSubset.asShaderVar(),
+                                                                      "subset",
                                                                       Interpolation::kCanBeFlat);
                         args.fFragBuilder->codeAppend(
                                 "texCoord = clamp(texCoord, subset.LT, subset.RB);");
@@ -726,8 +730,9 @@
                         // coverage. This only has to be done in the exterior triangles, the
                         // interior of the quad geometry can never be clipped by the subset box.
                         args.fFragBuilder->codeAppend("float4 geoSubset;");
-                        args.fVaryingHandler->addPassThroughAttribute(gp.fGeomSubset, "geoSubset",
-                                        Interpolation::kCanBeFlat);
+                        args.fVaryingHandler->addPassThroughAttribute(gp.fGeomSubset.asShaderVar(),
+                                                                      "geoSubset",
+                                                                      Interpolation::kCanBeFlat);
 #ifdef SK_USE_LEGACY_AA_QUAD_SUBSET
                         args.fFragBuilder->codeAppend(
                                 "if (coverage < 0.5) {"
diff --git a/src/gpu/tessellate/shaders/GrPathTessellationShader.h b/src/gpu/tessellate/shaders/GrPathTessellationShader.h
index 1563419..9c5d5a7 100644
--- a/src/gpu/tessellate/shaders/GrPathTessellationShader.h
+++ b/src/gpu/tessellate/shaders/GrPathTessellationShader.h
@@ -8,7 +8,6 @@
 #ifndef GrPathTessellationShader_DEFINED
 #define GrPathTessellationShader_DEFINED
 
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
 #include "src/gpu/tessellate/shaders/GrTessellationShader.h"
 
diff --git a/src/gpu/tessellate/shaders/GrPathTessellationShader_Hardware.cpp b/src/gpu/tessellate/shaders/GrPathTessellationShader_Hardware.cpp
index d5b234d..5f2b75e 100644
--- a/src/gpu/tessellate/shaders/GrPathTessellationShader_Hardware.cpp
+++ b/src/gpu/tessellate/shaders/GrPathTessellationShader_Hardware.cpp
@@ -8,7 +8,6 @@
 #include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
 
 #include "src/gpu/geometry/GrWangsFormula.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 
 namespace {
diff --git a/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp b/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp
index 510631b..20dc354 100644
--- a/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp
+++ b/src/gpu/tessellate/shaders/GrStrokeTessellationShader.cpp
@@ -8,7 +8,6 @@
 #include "src/gpu/tessellate/shaders/GrStrokeTessellationShader.h"
 
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 #include "src/gpu/tessellate/GrStrokeTessellator.h"
diff --git a/src/gpu/tessellate/shaders/GrStrokeTessellationShader.h b/src/gpu/tessellate/shaders/GrStrokeTessellationShader.h
index e58e8c5..88a6880 100644
--- a/src/gpu/tessellate/shaders/GrStrokeTessellationShader.h
+++ b/src/gpu/tessellate/shaders/GrStrokeTessellationShader.h
@@ -12,7 +12,6 @@
 
 #include "include/core/SkStrokeRec.h"
 #include "src/gpu/GrVx.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
 
diff --git a/src/gpu/tessellate/shaders/GrStrokeTessellationShader_InstancedImpl.cpp b/src/gpu/tessellate/shaders/GrStrokeTessellationShader_InstancedImpl.cpp
index 42081f0..dd82e90 100644
--- a/src/gpu/tessellate/shaders/GrStrokeTessellationShader_InstancedImpl.cpp
+++ b/src/gpu/tessellate/shaders/GrStrokeTessellationShader_InstancedImpl.cpp
@@ -9,7 +9,6 @@
 
 #include "src/gpu/geometry/GrWangsFormula.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 
 void GrStrokeTessellationShader::InstancedImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 6ca5279..199853b 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -8,13 +8,13 @@
 #include "src/gpu/vk/GrVkPipelineState.h"
 
 #include "src/core/SkMipmap.h"
+#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrRenderTarget.h"
 #include "src/gpu/GrTexture.h"
+#include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
-#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 #include "src/gpu/vk/GrVkBuffer.h"
 #include "src/gpu/vk/GrVkCommandBuffer.h"
 #include "src/gpu/vk/GrVkDescriptorPool.h"
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
index f051ff6..ce0499d 100644
--- a/src/gpu/vk/GrVkPipelineStateCache.cpp
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -5,15 +5,14 @@
  * found in the LICENSE file.
  */
 
-
 #include "include/gpu/GrContextOptions.h"
 #include "include/gpu/GrDirectContext.h"
 #include "src/core/SkOpts.h"
 #include "src/gpu/GrDirectContextPriv.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/GrRenderTarget.h"
 #include "src/gpu/GrStencilSettings.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/vk/GrVkGpu.h"
 #include "src/gpu/vk/GrVkPipelineState.h"
diff --git a/src/shaders/SkPerlinNoiseShader.cpp b/src/shaders/SkPerlinNoiseShader.cpp
index 516d185..6ae6041 100644
--- a/src/shaders/SkPerlinNoiseShader.cpp
+++ b/src/shaders/SkPerlinNoiseShader.cpp
@@ -21,11 +21,11 @@
 
 #if SK_SUPPORT_GPU
 #include "include/gpu/GrRecordingContext.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrRecordingContextPriv.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/effects/GrMatrixEffect.h"
 #include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
diff --git a/src/sksl/dsl/priv/DSLFPs.h b/src/sksl/dsl/priv/DSLFPs.h
index 372e921..3fa801d 100644
--- a/src/sksl/dsl/priv/DSLFPs.h
+++ b/src/sksl/dsl/priv/DSLFPs.h
@@ -12,7 +12,7 @@
 
 #if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
 
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/GrFragmentProcessor.h"
 
 namespace SkSL {
 
diff --git a/src/sksl/dsl/priv/DSLWriter.h b/src/sksl/dsl/priv/DSLWriter.h
index ae79be6..56b1db3 100644
--- a/src/sksl/dsl/priv/DSLWriter.h
+++ b/src/sksl/dsl/priv/DSLWriter.h
@@ -20,7 +20,7 @@
 #include "src/sksl/ir/SkSLExpressionStatement.h"
 #include "src/sksl/ir/SkSLProgram.h"
 #if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/GrFragmentProcessor.h"
 #endif // !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
 #include <list>
 #include <stack>