Move setSampleMatrix and setSampledWithExplicitCoords into child registration

Bug: skia:10396
Change-Id: I0c117ab4d95737b76dec5bce16103b9058218fb8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297065
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/gm/fpcoordinateoverride.cpp b/gm/fpcoordinateoverride.cpp
index c238da4..dc44536 100644
--- a/gm/fpcoordinateoverride.cpp
+++ b/gm/fpcoordinateoverride.cpp
@@ -38,8 +38,7 @@
 
     SampleCoordEffect(std::unique_ptr<GrFragmentProcessor> child)
         : INHERITED(CLASS_ID, kNone_OptimizationFlags) {
-        child->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(child));
+        this->registerExplicitlySampledChild(std::move(child));
     }
 
     const char* name() const override { return "SampleCoordEffect"; }
diff --git a/gm/sample_matrix_constant.cpp b/gm/sample_matrix_constant.cpp
index b57a20b..45e26e6 100644
--- a/gm/sample_matrix_constant.cpp
+++ b/gm/sample_matrix_constant.cpp
@@ -21,11 +21,11 @@
 
     SampleMatrixConstantEffect(std::unique_ptr<GrFragmentProcessor> child)
             : INHERITED(CLASS_ID, kNone_OptimizationFlags) {
-        child->setSampleMatrix(SkSL::SampleMatrix(SkSL::SampleMatrix::Kind::kConstantOrUniform,
-                                                  child.get(), "float3x3(float3(0.5, 0.0, 0.0), "
-                                                                        "float3(0.0, 0.5, 0.0), "
-                                                                        "float3(0.0, 0.0, 1.0))"));
-        this->registerChildProcessor(std::move(child));
+        this->registerChild(std::move(child),
+                            SkSL::SampleMatrix::MakeConstUniform(
+                                    "float3x3(float3(0.5, 0.0, 0.0), "
+                                             "float3(0.0, 0.5, 0.0), "
+                                             "float3(0.0, 0.0, 1.0))"));
     }
 
     const char* name() const override { return "SampleMatrixConstantEffect"; }
diff --git a/gm/sample_matrix_variable.cpp b/gm/sample_matrix_variable.cpp
index 63abd2b..185f654 100644
--- a/gm/sample_matrix_variable.cpp
+++ b/gm/sample_matrix_variable.cpp
@@ -25,8 +25,7 @@
             : INHERITED(CLASS_ID, kNone_OptimizationFlags)
             , fXOffset(xOffset)
             , fYOffset(yOffset) {
-        child->setSampleMatrix(SkSL::SampleMatrix(SkSL::SampleMatrix::Kind::kVariable));
-        this->registerChildProcessor(std::move(child));
+        this->registerChild(std::move(child), SkSL::SampleMatrix::MakeVariable());
     }
 
     const char* name() const override { return "SampleMatrixVariableEffect"; }
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 4a6e6fe..dc15b1f 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -307,15 +307,12 @@
         // Not bothering with table-specific optimizations.
         : INHERITED(kColorTableEffect_ClassID, kNone_OptimizationFlags) {
     auto te = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
-    te->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(te));
+    this->registerExplicitlySampledChild(std::move(te));
 }
 
 ColorTableEffect::ColorTableEffect(const ColorTableEffect& that)
         : INHERITED(kColorTableEffect_ClassID, that.optimizationFlags()) {
-    auto child = that.childProcessor(0).clone();
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->cloneAndRegisterAllChildProcessors(that);
 }
 
 GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const {
diff --git a/src/effects/imagefilters/SkDisplacementMapEffect.cpp b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
index bce57a7..fe5fe87 100644
--- a/src/effects/imagefilters/SkDisplacementMapEffect.cpp
+++ b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
@@ -508,9 +508,8 @@
         , fXChannelSelector(xChannelSelector)
         , fYChannelSelector(yChannelSelector)
         , fScale(scale) {
-    this->registerChildProcessor(std::move(displacement));
-    color->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(color));
+    this->registerChild(std::move(displacement));
+    this->registerExplicitlySampledChild(std::move(color));
     this->addCoordTransform(&fCoordTransform);
 }
 
diff --git a/src/effects/imagefilters/SkLightingImageFilter.cpp b/src/effects/imagefilters/SkLightingImageFilter.cpp
index 933171c..5181f11 100644
--- a/src/effects/imagefilters/SkLightingImageFilter.cpp
+++ b/src/effects/imagefilters/SkLightingImageFilter.cpp
@@ -1632,8 +1632,7 @@
         child = GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, SkMatrix::I(), kSampler,
                                       caps);
     }
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->registerExplicitlySampledChild(std::move(child));
     this->addCoordTransform(&fCoordTransform);
 }
 
@@ -1643,9 +1642,7 @@
         , fSurfaceScale(that.fSurfaceScale)
         , fFilterMatrix(that.fFilterMatrix)
         , fBoundaryMode(that.fBoundaryMode) {
-    auto child = that.childProcessor(0).clone();
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->cloneAndRegisterAllChildProcessors(that);
     this->addCoordTransform(&fCoordTransform);
 }
 
diff --git a/src/effects/imagefilters/SkMorphologyImageFilter.cpp b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
index 27d176d..35f35d7 100644
--- a/src/effects/imagefilters/SkMorphologyImageFilter.cpp
+++ b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
@@ -346,8 +346,7 @@
         , fUseRange(SkToBool(range)) {
     this->addCoordTransform(&fCoordTransform);
     auto te = GrTextureEffect::Make(std::move(view), srcAlphaType);
-    te->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(te));
+    this->registerExplicitlySampledChild(std::move(te));
     if (fUseRange) {
         fRange[0] = range[0];
         fRange[1] = range[1];
@@ -361,9 +360,7 @@
         , fType(that.fType)
         , fUseRange(that.fUseRange) {
     this->addCoordTransform(&fCoordTransform);
-    auto child = that.childProcessor(0).clone();
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->cloneAndRegisterAllChildProcessors(that);
     if (that.fUseRange) {
         fRange[0] = that.fRange[0];
         fRange[1] = that.fRange[1];
diff --git a/src/gpu/GrColorSpaceXform.cpp b/src/gpu/GrColorSpaceXform.cpp
index 0f97d21..b602b32 100644
--- a/src/gpu/GrColorSpaceXform.cpp
+++ b/src/gpu/GrColorSpaceXform.cpp
@@ -97,7 +97,7 @@
         : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
         , fColorXform(std::move(colorXform)) {
     if (child) {
-        this->registerChildProcessor(std::move(child));
+        this->registerChild(std::move(child));
     }
 }
 
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 435391b..9c668d3 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -98,8 +98,8 @@
             }
         } else {
             SkASSERT(newMatrix.fKind == SkSL::SampleMatrix::Kind::kVariable);
-            fMatrix = SkSL::SampleMatrix(SkSL::SampleMatrix::Kind::kMixed, fMatrix.fOwner,
-                                         fMatrix.fExpression);
+            fMatrix.fKind = SkSL::SampleMatrix::Kind::kMixed;
+            fMatrix.fBase = nullptr;
         }
     } else {
         SkASSERT(fMatrix.fKind == SkSL::SampleMatrix::Kind::kNone);
@@ -110,6 +110,13 @@
     }
 }
 
+void GrFragmentProcessor::setSampledWithExplicitCoords() {
+    fFlags |= kSampledWithExplicitCoords;
+    for (auto& child : fChildProcessors) {
+        child->setSampledWithExplicitCoords();
+    }
+}
+
 #ifdef SK_DEBUG
 bool GrFragmentProcessor::isInstantiated() const {
     for (int i = 0; i < fTextureSamplerCnt; ++i) {
@@ -128,7 +135,26 @@
 }
 #endif
 
-int GrFragmentProcessor::registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child) {
+int GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> child,
+                                       SkSL::SampleMatrix sampleMatrix,
+                                       bool explicitlySampled) {
+    // Configure child's sampling state first
+    if (explicitlySampled) {
+        child->setSampledWithExplicitCoords();
+    }
+    if (sampleMatrix.fKind != SkSL::SampleMatrix::Kind::kNone) {
+        // FIXME(michaelludwig) - Temporary hack. Owner tracking will be moved off of SampleMatrix
+        // and into FP. Currently, coord transform compilation fails on sample_matrix GMs if the
+        // child isn't the owner. But the matrix effect (and expected behavior) require the owner
+        // to be 'this' FP.
+        if (this->classID() == kGrMatrixEffect_ClassID) {
+            sampleMatrix.fOwner = this;
+        } else {
+            sampleMatrix.fOwner = child.get();
+        }
+        child->setSampleMatrix(sampleMatrix);
+    }
+
     if (child->fFlags & kHasCoordTransforms_Flag) {
         fFlags |= kHasCoordTransforms_Flag;
     }
@@ -143,10 +169,8 @@
 
 int GrFragmentProcessor::cloneAndRegisterChildProcessor(const GrFragmentProcessor& fp) {
     std::unique_ptr<GrFragmentProcessor> clone = fp.clone();
-    if (fp.isSampledWithExplicitCoords()) {
-        clone->setSampledWithExplicitCoords();
-    }
-    return this->registerChildProcessor(std::move(clone));
+    return this->registerChild(std::move(clone), fp.sampleMatrix(),
+                               fp.isSampledWithExplicitCoords());
 }
 
 void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) {
@@ -213,7 +237,7 @@
         SwizzleFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle)
                 : INHERITED(kSwizzleFragmentProcessor_ClassID, ProcessorOptimizationFlags(fp.get()))
                 , fSwizzle(swizzle) {
-            this->registerChildProcessor(std::move(fp));
+            this->registerChild(std::move(fp));
         }
 
         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
@@ -279,7 +303,7 @@
     private:
         PremulFragmentProcessor(std::unique_ptr<GrFragmentProcessor> processor)
                 : INHERITED(kPremulFragmentProcessor_ClassID, OptFlags(processor.get())) {
-            this->registerChildProcessor(std::move(processor));
+            this->registerChild(std::move(processor));
         }
 
         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
@@ -379,7 +403,7 @@
                 : INHERITED(kSeriesFragmentProcessor_ClassID, OptFlags(children, cnt)) {
             SkASSERT(cnt > 1);
             for (int i = 0; i < cnt; ++i) {
-                this->registerChildProcessor(std::move(children[i]));
+                this->registerChild(std::move(children[i]));
             }
         }
 
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h
index 56360b4..91f5e3c 100644
--- a/src/gpu/GrFragmentProcessor.h
+++ b/src/gpu/GrFragmentProcessor.h
@@ -148,19 +148,10 @@
         return SkToBool(fFlags & kSampledWithExplicitCoords);
     }
 
-    void setSampledWithExplicitCoords() {
-        fFlags |= kSampledWithExplicitCoords;
-        for (auto& child : fChildProcessors) {
-            child->setSampledWithExplicitCoords();
-        }
-    }
-
     SkSL::SampleMatrix sampleMatrix() const {
         return fMatrix;
     }
 
-    void setSampleMatrix(SkSL::SampleMatrix matrix);
-
     /**
      * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color
      * output under the following scenario:
@@ -332,6 +323,13 @@
     // Sentinel type for range-for using FPItemIter.
     class FPItemEndIter {};
 
+    // FIXME This should be private, but SkGr needs to mark the dither effect as sampled explicitly
+    // even though it's not added to another FP. Once varying generation doesn't add a redundant
+    // varying for it, this can be fully private.
+    void temporary_SetExplicitlySampled() {
+        this->setSampledWithExplicitCoords();
+    }
+
 protected:
     enum OptimizationFlags : uint32_t {
         kNone_OptimizationFlags,
@@ -424,8 +422,24 @@
      * colors will be combined somehow to produce its output color.  Registering these child
      * processors will allow the ProgramBuilder to automatically handle their transformed coords and
      * texture accesses and mangle their uniform and output color names.
+     *
+     * Depending on the 2nd and 3rd parameters, this corresponds to the following SkSL sample calls:
+     *  - sample(child): Keep default arguments
+     *  - sample(child, matrix): Provide approprate SampleMatrix matching SkSL
+     *  - sample(child, float2): SampleMatrix() and 'true', or use 'registerExplicitlySampledChild'
+     *  - sample(child, matrix)+sample(child, float2): Appropriate SampleMatrix and 'true'
      */
-    int registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child);
+    int registerChild(std::unique_ptr<GrFragmentProcessor> child,
+                      SkSL::SampleMatrix sampleMatrix = SkSL::SampleMatrix(),
+                      bool explicitlySampled = false);
+
+    /**
+     * A helper for use when the child is only invoked with sample(float2), and not sample()
+     * or sample(matrix).
+     */
+    int registerExplicitlySampledChild(std::unique_ptr<GrFragmentProcessor> child) {
+        return this->registerChild(std::move(child), SkSL::SampleMatrix(), true);
+    }
 
     /**
      * This method takes an existing fragment processor, clones it, registers it as a child of this
@@ -484,6 +498,10 @@
 
     bool hasSameTransforms(const GrFragmentProcessor&) const;
 
+    void setSampledWithExplicitCoords();
+
+    void setSampleMatrix(SkSL::SampleMatrix matrix);
+
     enum PrivateFlags {
         kFirstPrivateFlag = kAll_OptimizationFlags + 1,
         kHasCoordTransforms_Flag = kFirstPrivateFlag,
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 2e0cb32..94abf6b 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -387,7 +387,7 @@
             if (ditherFP) {
                 // The dither shader doesn't actually use input coordinates, but if we don't set
                 // this flag, the generated shader includes an extra local coord varying.
-                ditherFP->setSampledWithExplicitCoords();
+                ditherFP->temporary_SetExplicitlySampled();
                 grPaint->addColorFragmentProcessor(std::move(ditherFP));
             }
         }
diff --git a/src/gpu/ccpr/GrCCClipProcessor.cpp b/src/gpu/ccpr/GrCCClipProcessor.cpp
index 6e52706..718985a 100644
--- a/src/gpu/ccpr/GrCCClipProcessor.cpp
+++ b/src/gpu/ccpr/GrCCClipProcessor.cpp
@@ -30,11 +30,10 @@
         , fMustCheckBounds(MustCheckBounds::kYes == mustCheckBounds) {
     auto view = make_view(caps, clipPath->atlasLazyProxy(), fIsCoverageCount);
     auto texEffect = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
-    texEffect->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(texEffect));
+    this->registerExplicitlySampledChild(std::move(texEffect));
 
     if (inputFP != nullptr) {
-        this->registerChildProcessor(std::move(inputFP));
+        this->registerChild(std::move(inputFP));
     }
 }
 
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index ef9560e..d575668 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -176,9 +176,8 @@
         , fCoordTransform(matrix)
         , fDirection(direction)
         , fClamp(clamp) {
-    fp->setSampledWithExplicitCoords();
     this->addCoordTransform(&fCoordTransform);
-    this->registerChildProcessor(std::move(fp));
+    this->registerExplicitlySampledChild(std::move(fp));
 }
 
 GrBicubicEffect::GrBicubicEffect(const GrBicubicEffect& that)
@@ -187,9 +186,7 @@
         , fDirection(that.fDirection)
         , fClamp(that.fClamp) {
     this->addCoordTransform(&fCoordTransform);
-    auto child = that.childProcessor(0).clone();
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->cloneAndRegisterAllChildProcessors(that);
 }
 
 void GrBicubicEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index 1a328af..6512d47 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -200,7 +200,7 @@
     }
 
     if (inputFP != nullptr) {
-        this->registerChildProcessor(std::move(inputFP));
+        this->registerChild(std::move(inputFP));
     }
 }
 
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
index 8437d54..3c8db34 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
@@ -171,8 +171,7 @@
                     ProcessorOptimizationFlags(child.get()))
         , fRadius(radius)
         , fDirection(direction) {
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->registerExplicitlySampledChild(std::move(child));
     SkASSERT(radius <= kMaxKernelRadius);
     fill_in_1D_gaussian_kernel(fKernel, gaussianSigma, fRadius);
     this->addCoordTransform(&fCoordTransform);
@@ -183,9 +182,7 @@
         : INHERITED(kGrGaussianConvolutionFragmentProcessor_ClassID, that.optimizationFlags())
         , fRadius(that.fRadius)
         , fDirection(that.fDirection) {
-    auto child = that.childProcessor(0).clone();
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->cloneAndRegisterAllChildProcessors(that);
     memcpy(fKernel, that.fKernel, radius_to_width(fRadius) * sizeof(float));
     this->addCoordTransform(&fCoordTransform);
 }
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index 1ad920e..04036d0 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -294,11 +294,9 @@
         , fGain(SkScalarToFloat(gain))
         , fBias(SkScalarToFloat(bias) / 255.0f)
         , fConvolveAlpha(convolveAlpha) {
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->registerExplicitlySampledChild(std::move(child));
     if (kernelFP) {
-        kernelFP->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(kernelFP));
+        this->registerExplicitlySampledChild(std::move(kernelFP));
     }
     fKernelOffset = {static_cast<float>(kernelOffset.x()),
                      static_cast<float>(kernelOffset.y())};
@@ -312,14 +310,7 @@
         , fBias(that.fBias)
         , fKernelOffset(that.fKernelOffset)
         , fConvolveAlpha(that.fConvolveAlpha) {
-    auto child = that.childProcessor(0).clone();
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
-    if (fKernel.isSampled()) {
-        child = that.childProcessor(1).clone();
-        child->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(child));
-    }
+    this->cloneAndRegisterAllChildProcessors(that);
     this->addCoordTransform(&fCoordTransform);
 }
 
diff --git a/src/gpu/effects/GrMatrixEffect.h b/src/gpu/effects/GrMatrixEffect.h
index 18c35e9..69fd1be 100644
--- a/src/gpu/effects/GrMatrixEffect.h
+++ b/src/gpu/effects/GrMatrixEffect.h
@@ -38,9 +38,7 @@
             : INHERITED(kGrMatrixEffect_ClassID, kNone_OptimizationFlags)
             , fMatrix(matrix) {
         SkASSERT(child);
-        child->setSampleMatrix(
-                SkSL::SampleMatrix(SkSL::SampleMatrix::Kind::kConstantOrUniform, this, "matrix"));
-        this->registerChildProcessor(std::move(child));
+        this->registerChild(std::move(child), SkSL::SampleMatrix::MakeConstUniform("matrix"));
     }
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 64fa6967..2e2f4c0 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -106,7 +106,7 @@
         , fEdgeType(edgeType)
         , fCircularCornerFlags(circularCornerFlags) {
     if (inputFP != nullptr) {
-        this->registerChildProcessor(std::move(inputFP));
+        this->registerChild(std::move(inputFP));
     }
 }
 
@@ -465,7 +465,7 @@
         , fRRect(rrect)
         , fEdgeType(edgeType) {
     if (inputFP != nullptr) {
-        this->registerChildProcessor(std::move(inputFP));
+        this->registerChild(std::move(inputFP));
     }
 }
 
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index d84d63f..cbfeb9d 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -198,8 +198,7 @@
 }
 
 void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child) {
-    child->setSampledWithExplicitCoords();
-    this->registerChildProcessor(std::move(child));
+    this->registerExplicitlySampledChild(std::move(child));
 }
 
 GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index 8b4a774..fe09020 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -62,8 +62,8 @@
                                 SkBlendMode mode)
             : INHERITED(kComposeTwoFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode))
             , fMode(mode) {
-        SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
-        SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
+        SkDEBUGCODE(int shaderAChildIndex = )this->registerChild(std::move(src));
+        SkDEBUGCODE(int shaderBChildIndex = )this->registerChild(std::move(dst));
         SkASSERT(0 == shaderAChildIndex);
         SkASSERT(1 == shaderBChildIndex);
     }
@@ -413,7 +413,7 @@
             : INHERITED(kComposeOneFragmentProcessor_ClassID, OptFlags(fp.get(), mode, child))
             , fMode(mode)
             , fChild(child) {
-        SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp));
+        SkDEBUGCODE(int dstIndex =) this->registerChild(std::move(fp));
         SkASSERT(0 == dstIndex);
     }
 
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 6e70b20..ad0584a 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -112,7 +112,7 @@
                               ModulateForClampedSamplerOptFlags(alpha_type(yuvaIndices)))
         , fYUVColorSpace(yuvColorSpace) {
     for (int i = 0; i < numPlanes; ++i) {
-        this->registerChildProcessor(std::move(planeFPs[i]));
+        this->registerChild(std::move(planeFPs[i]));
     }
     std::copy_n(yuvaIndices, 4, fYUVAIndices);
 }
@@ -251,10 +251,7 @@
 GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src)
         : GrFragmentProcessor(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags())
         , fYUVColorSpace(src.fYUVColorSpace) {
-    int numPlanes = src.numChildProcessors();
-    for (int i = 0; i < numPlanes; ++i) {
-        this->registerChildProcessor(this->childProcessor(i).clone());
-    }
+    this->cloneAndRegisterAllChildProcessors(src);
     std::copy_n(src.fYUVAIndices, this->numChildProcessors(), fYUVAIndices);
 }
 
diff --git a/src/gpu/effects/generated/GrAARectEffect.h b/src/gpu/effects/generated/GrAARectEffect.h
index 17b0f7f..88891e4 100644
--- a/src/gpu/effects/generated/GrAARectEffect.h
+++ b/src/gpu/effects/generated/GrAARectEffect.h
@@ -43,7 +43,7 @@
             , edgeType(edgeType)
             , rect(rect) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h b/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h
index 539925d..eeb9e9c 100644
--- a/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h
+++ b/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h
@@ -47,10 +47,10 @@
             , innerThreshold(innerThreshold)
             , outerThreshold(outerThreshold) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
         SkASSERT(maskFP);
-        maskFP_index = this->registerChildProcessor(std::move(maskFP));
+        maskFP_index = this->registerChild(std::move(maskFP));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h b/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h
index 93c00b0..d9c0c3b 100644
--- a/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h
+++ b/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h
@@ -36,7 +36,7 @@
             : INHERITED(kGrBlurredEdgeFragmentProcessor_ClassID, kNone_OptimizationFlags)
             , mode(mode) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h b/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h
index 7ed4923..164ccdd 100644
--- a/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h
+++ b/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h
@@ -48,11 +48,10 @@
             , solidRadius(solidRadius)
             , textureRadius(textureRadius) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
         SkASSERT(blurProfile);
-        blurProfile->setSampledWithExplicitCoords();
-        blurProfile_index = this->registerChildProcessor(std::move(blurProfile));
+        blurProfile_index = this->registerExplicitlySampledChild(std::move(blurProfile));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/generated/GrCircleEffect.h b/src/gpu/effects/generated/GrCircleEffect.h
index 6db0e1c..0d00d31 100644
--- a/src/gpu/effects/generated/GrCircleEffect.h
+++ b/src/gpu/effects/generated/GrCircleEffect.h
@@ -52,7 +52,7 @@
             , center(center)
             , radius(radius) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrClampFragmentProcessor.h b/src/gpu/effects/generated/GrClampFragmentProcessor.h
index 734e3f5..795555a 100644
--- a/src/gpu/effects/generated/GrClampFragmentProcessor.h
+++ b/src/gpu/effects/generated/GrClampFragmentProcessor.h
@@ -48,7 +48,7 @@
                                  kPreservesOpaqueInput_OptimizationFlag))
             , clampToPremul(clampToPremul) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h b/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h
index c703b9e..4160af9 100644
--- a/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h
+++ b/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h
@@ -86,7 +86,7 @@
             , clampRGBOutput(clampRGBOutput)
             , premulOutput(premulOutput) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrComposeLerpEffect.h b/src/gpu/effects/generated/GrComposeLerpEffect.h
index af9d794..1f9d225 100644
--- a/src/gpu/effects/generated/GrComposeLerpEffect.h
+++ b/src/gpu/effects/generated/GrComposeLerpEffect.h
@@ -38,10 +38,10 @@
                         float weight)
             : INHERITED(kGrComposeLerpEffect_ClassID, kNone_OptimizationFlags), weight(weight) {
         if (child1) {
-            child1_index = this->registerChildProcessor(std::move(child1));
+            child1_index = this->registerChild(std::move(child1));
         }
         if (child2) {
-            child2_index = this->registerChildProcessor(std::move(child2));
+            child2_index = this->registerChild(std::move(child2));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrConstColorProcessor.h b/src/gpu/effects/generated/GrConstColorProcessor.h
index 551e47a..e9b8b86 100644
--- a/src/gpu/effects/generated/GrConstColorProcessor.h
+++ b/src/gpu/effects/generated/GrConstColorProcessor.h
@@ -74,7 +74,7 @@
             , color(color)
             , mode(mode) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrDeviceSpaceEffect.h b/src/gpu/effects/generated/GrDeviceSpaceEffect.h
index 7fbf00f..c7e4f24 100644
--- a/src/gpu/effects/generated/GrDeviceSpaceEffect.h
+++ b/src/gpu/effects/generated/GrDeviceSpaceEffect.h
@@ -33,8 +33,7 @@
     GrDeviceSpaceEffect(std::unique_ptr<GrFragmentProcessor> fp, SkMatrix matrix)
             : INHERITED(kGrDeviceSpaceEffect_ClassID, kNone_OptimizationFlags), matrix(matrix) {
         SkASSERT(fp);
-        fp->setSampledWithExplicitCoords();
-        fp_index = this->registerChildProcessor(std::move(fp));
+        fp_index = this->registerExplicitlySampledChild(std::move(fp));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/generated/GrEllipseEffect.h b/src/gpu/effects/generated/GrEllipseEffect.h
index e51f364..5c05950 100644
--- a/src/gpu/effects/generated/GrEllipseEffect.h
+++ b/src/gpu/effects/generated/GrEllipseEffect.h
@@ -62,7 +62,7 @@
             , center(center)
             , radii(radii) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h b/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h
index 9353750..25f10b8 100644
--- a/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h
+++ b/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h
@@ -51,7 +51,7 @@
                                 (kConstantOutputForConstantInput_OptimizationFlag |
                                  kPreservesOpaqueInput_OptimizationFlag)) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrLumaColorFilterEffect.h b/src/gpu/effects/generated/GrLumaColorFilterEffect.h
index 751ac73..274958e 100644
--- a/src/gpu/effects/generated/GrLumaColorFilterEffect.h
+++ b/src/gpu/effects/generated/GrLumaColorFilterEffect.h
@@ -46,7 +46,7 @@
                                                     : kAll_OptimizationFlags) &
                                 kConstantOutputForConstantInput_OptimizationFlag) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrMagnifierEffect.h b/src/gpu/effects/generated/GrMagnifierEffect.h
index 33b604e..aff287f 100644
--- a/src/gpu/effects/generated/GrMagnifierEffect.h
+++ b/src/gpu/effects/generated/GrMagnifierEffect.h
@@ -58,8 +58,7 @@
             , xInvInset(xInvInset)
             , yInvInset(yInvInset) {
         SkASSERT(src);
-        src->setSampledWithExplicitCoords();
-        src_index = this->registerChildProcessor(std::move(src));
+        src_index = this->registerExplicitlySampledChild(std::move(src));
         this->addCoordTransform(&fCoordTransform0);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrMixerEffect.h b/src/gpu/effects/generated/GrMixerEffect.h
index 2b0ba47..391fbf6 100644
--- a/src/gpu/effects/generated/GrMixerEffect.h
+++ b/src/gpu/effects/generated/GrMixerEffect.h
@@ -56,9 +56,9 @@
             : INHERITED(kGrMixerEffect_ClassID, (OptimizationFlags)OptFlags(fp0, fp1))
             , weight(weight) {
         SkASSERT(fp0);
-        fp0_index = this->registerChildProcessor(std::move(fp0));
+        fp0_index = this->registerChild(std::move(fp0));
         if (fp1) {
-            fp1_index = this->registerChildProcessor(std::move(fp1));
+            fp1_index = this->registerChild(std::move(fp1));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
index 0485874..988b1ca 100644
--- a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
+++ b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
@@ -61,7 +61,7 @@
             , uniformColor(uniformColor)
             , literalColor(literalColor) {
         SkASSERT(fp);
-        fp_index = this->registerChildProcessor(std::move(fp));
+        fp_index = this->registerChild(std::move(fp));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h b/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h
index 513415a..4b5fdcc 100644
--- a/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h
+++ b/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h
@@ -53,7 +53,7 @@
                                 (kConstantOutputForConstantInput_OptimizationFlag |
                                  kPreservesOpaqueInput_OptimizationFlag)) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/generated/GrRRectBlurEffect.h b/src/gpu/effects/generated/GrRRectBlurEffect.h
index 1a28302..32efd14 100644
--- a/src/gpu/effects/generated/GrRRectBlurEffect.h
+++ b/src/gpu/effects/generated/GrRRectBlurEffect.h
@@ -139,11 +139,10 @@
             , rect(rect)
             , cornerRadius(cornerRadius) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
         SkASSERT(ninePatchFP);
-        ninePatchFP->setSampledWithExplicitCoords();
-        ninePatchFP_index = this->registerChildProcessor(std::move(ninePatchFP));
+        ninePatchFP_index = this->registerExplicitlySampledChild(std::move(ninePatchFP));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/generated/GrRectBlurEffect.h b/src/gpu/effects/generated/GrRectBlurEffect.h
index f2fc47c..9b45f1e 100644
--- a/src/gpu/effects/generated/GrRectBlurEffect.h
+++ b/src/gpu/effects/generated/GrRectBlurEffect.h
@@ -145,11 +145,10 @@
             , rect(rect)
             , isFast(isFast) {
         if (inputFP) {
-            inputFP_index = this->registerChildProcessor(std::move(inputFP));
+            inputFP_index = this->registerChild(std::move(inputFP));
         }
         SkASSERT(integral);
-        integral->setSampledWithExplicitCoords();
-        integral_index = this->registerChildProcessor(std::move(integral));
+        integral_index = this->registerExplicitlySampledChild(std::move(integral));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
index 334b35b..4d2ee7e 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
@@ -166,7 +166,9 @@
                     localCoords = tr.fLocalCoords.c_str();
                 }
                 vb->codeAppend("{\n");
-                uniformHandler->writeUniformMappings(tr.fFP->sampleMatrix().fOwner, vb);
+                if (tr.fFP->sampleMatrix().fOwner) {
+                    uniformHandler->writeUniformMappings(tr.fFP->sampleMatrix().fOwner, vb);
+                }
                 if (tr.fType == kFloat2_GrSLType) {
                     vb->codeAppendf("%s = (%s * %s * %s).xy", tr.fName,
                                     tr.fFP->sampleMatrix().fExpression.c_str(), tr.fMatrix.c_str(),
diff --git a/src/gpu/gradients/generated/GrClampedGradientEffect.h b/src/gpu/gradients/generated/GrClampedGradientEffect.h
index 9771deb..eee25ff 100644
--- a/src/gpu/gradients/generated/GrClampedGradientEffect.h
+++ b/src/gpu/gradients/generated/GrClampedGradientEffect.h
@@ -57,9 +57,9 @@
             , makePremul(makePremul)
             , colorsAreOpaque(colorsAreOpaque) {
         SkASSERT(colorizer);
-        colorizer_index = this->registerChildProcessor(std::move(colorizer));
+        colorizer_index = this->registerChild(std::move(colorizer));
         SkASSERT(gradLayout);
-        gradLayout_index = this->registerChildProcessor(std::move(gradLayout));
+        gradLayout_index = this->registerChild(std::move(gradLayout));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/gradients/generated/GrTextureGradientColorizer.h b/src/gpu/gradients/generated/GrTextureGradientColorizer.h
index 8d886ed..b49637a 100644
--- a/src/gpu/gradients/generated/GrTextureGradientColorizer.h
+++ b/src/gpu/gradients/generated/GrTextureGradientColorizer.h
@@ -33,8 +33,7 @@
     GrTextureGradientColorizer(std::unique_ptr<GrFragmentProcessor> textureFP)
             : INHERITED(kGrTextureGradientColorizer_ClassID, kNone_OptimizationFlags) {
         SkASSERT(textureFP);
-        textureFP->setSampledWithExplicitCoords();
-        textureFP_index = this->registerChildProcessor(std::move(textureFP));
+        textureFP_index = this->registerExplicitlySampledChild(std::move(textureFP));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/gradients/generated/GrTiledGradientEffect.h b/src/gpu/gradients/generated/GrTiledGradientEffect.h
index 9d77bb7..4fbf2d3 100644
--- a/src/gpu/gradients/generated/GrTiledGradientEffect.h
+++ b/src/gpu/gradients/generated/GrTiledGradientEffect.h
@@ -52,9 +52,9 @@
             , makePremul(makePremul)
             , colorsAreOpaque(colorsAreOpaque) {
         SkASSERT(colorizer);
-        colorizer_index = this->registerChildProcessor(std::move(colorizer));
+        colorizer_index = this->registerChild(std::move(colorizer));
         SkASSERT(gradLayout);
-        gradLayout_index = this->registerChildProcessor(std::move(gradLayout));
+        gradLayout_index = this->registerChild(std::move(gradLayout));
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/shaders/SkPerlinNoiseShader.cpp b/src/shaders/SkPerlinNoiseShader.cpp
index ed5745c..a17d750 100644
--- a/src/shaders/SkPerlinNoiseShader.cpp
+++ b/src/shaders/SkPerlinNoiseShader.cpp
@@ -785,10 +785,8 @@
             , fNumOctaves(numOctaves)
             , fStitchTiles(stitchTiles)
             , fPaintingData(std::move(paintingData)) {
-        permutationsFP->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(permutationsFP));
-        noiseFP->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(noiseFP));
+        this->registerExplicitlySampledChild(std::move(permutationsFP));
+        this->registerExplicitlySampledChild(std::move(noiseFP));
         fCoordTransform = GrCoordTransform(matrix);
         this->addCoordTransform(&fCoordTransform);
     }
@@ -1154,10 +1152,8 @@
             , fOctaves(octaves)
             , fZ(z)
             , fPaintingData(std::move(paintingData)) {
-        permutationsFP->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(permutationsFP));
-        gradientFP->setSampledWithExplicitCoords();
-        this->registerChildProcessor(std::move(gradientFP));
+        this->registerExplicitlySampledChild(std::move(permutationsFP));
+        this->registerExplicitlySampledChild(std::move(gradientFP));
         fCoordTransform = GrCoordTransform(matrix);
         this->addCoordTransform(&fCoordTransform);
     }
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index 5878b12..66b020c 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -122,13 +122,17 @@
                 return;
             }
             int64_t index = ((IntLiteral&) *i.fIndex).fValue;
+            if (index != 0) {
+                fErrors.error(i.fIndex->fOffset, "Only sk_TransformedCoords2D[0] is allowed");
+                return;
+            }
             String name = "sk_TransformedCoords2D_" + to_string(index);
             fFormatArgs.push_back(name + ".c_str()");
-            if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) {
+            if (!fAccessLocalCoordsDirectly) {
+                fAccessLocalCoordsDirectly = true;
                 addExtraEmitCodeLine("SkString " + name +
                                      " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" +
                                      to_string(index) + "].fVaryingPoint, _outer.sampleMatrix());");
-                fWrittenTransformedCoords.insert(index);
             }
             return;
         } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) {
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index 803270c..357e7c1 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -123,7 +123,9 @@
     std::vector<String> fExtraEmitCodeBlocks;
 
     std::vector<String> fFormatArgs;
-    std::set<int> fWrittenTransformedCoords;
+    // true if the sksl referenced sk_TransformedCoords[0]
+    bool fAccessLocalCoordsDirectly = false;
+
     // if true, we are writing a C++ expression instead of a GLSL expression
     bool fCPPMode = false;
     bool fInMain = false;
diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp
index f53b572..5d4195b 100644
--- a/src/sksl/SkSLHCodeGenerator.cpp
+++ b/src/sksl/SkSLHCodeGenerator.cpp
@@ -282,35 +282,45 @@
             } else {
                 this->writef("        SkASSERT(%s);", String(param->fName).c_str());
             }
-            if (fSectionAndParameterHelper.hasCoordOverrides(*param)) {
-                this->writef("            %s->setSampledWithExplicitCoords();",
-                             String(param->fName).c_str());
-            }
+
+            bool explicitCoords = fSectionAndParameterHelper.hasCoordOverrides(*param);
             SampleMatrix matrix = SampleMatrix::Make(fProgram, *param);
-            switch (matrix.fKind) {
-                case SampleMatrix::Kind::kVariable:
-                    this->writef("            %s->setSampleMatrix(SkSL::SampleMatrix("
-                                                     "SkSL::SampleMatrix::Kind::kVariable));",
-                                 String(param->fName).c_str());
-                    break;
-                case SampleMatrix::Kind::kConstantOrUniform:
-                    this->writef("            %s->setSampleMatrix(SkSL::SampleMatrix("
-                                 "SkSL::SampleMatrix::Kind::kConstantOrUniform, this, \"%s\"));",
-                                 String(param->fName).c_str(),
-                                 matrix.fExpression.c_str());
-                    break;
-                case SampleMatrix::Kind::kMixed:
-                    this->writef("            %s->setSampleMatrix(SkSL::SampleMatrix("
-                                 "SkSL::SampleMatrix::Kind::kMixed, this, \"%s\"));",
-                                 String(param->fName).c_str(),
-                                 matrix.fExpression.c_str());
-                    break;
-                case SampleMatrix::Kind::kNone:
-                    break;
+
+            String registerFunc;
+            String matrixArg;
+            String explicitArg;
+
+            if (explicitCoords && matrix.fKind == SampleMatrix::Kind::kNone) {
+                registerFunc = "registerExplicitlySampledChild";
+            } else {
+                registerFunc = "registerChild";
+                if (explicitCoords) {
+                    explicitArg = ", true";
+                }
+                switch(matrix.fKind) {
+                    case SampleMatrix::Kind::kVariable:
+                        matrixArg.appendf(", SkSL::SampleMatrix::MakeVariable()");
+                        break;
+                    case SampleMatrix::Kind::kConstantOrUniform:
+                        matrixArg.appendf(", SkSL::SampleMatrix::MakeConstUniform(\"%s\")",
+                                          matrix.fExpression.c_str());
+                        break;
+                    case SampleMatrix::Kind::kMixed:
+                        // Mixed is only produced when combining FPs, not from analysis of sksl
+                        SkASSERT(false);
+                        break;
+                    case SampleMatrix::Kind::kNone:
+                        break;
+                }
             }
-            this->writef("            %s_index = this->registerChildProcessor(std::move(%s));",
+
+            this->writef("            %s_index = this->%s(std::move(%s)%s%s);",
                          FieldName(String(param->fName).c_str()).c_str(),
-                         String(param->fName).c_str());
+                         registerFunc.c_str(),
+                         String(param->fName).c_str(),
+                         matrixArg.c_str(),
+                         explicitArg.c_str());
+
             if (param->fType.kind() == Type::kNullable_Kind) {
                 this->writef("       }");
             }
diff --git a/src/sksl/SkSLSampleMatrix.cpp b/src/sksl/SkSLSampleMatrix.cpp
index a15e48e..9b07f59 100644
--- a/src/sksl/SkSLSampleMatrix.cpp
+++ b/src/sksl/SkSLSampleMatrix.cpp
@@ -32,7 +32,7 @@
 
 SampleMatrix SampleMatrix::merge(const SampleMatrix& other) {
     if (fKind == Kind::kVariable || other.fKind == Kind::kVariable) {
-        *this = SampleMatrix(Kind::kVariable);
+        *this = SampleMatrix::MakeVariable();
         return *this;
     }
     if (other.fKind == Kind::kConstantOrUniform) {
@@ -40,7 +40,7 @@
             if (fExpression == other.fExpression) {
                 return *this;
             }
-            *this = SampleMatrix(Kind::kVariable);
+            *this = SampleMatrix::MakeVariable();
             return *this;
         }
         SkASSERT(fKind == Kind::kNone);
@@ -94,10 +94,9 @@
                 fc.fArguments[0]->fKind == Expression::kVariableReference_Kind &&
                 &((VariableReference&) *fc.fArguments[0]).fVariable == &fFP) {
                 if (fc.fArguments.back()->isConstantOrUniform()) {
-                    return SampleMatrix(SampleMatrix::Kind::kConstantOrUniform, nullptr,
-                                        fc.fArguments.back()->description());
+                    return SampleMatrix::MakeConstUniform(fc.fArguments.back()->description());
                 } else {
-                    return SampleMatrix(SampleMatrix::Kind::kVariable);
+                    return SampleMatrix::MakeVariable();
                 }
             }
             SampleMatrix result;
diff --git a/src/sksl/SkSLSampleMatrix.h b/src/sksl/SkSLSampleMatrix.h
index 59e1fc0..41c0cb6 100644
--- a/src/sksl/SkSLSampleMatrix.h
+++ b/src/sksl/SkSLSampleMatrix.h
@@ -27,7 +27,8 @@
         // No sample(child, matrix) call affects the FP.
         kNone,
         // The FP is sampled with a matrix whose value is fixed and based only on constants or
-        // uniforms, and thus the transform can be hoisted to the vertex shader.
+        // uniforms, and thus the transform can be hoisted to the vertex shader (assuming that
+        // its parent can also be hoisted, i.e. not sampled explicitly).
         kConstantOrUniform,
         // The FP is sampled with a non-constant/uniform value, or sampled multiple times, and
         // thus the transform cannot be hoisted to the vertex shader.
@@ -38,20 +39,18 @@
         kMixed,
     };
 
+    // Make a SampleMatrix with kNone for its kind. Will not have an expression or have perspective.
     SampleMatrix()
-    : fOwner(nullptr)
-    , fKind(Kind::kNone) {}
+            : fOwner(nullptr)
+            , fKind(Kind::kNone) {}
 
-    SampleMatrix(Kind kind)
-    : fOwner(nullptr)
-    , fKind(kind) {
-        SkASSERT(kind == Kind::kNone || kind == Kind::kVariable);
+    static SampleMatrix MakeConstUniform(String expression) {
+        return SampleMatrix(Kind::kConstantOrUniform, expression);
     }
 
-    SampleMatrix(Kind kind, GrFragmentProcessor* owner, String expression)
-    : fOwner(owner)
-    , fKind(kind)
-    , fExpression(expression) {}
+    static SampleMatrix MakeVariable() {
+        return SampleMatrix(Kind::kVariable, "");
+    }
 
     static SampleMatrix Make(const Program& program, const Variable& fp);
 
@@ -76,12 +75,20 @@
     }
 #endif
 
+    // TODO(michaelludwig): fOwner and fBase are going away; owner is filled in automatically when
+    // a matrix-sampled FP is registered as a child.
     GrFragmentProcessor* fOwner;
     Kind fKind;
     // The constant or uniform expression representing the matrix (will be the empty string when
     // kind == kNone or kVariable)
     String fExpression;
     const GrFragmentProcessor* fBase = nullptr;
+
+private:
+    SampleMatrix(Kind kind, String expression)
+            : fOwner(nullptr)
+            , fKind(kind)
+            , fExpression(expression) {}
 };
 
 } // namespace
diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp
index e89f524..9bb4bff 100644
--- a/tests/LazyProxyTest.cpp
+++ b/tests/LazyProxyTest.cpp
@@ -148,7 +148,7 @@
                     GrSurfaceProxy::UseAllocator::kYes);
             auto atlasEffect = GrTextureEffect::Make({fLazyProxy, kOrigin, readSwizzle},
                                                      kPremul_SkAlphaType);
-            this->registerChildProcessor(std::move(atlasEffect));
+            this->registerChild(std::move(atlasEffect));
         }
 
     private:
diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp
index 558e33c..dda51e3 100644
--- a/tests/ProcessorTest.cpp
+++ b/tests/ProcessorTest.cpp
@@ -110,13 +110,13 @@
     TestFP(const SkTArray<GrSurfaceProxyView>& views)
             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags) {
         for (const auto& view : views) {
-            this->registerChildProcessor(GrTextureEffect::Make(view, kUnknown_SkAlphaType));
+            this->registerChild(GrTextureEffect::Make(view, kUnknown_SkAlphaType));
         }
     }
 
     TestFP(std::unique_ptr<GrFragmentProcessor> child)
             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags) {
-        this->registerChildProcessor(std::move(child));
+        this->registerChild(std::move(child));
     }
 
     explicit TestFP(const TestFP& that) : INHERITED(kTestFP_ClassID, that.optimizationFlags()) {
diff --git a/tests/ProgramsTest.cpp b/tests/ProgramsTest.cpp
index 22abfe0..a692517 100644
--- a/tests/ProgramsTest.cpp
+++ b/tests/ProgramsTest.cpp
@@ -126,7 +126,7 @@
 
     BlockInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child)
             : INHERITED(kBlockInputFragmentProcessor_ClassID, kNone_OptimizationFlags) {
-        this->registerChildProcessor(std::move(child));
+        this->registerChild(std::move(child));
     }
 
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {}
diff --git a/tests/SkSLFPTest.cpp b/tests/SkSLFPTest.cpp
index 3596ca2..9c6eea8 100644
--- a/tests/SkSLFPTest.cpp
+++ b/tests/SkSLFPTest.cpp
@@ -545,8 +545,8 @@
              }
          )__SkSL__",
          /*expectedH=*/{
-            "child1_index = this->registerChildProcessor(std::move(child1));",
-            "child2_index = this->registerChildProcessor(std::move(child2));"
+            "child1_index = this->registerChild(std::move(child1));",
+            "child2_index = this->registerChild(std::move(child2));"
          },
          /*expectedCPP=*/{
             "SkString _sample149;\n",
@@ -576,8 +576,8 @@
              }
          )__SkSL__",
          /*expectedH=*/{
-            "child1_index = this->registerChildProcessor(std::move(child1));",
-            "child2_index = this->registerChildProcessor(std::move(child2));"
+            "child1_index = this->registerChild(std::move(child1));",
+            "child2_index = this->registerChild(std::move(child2));"
          },
          /*expectedCPP=*/{
             "SkString _input198(\"childIn\");",
@@ -605,7 +605,7 @@
              }
          )__SkSL__",
          /*expectedH=*/{
-            "child_index = this->registerChildProcessor(std::move(child));",
+            "child_index = this->registerChild(std::move(child));",
          },
          /*expectedCPP=*/{
             "SkString _input106 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
@@ -630,8 +630,8 @@
              }
          )__SkSL__",
          /*expectedH=*/{
-            "child1_index = this->registerChildProcessor(std::move(child1));",
-            "child2_index = this->registerChildProcessor(std::move(child2));"
+            "child1_index = this->registerChild(std::move(child1));",
+            "child2_index = this->registerChild(std::move(child2));"
          },
          /*expectedCPP=*/{
             "SkString _input177 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
@@ -664,7 +664,7 @@
              }
          )__SkSL__",
          /*expectedH=*/{
-            "child_index = this->registerChildProcessor(std::move(child));"
+            "child_index = this->registerChild(std::move(child));"
          },
          /*expectedCPP=*/{
             "hasCap = sk_Caps.externalTextureSupport;",
@@ -702,7 +702,7 @@
              }
          )__SkSL__",
          /*expectedH=*/{
-            "child_index = this->registerChildProcessor(std::move(child));"
+            "child_index = this->registerChild(std::move(child));"
          },
          /*expectedCPP=*/{
             "fragBuilder->codeAppendf(\n"
@@ -738,7 +738,7 @@
          }
          )__SkSL__",
          /*expectedH=*/{
-            "child_index = this->registerChildProcessor(std::move(child));"
+            "child_index = this->registerChild(std::move(child));"
          },
          /*expectedCPP=*/{
             "opaque = _outer.childProcessor(_outer.child_index).preservesOpaqueInput();",
@@ -814,7 +814,9 @@
                  sk_OutColor = sample(child) + sample(child, sk_TransformedCoords2D[0] / 2);
              }
          )__SkSL__",
-         /*expectedH=*/{},
+         /*expectedH=*/{
+             "child_index = this->registerExplicitlySampledChild(std::move(child));"
+         },
          /*expectedCPP=*/{
             "SkString _sample150;\n",
             "_sample150 = this->invokeChild(_outer.child_index, args);\n",