Remove GrCoordTransform entirely

Bug: skia:10416
Change-Id: I0ca7535a0e6507e6b2a9f4682788826972c5f3b8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300296
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 9a40c93..8a0f765 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -71,7 +71,6 @@
   "$_src/gpu/GrContextThreadSafeProxy.cpp",
   "$_src/gpu/GrContextThreadSafeProxyPriv.h",
   "$_src/gpu/GrContext_Base.cpp",
-  "$_src/gpu/GrCoordTransform.h",
   "$_src/gpu/GrCopyRenderTask.cpp",
   "$_src/gpu/GrCopyRenderTask.h",
   "$_src/gpu/GrCpuBuffer.h",
diff --git a/src/gpu/GrCoordTransform.h b/src/gpu/GrCoordTransform.h
deleted file mode 100644
index 85cdf2e..0000000
--- a/src/gpu/GrCoordTransform.h
+++ /dev/null
@@ -1,22 +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 GrCoordTransform_DEFINED
-#define GrCoordTransform_DEFINED
-
-#include "include/core/SkMatrix.h"
-
-/**
- * A class representing a linear transformation of local coordinates. GrFragnentProcessors
- * these transformations, and the GrGeometryProcessor implements the transformation.
- */
-class GrCoordTransform {
-public:
-    GrCoordTransform() = default;
-};
-
-#endif
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index a37206b..c16014c 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -5,7 +5,6 @@
 * found in the LICENSE file.
 */
 
-#include "src/gpu/GrCoordTransform.h"
 #include "src/gpu/GrFragmentProcessor.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrProcessorAnalysis.h"
@@ -30,8 +29,7 @@
             return false;
         }
     }
-    if (this->numCoordTransforms() != that.numCoordTransforms()) {
-        // FPs have either 0 or 1 coord transform, and if they have 1, it's the identity
+    if (this->usesVaryingCoordsDirectly() != that.usesVaryingCoordsDirectly()) {
         return false;
     }
     if (!this->onIsEqual(that)) {
@@ -69,25 +67,6 @@
     return this->onTextureSampler(i);
 }
 
-int GrFragmentProcessor::numCoordTransforms() const {
-    if (SkToBool(fFlags & kUsesSampleCoordsDirectly_Flag) && !this->isSampledWithExplicitCoords()) {
-        // coordTransform(0) will return an implicitly defined coord transform so that varyings are
-        // added for this FP in order to support uniform sample matrix lifting.
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
-const GrCoordTransform& GrFragmentProcessor::coordTransform(int i) const {
-    SkASSERT(i == 0 && SkToBool(fFlags & kUsesSampleCoordsDirectly_Flag) &&
-             !this->isSampledWithExplicitCoords());
-    // as things stand, matrices only work when there's a coord transform, so we need to add
-    // an identity transform to keep the downstream code happy
-    static const GrCoordTransform kImplicitIdentity;
-    return kImplicitIdentity;
-}
-
 void GrFragmentProcessor::addAndPushFlagToChildren(PrivateFlags flag) {
     // This propagates down, so if we've already marked it, all our children should have it too
     if (!(fFlags & flag)) {
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h
index 9fe9291..7ea426d 100644
--- a/src/gpu/GrFragmentProcessor.h
+++ b/src/gpu/GrFragmentProcessor.h
@@ -14,7 +14,6 @@
 #include "src/gpu/GrProcessor.h"
 #include "src/gpu/ops/GrOp.h"
 
-class GrCoordTransform;
 class GrGLSLFragmentProcessor;
 class GrPaint;
 class GrPipeline;
@@ -23,9 +22,7 @@
 class GrSwizzle;
 
 /** Provides custom fragment shader code. Fragment processors receive an input color (half4) and
-    produce an output color. They may reference textures and uniforms. They may use
-    GrCoordTransforms to receive a transformation of the local coordinates that map from local space
-    to the fragment being processed.
+    produce an output color. They may reference textures and uniforms.
  */
 class GrFragmentProcessor : public GrProcessor {
 public:
@@ -121,8 +118,7 @@
     int numTextureSamplers() const { return fTextureSamplerCnt; }
     const TextureSampler& textureSampler(int i) const;
 
-    int numCoordTransforms() const;
-    const GrCoordTransform& coordTransform(int index) const;
+    int numVaryingCoordsUsed() const { return this->usesVaryingCoordsDirectly() ? 1 : 0; }
 
     int numChildProcessors() const { return fChildProcessors.count(); }
 
@@ -132,16 +128,26 @@
     SkDEBUGCODE(bool isInstantiated() const;)
 
     /**
-     * Do any of the FPs in this tree require local coordinates to be produced by the primitive
-     * processor. This can return true even if this FP does not refer to sample coordinates, but
-     * true if a descendant FP uses them.  FPs that are sampled explicitly do not
-     * require primitive-generated local coordinates.
+     * Does this FP require local coordinates to be produced by the primitive processor? This only
+     * returns true if this FP will directly read those local coordinates. FPs that are sampled
+     * explicitly do not require primitive-generated local coordinates (because the sample
+     * coordinates are supplied by the parent FP).
      *
      * If the root of an FP tree does not provide explicit coordinates, the geometry processor
      * provides the original local coordinates to start. This may be implicit as part of vertex
      * shader-lifted varyings, or by providing the base local coordinate to the fragment shader.
      */
-    bool sampleCoordsDependOnLocalCoords() const {
+    bool usesVaryingCoordsDirectly() const {
+        return SkToBool(fFlags & kUsesSampleCoordsDirectly_Flag) &&
+               !SkToBool(fFlags & kSampledWithExplicitCoords_Flag);
+    }
+
+    /**
+     * Do any of the FPs in this tree require local coordinates to be produced by the primitive
+     * processor? This can return true even if this FP does not refer to sample coordinates, but
+     * true if a descendant FP uses them.
+     */
+    bool usesVaryingCoords() const {
         return (SkToBool(fFlags & kUsesSampleCoordsDirectly_Flag) ||
                 SkToBool(fFlags & kUsesSampleCoordsIndirectly_Flag)) &&
                !SkToBool(fFlags & kSampledWithExplicitCoords_Flag);
@@ -152,9 +158,9 @@
      * (e.g. uses EmitArgs::fSampleCoord in emitCode()). This also returns true if the
      * coordinate reference comes from autogenerated code invoking 'sample(matrix)' expressions.
      *
-     * Unlike sampleCoordsDependOnLocalCoords(), this can return true whether or not the FP is
-     * explicitly sampled, and does not change based on how the FP is composed. This property is
-     * specific to the FP's function and not the entire program.
+     * Unlike usesVaryingCoords(), this can return true whether or not the FP is explicitly
+     * sampled, and does not change based on how the FP is composed. This property is specific to
+     * the FP's function and not the entire program.
      */
     bool referencesSampleCoords() const {
         return SkToBool(fFlags & kUsesSampleCoordsDirectly_Flag);
@@ -281,19 +287,9 @@
     // gets the number of Items owned by each FP and GetFn is a member that gets them by index.
     template <typename Item, CountFn Count, GetFn<Item> Get> class FPItemIter;
 
-    // Loops over all the GrCoordTransforms owned by GrFragmentProcessors. The possible sources for
+    // Loops over all the TextureSamplers owned by GrFragmentProcessors. The possible sources for
     // the iteration are the same as those for Iter and the FPs are walked in the same order as
-    // Iter. This provides access to the coord transform and the FP that owns it. Example usage:
-    //   for (GrFragmentProcessor::CoordTransformIter iter(pipeline); iter; ++iter) {
-    //       // transform is const GrCoordTransform& and owningFP is const GrFragmentProcessor&.
-    //       auto [transform, owningFP] = *iter;
-    //       ...
-    //   }
-    // See the ranges below to make this simpler a la range-for loops.
-    using CoordTransformIter = FPItemIter<const GrCoordTransform,
-                                          &GrFragmentProcessor::numCoordTransforms,
-                                          &GrFragmentProcessor::coordTransform>;
-    // Same as CoordTransformIter but for TextureSamplers:
+    // Iter. This provides access to the texture sampler and the FP that owns it. Example usage:
     //   for (GrFragmentProcessor::TextureSamplerIter iter(pipeline); iter; ++iter) {
     //       // TextureSamplerIter is const GrFragmentProcessor::TextureSampler& and
     //       // owningFP is const GrFragmentProcessor&.
@@ -305,7 +301,7 @@
                                           &GrFragmentProcessor::numTextureSamplers,
                                           &GrFragmentProcessor::textureSampler>;
 
-    // Implementation detail for using CoordTransformIter and TextureSamplerIter in range-for loops.
+    // Implementation detail for using TextureSamplerIter in range-for loops.
     template <typename Src, typename ItemIter> class FPItemRange;
 
     // These allow iteration over texture samplers for various FP sources via range-for loops.
@@ -459,8 +455,7 @@
     /**
      * Subclass implements this to support isEqual(). It will only be called if it is known that
      * the two processors are of the same subclass (i.e. they return the same object from
-     * getFactory()). The processor subclass should not compare its coord transforms as that will
-     * be performed automatically in the non-virtual isEqual().
+     * getFactory()).
      */
     virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
 
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
index 2fdd97b..8371117 100644
--- a/src/gpu/GrPathProcessor.cpp
+++ b/src/gpu/GrPathProcessor.cpp
@@ -58,25 +58,17 @@
                         GrGLSLUniformHandler* uniformHandler,
                         FPCoordTransformHandler* transformHandler) {
         for (int i = 0; *transformHandler; ++*transformHandler, ++i) {
-            const auto& fp = transformHandler->get();
-
-            GrShaderVar fragmentVar;
-            GrShaderVar transformVar;
-            if (fp.isSampledWithExplicitCoords()) {
-                transformHandler->omitCoordsForCurrCoordTransform();
-            } else {
-                SkString strVaryingName;
-                strVaryingName.printf("TransformedCoord_%d", i);
-                GrGLSLVarying v(kFloat2_GrSLType);
+            SkString strVaryingName;
+            strVaryingName.printf("TransformedCoord_%d", i);
+            GrGLSLVarying v(kFloat2_GrSLType);
 #ifdef SK_GL
-                GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*)varyingHandler;
-                fVaryingTransform.push_back().fHandle =
-                        glVaryingHandler->addPathProcessingVarying(strVaryingName.c_str(), &v)
-                                .toIndex();
+            GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*)varyingHandler;
+            fVaryingTransform.push_back().fHandle =
+                    glVaryingHandler->addPathProcessingVarying(strVaryingName.c_str(), &v)
+                            .toIndex();
 #endif
-                fragmentVar = {SkString(v.fsIn()), kFloat2_GrSLType};
-                transformHandler->specifyCoordsForCurrCoordTransform(transformVar, fragmentVar);
-            }
+            GrShaderVar fragmentVar = {SkString(v.fsIn()), kFloat2_GrSLType};
+            transformHandler->specifyCoordsForCurrCoordTransform(fragmentVar);
         }
     }
 
@@ -104,7 +96,7 @@
 
     // Varying transforms are used for non-explicitly sampled FPs. We provide a matrix
     // to GL as fixed function state and it uses it to compute a varying that we pick up
-    // in the FS as the output of the coord transform.
+    // in the FS as the transformed local coords.
     struct TransformVarying {
         VaryingHandle fHandle;
         SkMatrix      fCurrentValue = SkMatrix::InvalidMatrix();
diff --git a/src/gpu/GrPrimitiveProcessor.cpp b/src/gpu/GrPrimitiveProcessor.cpp
index 60ecb50..fcbc753 100644
--- a/src/gpu/GrPrimitiveProcessor.cpp
+++ b/src/gpu/GrPrimitiveProcessor.cpp
@@ -34,8 +34,6 @@
 
 uint32_t GrPrimitiveProcessor::computeCoordTransformsKey(const GrFragmentProcessor& fp) const {
     // This is highly coupled with the code in GrGLSLGeometryProcessor::collectTransforms().
-    // At this point, all effects do not use really coord transforms; they may implicitly report
-    // a noop coord transform but this does not impact the key.
 
     uint32_t key = 0;
     if (fp.isSampledWithExplicitCoords()) {
diff --git a/src/gpu/GrProcessorAnalysis.cpp b/src/gpu/GrProcessorAnalysis.cpp
index 0395236..df3f426 100644
--- a/src/gpu/GrProcessorAnalysis.cpp
+++ b/src/gpu/GrProcessorAnalysis.cpp
@@ -40,7 +40,7 @@
             if (fCompatibleWithCoverageAsAlpha && !fp->compatibleWithCoverageAsAlpha()) {
                 fCompatibleWithCoverageAsAlpha = false;
             }
-            if (fp->sampleCoordsDependOnLocalCoords()) {
+            if (fp->usesVaryingCoords()) {
                 fUsesLocalCoords = true;
             }
         }
diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp
index cc10424..48fb9af 100644
--- a/src/gpu/GrProcessorSet.cpp
+++ b/src/gpu/GrProcessorSet.cpp
@@ -183,14 +183,14 @@
         if (!fps[i]->compatibleWithCoverageAsAlpha()) {
             analysis.fCompatibleWithCoverageAsAlpha = false;
         }
-        coverageUsesLocalCoords |= fps[i]->sampleCoordsDependOnLocalCoords();
+        coverageUsesLocalCoords |= fps[i]->usesVaryingCoords();
     }
     if (clip) {
         hasCoverageFP = hasCoverageFP || clip->numClipCoverageFragmentProcessors();
         for (int i = 0; i < clip->numClipCoverageFragmentProcessors(); ++i) {
             const GrFragmentProcessor* clipFP = clip->clipCoverageFragmentProcessor(i);
             analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
-            coverageUsesLocalCoords |= clipFP->sampleCoordsDependOnLocalCoords();
+            coverageUsesLocalCoords |= clipFP->usesVaryingCoords();
         }
     }
     int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor);
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index c17de84..c436f14 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -16,9 +16,9 @@
 #include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
 #include "src/gpu/ccpr/GrOctoBounds.h"
 
-static bool has_coord_transforms(const GrPaint& paint) {
+static bool uses_varying_coords(const GrPaint& paint) {
     for (const auto& fp : GrFragmentProcessor::PaintCRange(paint)) {
-        if (fp.numCoordTransforms() > 0) {
+        if (fp.usesVaryingCoordsDirectly()) {
             return true;
         }
     }
@@ -102,7 +102,7 @@
                                  const SkIRect& maskDevIBounds, const SkRect& conservativeDevBounds,
                                  GrPaint&& paint)
         : GrDrawOp(ClassID())
-        , fViewMatrixIfUsingLocalCoords(has_coord_transforms(paint) ? m : SkMatrix::I())
+        , fViewMatrixIfUsingLocalCoords(uses_varying_coords(paint) ? m : SkMatrix::I())
         , fDraws(m, shape, strokeDevWidth, shapeConservativeIBounds, maskDevIBounds,
                  paint.getColor4f())
         , fProcessors(std::move(paint)) {  // Paint must be moved after fetching its color above.
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index 3408809..5eb265d 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -71,8 +71,8 @@
     };
 
 public:
-    using TransformedCoordVars = BuilderInputProvider<GrGLSLPrimitiveProcessor::TransformVar,
-                                                      &GrFragmentProcessor::numCoordTransforms>;
+    using TransformedCoordVars =
+            BuilderInputProvider<GrShaderVar, &GrFragmentProcessor::numVaryingCoordsUsed>;
     using TextureSamplers =
             BuilderInputProvider<SamplerHandle, &GrFragmentProcessor::numTextureSamplers>;
 
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index c57735d..b276969 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -167,7 +167,7 @@
         paramCount = 1;
 
         if (args.fFp.referencesSampleCoords()) {
-            const GrShaderVar& varying = args.fTransformedCoords[0].fVaryingPoint;
+            const GrShaderVar& varying = args.fTransformedCoords[0];
             switch(varying.getType()) {
                 case kFloat2_GrSLType:
                     // Just point the local coords to the varying
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
index 77c846a..a741fd1 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
@@ -95,83 +95,67 @@
 
     for (int i = 0; *handler; ++*handler, ++i) {
         const auto& fp = handler->get();
-        // FIXME: GrCoordTransform is used solely as a vehicle for iterating over all FPs that
-        // require sample coordinates directly. We should make this iteration lighter weight.
+
+        SkASSERT(fp.referencesSampleCoords());
+        SkASSERT(!fp.isSampledWithExplicitCoords());
 
         // FPs that use local coordinates need a varying to convey the coordinate. This may be the
         // base GP's local coord if transforms have to be computed in the FS, or it may be a unique
         // varying that computes the equivalent transformation hierarchy in the VS.
         GrShaderVar varyingVar;
 
-        // If the FP references local coords, we need to make sure the vertex shader sets up the
-        // right transforms or pass-through variables for the FP to evaluate in the fragment shader
-        if (fp.referencesSampleCoords()) {
-            if (fp.isSampledWithExplicitCoords()) {
-                // If the FP local coords are evaluated in the fragment shader, we only need to
-                // produce the original local coordinate to pass into the root; any other situation,
-                // the FP will have a 2nd parameter to its function and the caller sends the coords
-                if (!fp.parent()) {
-                    varyingVar = getBaseLocalCoord();
+        // The FP's local coordinates are determined by the uniform transform hierarchy
+        // from this FP to the root, and can be computed in the vertex shader.
+        // If this hierarchy would be the identity transform, then we should use the
+        // original local coordinate.
+        // NOTE: The actual transform logic is handled in emitTransformCode(), this just
+        // needs to determine if a unique varying should be added for the FP.
+        GrShaderVar transformedLocalCoord;
+        const GrFragmentProcessor* coordOwner = nullptr;
+
+        const GrFragmentProcessor* node = &fp;
+        while(node) {
+            SkASSERT(!node->isSampledWithExplicitCoords() &&
+                     !node->sampleUsage().hasVariableMatrix());
+
+            if (node->sampleUsage().hasUniformMatrix()) {
+                // We can stop once we hit an FP that adds transforms; this FP can reuse
+                // that FPs varying (possibly vivifying it if this was the first use).
+                transformedLocalCoord = localCoordsMap[node];
+                coordOwner = node;
+                break;
+            } // else intervening FP is an identity transform so skip past it
+
+            node = node->parent();
+        }
+
+        if (coordOwner) {
+            // The FP will use coordOwner's varying; add varying if this was the first use
+            if (transformedLocalCoord.getType() == kVoid_GrSLType) {
+                GrGLSLVarying v(kFloat2_GrSLType);
+                if (GrSLTypeVecLength(localCoordsVar.getType()) == 3 ||
+                    coordOwner->hasPerspectiveTransform()) {
+                    v = GrGLSLVarying(kFloat3_GrSLType);
                 }
-            } else {
-                // The FP's local coordinates are determined by the uniform transform hierarchy
-                // from this FP to the root, and can be computed in the vertex shader.
-                // If this hierarchy would be the identity transform, then we should use the
-                // original local coordinate.
-                // NOTE: The actual transform logic is handled in emitTransformCode(), this just
-                // needs to determine if a unique varying should be added for the FP.
-                GrShaderVar transformedLocalCoord;
-                const GrFragmentProcessor* coordOwner = nullptr;
+                SkString strVaryingName;
+                strVaryingName.printf("TransformedCoords_%d", i);
+                varyingHandler->addVarying(strVaryingName.c_str(), &v);
 
-                const GrFragmentProcessor* node = &fp;
-                while(node) {
-                    SkASSERT(!node->isSampledWithExplicitCoords() &&
-                             !node->sampleUsage().hasVariableMatrix());
-
-                    if (node->sampleUsage().hasUniformMatrix()) {
-                        // We can stop once we hit an FP that adds transforms; this FP can reuse
-                        // that FPs varying (possibly vivifying it if this was the first use).
-                        transformedLocalCoord = localCoordsMap[node];
-                        coordOwner = node;
-                        break;
-                    } // else intervening FP is an identity transform so skip past it
-
-                    node = node->parent();
-                }
-
-                if (coordOwner) {
-                    // The FP will use coordOwner's varying; add varying if this was the first use
-                    if (transformedLocalCoord.getType() == kVoid_GrSLType) {
-                        GrGLSLVarying v(kFloat2_GrSLType);
-                        if (GrSLTypeVecLength(localCoordsVar.getType()) == 3 ||
-                            coordOwner->hasPerspectiveTransform()) {
-                            v = GrGLSLVarying(kFloat3_GrSLType);
-                        }
-                        SkString strVaryingName;
-                        strVaryingName.printf("TransformedCoords_%d", i);
-                        varyingHandler->addVarying(strVaryingName.c_str(), &v);
-
-                        fTransformInfos.push_back({GrShaderVar(v.vsOut(), v.type()),
-                                                   localCoordsVar,
-                                                   coordOwner});
-                        transformedLocalCoord = GrShaderVar(SkString(v.fsIn()), v.type(),
-                                                            GrShaderVar::TypeModifier::In);
-                        localCoordsMap[coordOwner] = transformedLocalCoord;
-                    }
-
-                    varyingVar = transformedLocalCoord;
-                } else {
-                    // The FP transform hierarchy is the identity, so use the original local coord
-                    varyingVar = getBaseLocalCoord();
-                }
+                fTransformInfos.push_back(
+                        {GrShaderVar(v.vsOut(), v.type()), localCoordsVar, coordOwner});
+                transformedLocalCoord =
+                        GrShaderVar(SkString(v.fsIn()), v.type(), GrShaderVar::TypeModifier::In);
+                localCoordsMap[coordOwner] = transformedLocalCoord;
             }
+
+            varyingVar = transformedLocalCoord;
+        } else {
+            // The FP transform hierarchy is the identity, so use the original local coord
+            varyingVar = getBaseLocalCoord();
         }
 
-        if (varyingVar.getType() != kVoid_GrSLType) {
-            handler->specifyCoordsForCurrCoordTransform(GrShaderVar(), varyingVar);
-        } else {
-            handler->omitCoordsForCurrCoordTransform();
-        }
+        SkASSERT(varyingVar.getType() != kVoid_GrSLType);
+        handler->specifyCoordsForCurrCoordTransform(varyingVar);
     }
 }
 
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp b/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp
index 7b1264c..d8bdb2b 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp
@@ -33,17 +33,23 @@
 //////////////////////////////////////////////////////////////////////////////
 
 GrGLSLPrimitiveProcessor::FPCoordTransformHandler::FPCoordTransformHandler(
-        const GrPipeline& pipeline, SkTArray<TransformVar>* transformedCoordVars)
-        : fIter(pipeline), fTransformedCoordVars(transformedCoordVars) {}
+        const GrPipeline& pipeline, SkTArray<GrShaderVar>* transformedCoordVars)
+        : fIter(pipeline), fTransformedCoordVars(transformedCoordVars) {
+    while (fIter && !fIter->usesVaryingCoordsDirectly()) {
+        ++fIter;
+    }
+}
 
 const GrFragmentProcessor& GrGLSLPrimitiveProcessor::FPCoordTransformHandler::get() const {
-    return (*fIter).second;
+    return *fIter;
 }
 
 GrGLSLPrimitiveProcessor::FPCoordTransformHandler&
 GrGLSLPrimitiveProcessor::FPCoordTransformHandler::operator++() {
     SkASSERT(fAddedCoord);
-    ++fIter;
+    do {
+        ++fIter;
+    } while (fIter && !fIter->usesVaryingCoordsDirectly());
     SkDEBUGCODE(fAddedCoord = false;)
     return *this;
 }
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
index e429d64..2db52cb 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
@@ -26,55 +26,38 @@
     using UniformHandle         = GrGLSLProgramDataManager::UniformHandle;
     using SamplerHandle         = GrGLSLUniformHandler::SamplerHandle;
 
-    struct TransformVar {
-        // The transform as a variable. This may be a kFloat3x3 matrix or a kFloat4 representing
-        // {scaleX, transX, scaleY, transY}. For explicitly sampled FPs this is visible in the
-        // FS. This is not available for NV_path_rendering with non-explicitly sampled FPs.
-        GrShaderVar fTransform;
-        // The transformed coordinate output by the vertex shader and consumed by the fragment
-        // shader. Only valid for non-explicitly sampled FPs.
-        GrShaderVar fVaryingPoint;
-    };
-
-
     virtual ~GrGLSLPrimitiveProcessor() {}
 
     /**
-     * This class provides access to the GrCoordTransforms across all GrFragmentProcessors in a
-     * GrPipeline. It is also used by the primitive processor to specify the fragment shader
-     * variable that will hold the transformed coords for each GrCoordTransform. It is required that
-     * the primitive processor iterate over each coord transform and insert a shader var result for
-     * each. The GrGLSLFragmentProcessors will reference these variables in their fragment code.
+     * This class provides access to each GrFragmentProcessor in a GrPipeline that requires varying
+     * local coords to be produced by the primitive processor. It is also used by the primitive
+     * processor to specify the fragment shader variable that will hold the transformed coords for
+     * each of those GrFragmentProcessors. It is required that the primitive processor iterate over
+     * each fragment processor and insert a shader var result for each. The GrGLSLFragmentProcessors
+     * will reference these variables in their fragment code.
      */
     class FPCoordTransformHandler : public SkNoncopyable {
     public:
-        FPCoordTransformHandler(const GrPipeline&, SkTArray<TransformVar>*);
+        FPCoordTransformHandler(const GrPipeline&, SkTArray<GrShaderVar>*);
         ~FPCoordTransformHandler() { SkASSERT(!fIter); }
 
         operator bool() const { return (bool)fIter; }
 
-        // Gets the current coord transform and its owning GrFragmentProcessor.
+        // Gets the current GrFragmentProcessor
         const GrFragmentProcessor& get() const;
 
         FPCoordTransformHandler& operator++();
 
-        // 'args' are constructor params to GrShaderVar.
-        void specifyCoordsForCurrCoordTransform(GrShaderVar transformVar, GrShaderVar varyingVar) {
+        void specifyCoordsForCurrCoordTransform(GrShaderVar varyingVar) {
             SkASSERT(!fAddedCoord);
-            fTransformedCoordVars->push_back({transformVar, varyingVar});
-            SkDEBUGCODE(fAddedCoord = true;)
-        }
-
-        void omitCoordsForCurrCoordTransform() {
-            SkASSERT(!fAddedCoord);
-            fTransformedCoordVars->push_back();
+            fTransformedCoordVars->push_back(varyingVar);
             SkDEBUGCODE(fAddedCoord = true;)
         }
 
     private:
-        GrFragmentProcessor::CoordTransformIter fIter;
-        SkDEBUGCODE(bool                        fAddedCoord = false;)
-        SkTArray<TransformVar>*                 fTransformedCoordVars;
+        GrFragmentProcessor::CIter fIter;
+        SkDEBUGCODE(bool           fAddedCoord = false;)
+        SkTArray<GrShaderVar>*     fTransformedCoordVars;
     };
 
     struct EmitArgs {
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 5965514..627f380 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -140,7 +140,7 @@
         output = this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, output,
                                               &glslFragmentProcessors);
         for (const auto& subFP : GrFragmentProcessor::FPCRange(fp)) {
-            transformedCoordVarsIdx += subFP.numCoordTransforms();
+            transformedCoordVarsIdx += subFP.numVaryingCoordsUsed();
         }
         **inOut = output;
     }
@@ -185,8 +185,7 @@
                                                        name.c_str()));
         }
     }
-    const GrGLSLPrimitiveProcessor::TransformVar* coordVars = fTransformedCoordVars.begin() +
-                                                              transformedCoordVarsIdx;
+    const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
     GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
     GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, texSamplers.begin());
     GrGLSLFragmentProcessor::EmitArgs args(&fFS,
@@ -200,11 +199,11 @@
                                            textureSamplers);
 
     if (fp.referencesSampleCoords()) {
-        // The fp's generated code expects a _coords variable, but we're a the root so _coords
+        // The fp's generated code expects a _coords variable, but we're at the root so _coords
         // is just the local coordinates produced by the primitive processor.
-        SkASSERT(coords.count() > 0);
+        SkASSERT(fp.usesVaryingCoordsDirectly());
 
-        const GrShaderVar& varying = coordVars[0].fVaryingPoint;
+        const GrShaderVar& varying = coordVars[0];
         switch(varying.getType()) {
             case kFloat2_GrSLType:
                 fFS.codeAppendf("float2 %s = %s.xy;\n",
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 4129975..3fe7816 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -173,7 +173,7 @@
 
     // These are used to check that we don't excede the allowable number of resources in a shader.
     int fNumFragmentSamplers;
-    SkSTArray<4, GrGLSLPrimitiveProcessor::TransformVar> fTransformedCoordVars;
+    SkSTArray<4, GrShaderVar> fTransformedCoordVars;
 };
 
 #endif
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index 8324130..8151c9c 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -395,7 +395,6 @@
         Modifiers mods(Layout(), Modifiers::kConst_Flag);
         std::vector<Type::Field> fields = {
             Type::Field(mods, "numTextureSamplers", intType),
-            Type::Field(mods, "numCoordTransforms", intType),
             Type::Field(mods, "numChildProcessors", intType),
             Type::Field(mods, "usesLocalCoords", boolType),
             Type::Field(mods, "compatibleWithCoverageAsAlpha", boolType),
diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp
index 33ab5ba..192c9c6 100644
--- a/tests/ProcessorTest.cpp
+++ b/tests/ProcessorTest.cpp
@@ -787,8 +787,7 @@
                                       "%s\n", describe_fp(*fp).c_str());
             REPORTER_ASSERT(reporter, fp->numChildProcessors() == clone->numChildProcessors(),
                                       "%s\n", describe_fp(*fp).c_str());
-            REPORTER_ASSERT(reporter, fp->sampleCoordsDependOnLocalCoords() ==
-                                      clone->sampleCoordsDependOnLocalCoords(),
+            REPORTER_ASSERT(reporter, fp->usesVaryingCoords() == clone->usesVaryingCoords(),
                                       "%s\n", describe_fp(*fp).c_str());
             REPORTER_ASSERT(reporter, fp->referencesSampleCoords() ==
                                       clone->referencesSampleCoords(),