Remove array of TextureSampler pointers from GrIOResourceProcessor.

Instead store sampler count on base class and subclasses implement a
virtual to get the ith sampler.

Change-Id: I13e2447a6467a09761d8615acb4aa360b87b1476
Reviewed-on: https://skia-review.googlesource.com/141563
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/effects/SkHighContrastFilter.cpp b/src/effects/SkHighContrastFilter.cpp
index 2d0b0f9..48bcb40 100644
--- a/src/effects/SkHighContrastFilter.cpp
+++ b/src/effects/SkHighContrastFilter.cpp
@@ -177,8 +177,7 @@
     HighContrastFilterEffect(const SkHighContrastConfig& config, bool linearize)
         : INHERITED(kHighContrastFilterEffect_ClassID, kNone_OptimizationFlags)
         , fConfig(config)
-        , fLinearize(linearize) {
-    }
+        , fLinearize(linearize) {}
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index fa68d11..25cfa6b 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -316,6 +316,8 @@
 
     ColorTableEffect(sk_sp<GrTextureProxy> proxy, sk_sp<GrTextureStripAtlas> atlas, int row);
 
+    const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     TextureSampler fTextureSampler;
@@ -455,7 +457,7 @@
         , fTextureSampler(std::move(proxy))
         , fAtlas(std::move(atlas))
         , fRow(row) {
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 ColorTableEffect::~ColorTableEffect() {
diff --git a/src/effects/imagefilters/SkDisplacementMapEffect.cpp b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
index 026c03e..2ab8c5e 100644
--- a/src/effects/imagefilters/SkDisplacementMapEffect.cpp
+++ b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
@@ -208,6 +208,10 @@
                             sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix,
                             sk_sp<GrTextureProxy> color, const SkISize& colorDimensions);
 
+    const TextureSampler& onTextureSampler(int i) const override {
+        return IthTextureSampler(i, fDisplacementSampler, fColorSampler);
+    }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     GrCoordTransform            fDisplacementTransform;
@@ -461,9 +465,8 @@
         , fYChannelSelector(yChannelSelector)
         , fScale(scale) {
     this->addCoordTransform(&fDisplacementTransform);
-    this->addTextureSampler(&fDisplacementSampler);
     this->addCoordTransform(&fColorTransform);
-    this->addTextureSampler(&fColorSampler);
+    this->setTextureSamplerCnt(2);
 }
 
 GrDisplacementMapEffect::GrDisplacementMapEffect(const GrDisplacementMapEffect& that)
@@ -478,9 +481,8 @@
         , fYChannelSelector(that.fYChannelSelector)
         , fScale(that.fScale) {
     this->addCoordTransform(&fDisplacementTransform);
-    this->addTextureSampler(&fDisplacementSampler);
     this->addCoordTransform(&fColorTransform);
-    this->addTextureSampler(&fColorSampler);
+    this->setTextureSamplerCnt(2);
 }
 
 GrDisplacementMapEffect::~GrDisplacementMapEffect() {}
diff --git a/src/effects/imagefilters/SkLightingImageFilter.cpp b/src/effects/imagefilters/SkLightingImageFilter.cpp
index 9a560b4..486a3ef 100644
--- a/src/effects/imagefilters/SkLightingImageFilter.cpp
+++ b/src/effects/imagefilters/SkLightingImageFilter.cpp
@@ -613,6 +613,8 @@
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
 private:
+    const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
+
     GrCoordTransform fCoordTransform;
     GrTextureDomain fDomain;
     TextureSampler fTextureSampler;
@@ -1696,7 +1698,7 @@
         , fFilterMatrix(matrix)
         , fBoundaryMode(boundaryMode) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 GrLightingEffect::GrLightingEffect(const GrLightingEffect& that)
@@ -1709,7 +1711,7 @@
         , fFilterMatrix(that.fFilterMatrix)
         , fBoundaryMode(that.fBoundaryMode) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
diff --git a/src/effects/imagefilters/SkMorphologyImageFilter.cpp b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
index 899c5a1..99060b9 100644
--- a/src/effects/imagefilters/SkMorphologyImageFilter.cpp
+++ b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
@@ -167,6 +167,8 @@
 
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSampler; }
+
     GrMorphologyEffect(sk_sp<GrTextureProxy>, Direction, int radius, Type, const float range[2]);
     explicit GrMorphologyEffect(const GrMorphologyEffect&);
 
@@ -317,7 +319,7 @@
         , fType(type)
         , fUseRange(SkToBool(range)) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     if (fUseRange) {
         fRange[0] = range[0];
         fRange[1] = range[1];
@@ -333,7 +335,7 @@
         , fType(that.fType)
         , fUseRange(that.fUseRange) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     if (that.fUseRange) {
         fRange[0] = that.fRange[0];
         fRange[1] = that.fRange[1];
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index d4006e7..63dc39c 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -163,8 +163,7 @@
     private:
         SwizzleFragmentProcessor(const GrSwizzle& swizzle)
                 : INHERITED(kSwizzleFragmentProcessor_ClassID, kAll_OptimizationFlags)
-                , fSwizzle(swizzle) {
-        }
+                , fSwizzle(swizzle) {}
 
         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
             class GLFP : public GrGLSLFragmentProcessor {
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index e47d868..cc24b64 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -12,6 +12,8 @@
 #include "GrProcessor.h"
 #include "GrShaderVar.h"
 
+class GrCoordTransform;
+
 /*
  * The GrPrimitiveProcessor represents some kind of geometric primitive.  This includes the shape
  * of the primitive and the inherent color of the primitive.  The GrPrimitiveProcessor is
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 1be97cf..43b4213 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -128,31 +128,27 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrResourceIOProcessor::addTextureSampler(const TextureSampler* access) {
-    fTextureSamplers.push_back(access);
-}
-
 void GrResourceIOProcessor::addPendingIOs() const {
-    for (const auto& sampler : fTextureSamplers) {
-        sampler->programProxy()->markPendingIO();
+    for (int i = 0; i < fNumTextureSamplers; ++i) {
+        this->textureSampler(i).programProxy()->markPendingIO();
     }
 }
 
 void GrResourceIOProcessor::removeRefs() const {
-    for (const auto& sampler : fTextureSamplers) {
-        sampler->programProxy()->removeRef();
+    for (int i = 0; i < fNumTextureSamplers; ++i) {
+        this->textureSampler(i).programProxy()->removeRef();
     }
 }
 
 void GrResourceIOProcessor::pendingIOComplete() const {
-    for (const auto& sampler : fTextureSamplers) {
-        sampler->programProxy()->pendingIOComplete();
+    for (int i = 0; i < fNumTextureSamplers; ++i) {
+        this->textureSampler(i).programProxy()->pendingIOComplete();
     }
 }
 
 bool GrResourceIOProcessor::instantiate(GrResourceProvider* resourceProvider) const {
-    for (const auto& sampler : fTextureSamplers) {
-        if (!sampler->instantiate(resourceProvider)) {
+    for (int i = 0; i < fNumTextureSamplers; ++i) {
+        if (!this->textureSampler(i).instantiate(resourceProvider)) {
             return false;
         }
     }
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 5d83ce3..586f6d2 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -23,8 +23,6 @@
 #include "SkString.h"
 
 class GrContext;
-class GrCoordTransform;
-class GrInvariantOutput;
 class GrResourceProvider;
 
 /**
@@ -203,24 +201,31 @@
 public:
     class TextureSampler;
 
-    int numTextureSamplers() const { return fTextureSamplers.count(); }
+    int numTextureSamplers() const { return fNumTextureSamplers; }
 
-    /** Returns the access pattern for the texture at index. index must be valid according to
-        numTextureSamplers(). */
-    const TextureSampler& textureSampler(int index) const { return *fTextureSamplers[index]; }
+    /** Gets a TextureSampler which is a combination of a GrTextureProxy and how it is sampled.
+     * index must be valid according to numTextureSamplers(). */
+    const TextureSampler& textureSampler(int index) const {
+        SkASSERT(index >= 0 && index < fNumTextureSamplers);
+        return this->onTextureSampler(index);
+    }
 
     bool instantiate(GrResourceProvider* resourceProvider) const;
 
 protected:
+    template <typename... Args>
+    static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0,
+                                                   const Args&... samps) {
+        return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...);
+    }
+    inline static const TextureSampler& IthTextureSampler(int i);
+
     GrResourceIOProcessor(ClassID classID) : INHERITED(classID) {}
 
-    /**
-     * Subclasses call these from their constructor to register sampler sources. The processor
-     * subclass manages the lifetime of the objects (these functions only store pointers). The
-     * TextureSampler instances are typically member fields of the GrProcessor subclass. These must
-     * only be called from the constructor because GrProcessors are immutable.
-     */
-    void addTextureSampler(const TextureSampler*);
+    void setTextureSamplerCnt(int numTextureSamplers) {
+        SkASSERT(numTextureSamplers >= 0);
+        fNumTextureSamplers = numTextureSamplers;
+    }
 
     bool hasSameSamplers(const GrResourceIOProcessor&) const;
 
@@ -230,8 +235,9 @@
     void pendingIOComplete() const;
 
 private:
-    SkSTArray<4, const TextureSampler*, true> fTextureSamplers;
+    virtual const TextureSampler& onTextureSampler(int index) const { return IthTextureSampler(0); }
 
+    int fNumTextureSamplers = 0;
     typedef GrProcessor INHERITED;
 };
 
@@ -306,4 +312,10 @@
     GrShaderFlags fVisibility;
 };
 
+const GrResourceIOProcessor::TextureSampler& GrResourceIOProcessor::IthTextureSampler(int i) {
+    SK_ABORT("Illegal texture sampler index");
+    static const TextureSampler kBogus;
+    return kBogus;
+}
+
 #endif
diff --git a/src/gpu/ccpr/GrCCClipProcessor.cpp b/src/gpu/ccpr/GrCCClipProcessor.cpp
index 91d6892..0c1f0e8 100644
--- a/src/gpu/ccpr/GrCCClipProcessor.cpp
+++ b/src/gpu/ccpr/GrCCClipProcessor.cpp
@@ -22,7 +22,7 @@
         , fOverrideFillType(overrideFillType)
         , fAtlasAccess(sk_ref_sp(fClipPath->atlasLazyProxy()), GrSamplerState::Filter::kNearest,
                        GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag) {
-    this->addTextureSampler(&fAtlasAccess);
+    this->setTextureSamplerCnt(1);
 }
 
 std::unique_ptr<GrFragmentProcessor> GrCCClipProcessor::clone() const {
diff --git a/src/gpu/ccpr/GrCCClipProcessor.h b/src/gpu/ccpr/GrCCClipProcessor.h
index 8c670e1..802f337 100644
--- a/src/gpu/ccpr/GrCCClipProcessor.h
+++ b/src/gpu/ccpr/GrCCClipProcessor.h
@@ -26,6 +26,7 @@
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
 
 private:
     const GrCCClipPath* const fClipPath;
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index 450b74c..ae3cba3 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -100,7 +100,7 @@
     this->setVertexAttributeCnt(1);
 
     fAtlasAccess.instantiate(resourceProvider);
-    this->addTextureSampler(&fAtlasAccess);
+    this->setTextureSamplerCnt(1);
 
     if (!viewMatrixIfUsingLocalCoords.invert(&fLocalMatrix)) {
         fLocalMatrix.setIdentity();
diff --git a/src/gpu/ccpr/GrCCPathProcessor.h b/src/gpu/ccpr/GrCCPathProcessor.h
index 878cd1c..752083a 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.h
+++ b/src/gpu/ccpr/GrCCPathProcessor.h
@@ -93,6 +93,7 @@
 private:
     const Attribute& onVertexAttribute(int i) const override { return kEdgeNormsAttrib; }
     const Attribute& onInstanceAttribute(int i) const override { return kInstanceAttribs[i]; }
+    const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
 
     const TextureSampler fAtlasAccess;
     SkMatrix fLocalMatrix;
diff --git a/src/gpu/effects/GrAlphaThresholdFragmentProcessor.cpp b/src/gpu/effects/GrAlphaThresholdFragmentProcessor.cpp
index 176e812..6e12bd4 100644
--- a/src/gpu/effects/GrAlphaThresholdFragmentProcessor.cpp
+++ b/src/gpu/effects/GrAlphaThresholdFragmentProcessor.cpp
@@ -93,12 +93,16 @@
         , fInnerThreshold(src.fInnerThreshold)
         , fOuterThreshold(src.fOuterThreshold)
         , fMaskCoordTransform(src.fMaskCoordTransform) {
-    this->addTextureSampler(&fMask);
+    this->setTextureSamplerCnt(1);
     this->addCoordTransform(&fMaskCoordTransform);
 }
 std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrAlphaThresholdFragmentProcessor::onTextureSampler(
+        int index) const {
+    return IthTextureSampler(index, fMask);
+}
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor);
 #if GR_TEST_UTILS
 std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate(
diff --git a/src/gpu/effects/GrAlphaThresholdFragmentProcessor.h b/src/gpu/effects/GrAlphaThresholdFragmentProcessor.h
index 1c0cd2e..74811d3 100644
--- a/src/gpu/effects/GrAlphaThresholdFragmentProcessor.h
+++ b/src/gpu/effects/GrAlphaThresholdFragmentProcessor.h
@@ -40,12 +40,13 @@
             , fMaskCoordTransform(
                       SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())),
                       fMask.proxy()) {
-        this->addTextureSampler(&fMask);
+        this->setTextureSamplerCnt(1);
         this->addCoordTransform(&fMaskCoordTransform);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     TextureSampler fMask;
     float fInnerThreshold;
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 803f290..6607efc 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -125,7 +125,7 @@
         , fTextureSampler(std::move(proxy),
                           GrSamplerState(wrapModes, GrSamplerState::Filter::kNearest)) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 GrBicubicEffect::GrBicubicEffect(sk_sp<GrTextureProxy> proxy,
@@ -136,7 +136,7 @@
         , fDomain(proxy.get(), domain, GrTextureDomain::kClamp_Mode)
         , fTextureSampler(std::move(proxy)) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 GrBicubicEffect::GrBicubicEffect(const GrBicubicEffect& that)
@@ -145,7 +145,7 @@
         , fDomain(that.fDomain)
         , fTextureSampler(that.fTextureSampler) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 void GrBicubicEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index 1d70103..45c416f 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -70,6 +70,8 @@
 
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
+    const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
+
     GrCoordTransform fCoordTransform;
     GrTextureDomain fDomain;
     TextureSampler fTextureSampler;
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 2594f40..32da45c 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -151,10 +151,9 @@
 
     for (int i = 0; i < numActiveProxies; ++i) {
         SkASSERT(proxies[i]);
-
         fTextureSamplers[i].reset(std::move(proxies[i]), params);
-        this->addTextureSampler(&fTextureSamplers[i]);
     }
+    this->setTextureSamplerCnt(numActiveProxies);
 }
 
 const GrPrimitiveProcessor::Attribute& GrBitmapTextGeoProc::onVertexAttribute(int i) const {
@@ -171,9 +170,9 @@
 
         if (!fTextureSamplers[i].isInitialized()) {
             fTextureSamplers[i].reset(std::move(proxies[i]), params);
-            this->addTextureSampler(&fTextureSamplers[i]);
         }
     }
+    this->setTextureSamplerCnt(numActiveProxies);
 }
 
 void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index 5e44497..1bc0620 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -59,6 +59,7 @@
                         const SkMatrix& localMatrix, bool usesW);
 
     const Attribute& onVertexAttribute(int i) const override;
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
 
     GrColor          fColor;
     SkMatrix         fLocalMatrix;
diff --git a/src/gpu/effects/GrCircleBlurFragmentProcessor.cpp b/src/gpu/effects/GrCircleBlurFragmentProcessor.cpp
index efd9ee7..921d69b 100644
--- a/src/gpu/effects/GrCircleBlurFragmentProcessor.cpp
+++ b/src/gpu/effects/GrCircleBlurFragmentProcessor.cpp
@@ -330,11 +330,15 @@
         , fTextureRadius(src.fTextureRadius)
         , fSolidRadius(src.fSolidRadius)
         , fBlurProfileSampler(src.fBlurProfileSampler) {
-    this->addTextureSampler(&fBlurProfileSampler);
+    this->setTextureSamplerCnt(1);
 }
 std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrCircleBlurFragmentProcessor::onTextureSampler(
+        int index) const {
+    return IthTextureSampler(index, fBlurProfileSampler);
+}
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor);
 #if GR_TEST_UTILS
 std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate(
diff --git a/src/gpu/effects/GrCircleBlurFragmentProcessor.h b/src/gpu/effects/GrCircleBlurFragmentProcessor.h
index 3670a98..373ea42 100644
--- a/src/gpu/effects/GrCircleBlurFragmentProcessor.h
+++ b/src/gpu/effects/GrCircleBlurFragmentProcessor.h
@@ -34,11 +34,12 @@
             , fTextureRadius(textureRadius)
             , fSolidRadius(solidRadius)
             , fBlurProfileSampler(std::move(blurProfileSampler)) {
-        this->addTextureSampler(&fBlurProfileSampler);
+        this->setTextureSamplerCnt(1);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     SkRect fCircleRect;
     float fTextureRadius;
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 4d5d50b..351e191 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -236,10 +236,9 @@
 
     for (int i = 0; i < numProxies; ++i) {
         SkASSERT(proxies[i]);
-
         fTextureSamplers[i].reset(std::move(proxies[i]), params);
-        this->addTextureSampler(&fTextureSamplers[i]);
     }
+    this->setTextureSamplerCnt(numProxies);
 }
 
 void GrDistanceFieldA8TextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
@@ -249,12 +248,11 @@
 
     for (int i = 0; i < numProxies; ++i) {
         SkASSERT(proxies[i]);
-
         if (!fTextureSamplers[i].isInitialized()) {
             fTextureSamplers[i].reset(std::move(proxies[i]), params);
-            this->addTextureSampler(&fTextureSamplers[i]);
         }
     }
+    this->setTextureSamplerCnt(numProxies);
 }
 
 void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
@@ -519,10 +517,9 @@
     this->setVertexAttributeCnt(3);
     for (int i = 0; i < numProxies; ++i) {
         SkASSERT(proxies[i]);
-
         fTextureSamplers[i].reset(std::move(proxies[i]), params);
-        this->addTextureSampler(&fTextureSamplers[i]);
     }
+    this->setTextureSamplerCnt(numProxies);
 }
 
 void GrDistanceFieldPathGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
@@ -535,9 +532,9 @@
 
         if (!fTextureSamplers[i].isInitialized()) {
             fTextureSamplers[i].reset(std::move(proxies[i]), params);
-            this->addTextureSampler(&fTextureSamplers[i]);
         }
     }
+    this->setTextureSamplerCnt(numProxies);
 }
 
 void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
@@ -834,10 +831,9 @@
 
     for (int i = 0; i < numProxies; ++i) {
         SkASSERT(proxies[i]);
-
         fTextureSamplers[i].reset(std::move(proxies[i]), params);
-        this->addTextureSampler(&fTextureSamplers[i]);
     }
+    this->setTextureSamplerCnt(numProxies);
 }
 
 void GrDistanceFieldLCDTextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
@@ -850,9 +846,9 @@
 
         if (!fTextureSamplers[i].isInitialized()) {
             fTextureSamplers[i].reset(std::move(proxies[i]), params);
-            this->addTextureSampler(&fTextureSamplers[i]);
         }
     }
+    this->setTextureSamplerCnt(numProxies);
 }
 
 void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index 71626fa..a0fb9d7 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -104,6 +104,8 @@
         return IthAttribute(i, fInPosition, kInColor, kInTextureCoords);
     }
 
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
+
     static constexpr int kMaxTextures = 4;
 
     TextureSampler   fTextureSamplers[kMaxTextures];
@@ -165,6 +167,7 @@
                                const GrSamplerState&, uint32_t flags);
 
     const Attribute& onVertexAttribute(int i) const override;
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
 
     SkMatrix         fMatrix;      // view matrix if perspective, local matrix otherwise
     TextureSampler   fTextureSamplers[kMaxTextures];
@@ -235,6 +238,7 @@
                                   const SkMatrix& localMatrix);
 
     const Attribute& onVertexAttribute(int) const override;
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
 
     static constexpr int kMaxTextures = 4;
 
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
index bfd3f86..f05bf42 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
@@ -223,7 +223,7 @@
         , fDirection(direction)
         , fMode(mode) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     SkASSERT(radius <= kMaxKernelRadius);
 
     fill_in_1D_gaussian_kernel(fKernel, this->width(), gaussianSigma, this->radius());
@@ -240,7 +240,7 @@
         , fDirection(that.fDirection)
         , fMode(that.fMode) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     memcpy(fKernel, that.fKernel, that.width() * sizeof(float));
     memcpy(fBounds, that.fBounds, sizeof(fBounds));
 }
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
index 6d68292..cc34feb 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
@@ -81,6 +81,8 @@
 
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
+    const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     GrCoordTransform      fCoordTransform;
diff --git a/src/gpu/effects/GrMagnifierEffect.cpp b/src/gpu/effects/GrMagnifierEffect.cpp
index 752a81b..aadd541 100644
--- a/src/gpu/effects/GrMagnifierEffect.cpp
+++ b/src/gpu/effects/GrMagnifierEffect.cpp
@@ -161,12 +161,15 @@
         , fXInvInset(src.fXInvInset)
         , fYInvInset(src.fYInvInset)
         , fSrcCoordTransform(src.fSrcCoordTransform) {
-    this->addTextureSampler(&fSrc);
+    this->setTextureSamplerCnt(1);
     this->addCoordTransform(&fSrcCoordTransform);
 }
 std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrMagnifierEffect(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrMagnifierEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, fSrc);
+}
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMagnifierEffect);
 #if GR_TEST_UTILS
 std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::TestCreate(GrProcessorTestData* d) {
diff --git a/src/gpu/effects/GrMagnifierEffect.h b/src/gpu/effects/GrMagnifierEffect.h
index 7888f9c..582e0ef 100644
--- a/src/gpu/effects/GrMagnifierEffect.h
+++ b/src/gpu/effects/GrMagnifierEffect.h
@@ -43,12 +43,13 @@
             , fXInvInset(xInvInset)
             , fYInvInset(yInvInset)
             , fSrcCoordTransform(SkMatrix::I(), fSrc.proxy()) {
-        this->addTextureSampler(&fSrc);
+        this->setTextureSamplerCnt(1);
         this->addCoordTransform(&fSrcCoordTransform);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     TextureSampler fSrc;
     SkIRect fBounds;
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index c2c1f7c..ccb32cf 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -165,7 +165,7 @@
         , fBias(SkScalarToFloat(bias) / 255.0f)
         , fConvolveAlpha(convolveAlpha) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
         fKernel[i] = SkScalarToFloat(kernel[i]);
     }
@@ -183,7 +183,7 @@
         , fBias(that.fBias)
         , fConvolveAlpha(that.fConvolveAlpha) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     memcpy(fKernel, that.fKernel, sizeof(float) * fKernelSize.width() * fKernelSize.height());
     memcpy(fKernelOffset, that.fKernelOffset, sizeof(fKernelOffset));
 }
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.h b/src/gpu/effects/GrMatrixConvolutionEffect.h
index 844f721..f20c805 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.h
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.h
@@ -75,6 +75,8 @@
 
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSampler; }
+
     GrCoordTransform fCoordTransform;
     GrTextureDomain  fDomain;
     TextureSampler   fTextureSampler;
diff --git a/src/gpu/effects/GrRRectBlurEffect.cpp b/src/gpu/effects/GrRRectBlurEffect.cpp
index 9ab844a..6101f24 100644
--- a/src/gpu/effects/GrRRectBlurEffect.cpp
+++ b/src/gpu/effects/GrRRectBlurEffect.cpp
@@ -146,11 +146,14 @@
         , fRect(src.fRect)
         , fCornerRadius(src.fCornerRadius)
         , fNinePatchSampler(src.fNinePatchSampler) {
-    this->addTextureSampler(&fNinePatchSampler);
+    this->setTextureSamplerCnt(1);
 }
 std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrRRectBlurEffect(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrRRectBlurEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, fNinePatchSampler);
+}
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
 #if GR_TEST_UTILS
 std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
diff --git a/src/gpu/effects/GrRRectBlurEffect.h b/src/gpu/effects/GrRRectBlurEffect.h
index 04af127..3e386a6 100644
--- a/src/gpu/effects/GrRRectBlurEffect.h
+++ b/src/gpu/effects/GrRRectBlurEffect.h
@@ -115,11 +115,12 @@
             , fRect(rect)
             , fCornerRadius(cornerRadius)
             , fNinePatchSampler(std::move(ninePatchSampler)) {
-        this->addTextureSampler(&fNinePatchSampler);
+        this->setTextureSamplerCnt(1);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     float fSigma;
     SkRect fRect;
diff --git a/src/gpu/effects/GrRectBlurEffect.cpp b/src/gpu/effects/GrRectBlurEffect.cpp
index 219fefa..9ade87c 100644
--- a/src/gpu/effects/GrRectBlurEffect.cpp
+++ b/src/gpu/effects/GrRectBlurEffect.cpp
@@ -149,11 +149,14 @@
         , fRect(src.fRect)
         , fSigma(src.fSigma)
         , fBlurProfile(src.fBlurProfile) {
-    this->addTextureSampler(&fBlurProfile);
+    this->setTextureSamplerCnt(1);
 }
 std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrRectBlurEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, fBlurProfile);
+}
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
 #if GR_TEST_UTILS
 std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* data) {
diff --git a/src/gpu/effects/GrRectBlurEffect.h b/src/gpu/effects/GrRectBlurEffect.h
index 8307a49..0d443c3 100644
--- a/src/gpu/effects/GrRectBlurEffect.h
+++ b/src/gpu/effects/GrRectBlurEffect.h
@@ -104,11 +104,12 @@
             , fRect(rect)
             , fSigma(sigma)
             , fBlurProfile(std::move(blurProfile), samplerParams) {
-        this->addTextureSampler(&fBlurProfile);
+        this->setTextureSamplerCnt(1);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     SkRect fRect;
     float fSigma;
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 5e3e697..0dda499 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -54,12 +54,16 @@
         , fImage(src.fImage)
         , fMatrix(src.fMatrix)
         , fImageCoordTransform(src.fImageCoordTransform) {
-    this->addTextureSampler(&fImage);
+    this->setTextureSamplerCnt(1);
     this->addCoordTransform(&fImageCoordTransform);
 }
 std::unique_ptr<GrFragmentProcessor> GrSimpleTextureEffect::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrSimpleTextureEffect(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrSimpleTextureEffect::onTextureSampler(
+        int index) const {
+    return IthTextureSampler(index, fImage);
+}
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSimpleTextureEffect);
 #if GR_TEST_UTILS
 std::unique_ptr<GrFragmentProcessor> GrSimpleTextureEffect::TestCreate(
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index fcd29b8..8a8924b 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -55,12 +55,13 @@
             , fImage(std::move(image), samplerParams)
             , fMatrix(matrix)
             , fImageCoordTransform(matrix, fImage.proxy()) {
-        this->addTextureSampler(&fImage);
+        this->setTextureSamplerCnt(1);
         this->addCoordTransform(&fImageCoordTransform);
     }
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     TextureSampler fImage;
     SkMatrix44 fMatrix;
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index e219702..ee27cc0 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -234,7 +234,7 @@
     SkASSERT(mode != GrTextureDomain::kRepeat_Mode ||
              filterMode == GrSamplerState::Filter::kNearest);
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 GrTextureDomainEffect::GrTextureDomainEffect(const GrTextureDomainEffect& that)
@@ -243,7 +243,7 @@
         , fTextureDomain(that.fTextureDomain)
         , fTextureSampler(that.fTextureSampler) {
     this->addCoordTransform(&fCoordTransform);
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 void GrTextureDomainEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
@@ -334,7 +334,7 @@
         , fTextureSampler(proxy, GrSamplerState::ClampNearest())
         , fTextureDomain(proxy.get(), GrTextureDomain::MakeTexelDomain(subset),
                          GrTextureDomain::kDecal_Mode) {
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
     fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft;
     fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop;
 }
@@ -346,7 +346,7 @@
         , fTextureSampler(that.fTextureSampler)
         , fTextureDomain(that.fTextureDomain)
         , fDeviceSpaceOffset(that.fDeviceSpaceOffset) {
-    this->addTextureSampler(&fTextureSampler);
+    this->setTextureSamplerCnt(1);
 }
 
 std::unique_ptr<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::clone() const {
diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h
index 048c8dc..b3728cb 100644
--- a/src/gpu/effects/GrTextureDomain.h
+++ b/src/gpu/effects/GrTextureDomain.h
@@ -192,6 +192,8 @@
 
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
+    const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     typedef GrFragmentProcessor INHERITED;
@@ -233,6 +235,8 @@
 
     bool onIsEqual(const GrFragmentProcessor& fp) const override;
 
+    const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     typedef GrFragmentProcessor INHERITED;
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 905445e..33dff41 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -171,9 +171,7 @@
         , fYSamplerCoordTransform(src.fYSamplerCoordTransform)
         , fUSamplerCoordTransform(src.fUSamplerCoordTransform)
         , fVSamplerCoordTransform(src.fVSamplerCoordTransform) {
-    this->addTextureSampler(&fYSampler);
-    this->addTextureSampler(&fUSampler);
-    this->addTextureSampler(&fVSampler);
+    this->setTextureSamplerCnt(3);
     this->addCoordTransform(&fYSamplerCoordTransform);
     this->addCoordTransform(&fUSamplerCoordTransform);
     this->addCoordTransform(&fVSamplerCoordTransform);
@@ -181,3 +179,6 @@
 std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::clone() const {
     return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(*this));
 }
+const GrFragmentProcessor::TextureSampler& GrYUVtoRGBEffect::onTextureSampler(int index) const {
+    return IthTextureSampler(index, fYSampler, fUSampler, fVSampler);
+}
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.h b/src/gpu/effects/GrYUVtoRGBEffect.h
index 6cc468e..0b3393c 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.h
+++ b/src/gpu/effects/GrYUVtoRGBEffect.h
@@ -55,9 +55,7 @@
             , fYSamplerCoordTransform(ySamplerTransform, fYSampler.proxy())
             , fUSamplerCoordTransform(uSamplerTransform, fUSampler.proxy())
             , fVSamplerCoordTransform(vSamplerTransform, fVSampler.proxy()) {
-        this->addTextureSampler(&fYSampler);
-        this->addTextureSampler(&fUSampler);
-        this->addTextureSampler(&fVSampler);
+        this->setTextureSamplerCnt(3);
         this->addCoordTransform(&fYSamplerCoordTransform);
         this->addCoordTransform(&fUSamplerCoordTransform);
         this->addCoordTransform(&fVSamplerCoordTransform);
@@ -65,6 +63,7 @@
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     bool onIsEqual(const GrFragmentProcessor&) const override;
+    const TextureSampler& onTextureSampler(int) const override;
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     TextureSampler fYSampler;
     SkMatrix44 fYSamplerTransform;
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index 07821c0..00dbef5 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -96,7 +96,7 @@
               GrSamplerState::Filter filter)
             : INHERITED(kLatticeGP_ClassID), fColorSpaceXform(std::move(csxf)) {
         fSampler.reset(std::move(proxy), filter);
-        this->addTextureSampler(&fSampler);
+        this->setTextureSamplerCnt(1);
         this->setVertexAttributeCnt(4);
     }
 
@@ -104,6 +104,8 @@
         return IthAttribute(i, kPositions, kTextureCoords, kTextureDomain, kColors);
     }
 
+    const TextureSampler& onTextureSampler(int) const override { return fSampler; }
+
     static constexpr Attribute kPositions = {"position", kFloat2_GrVertexAttribType};
     static constexpr Attribute kTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType};
     static constexpr Attribute kTextureDomain = {"textureDomain", kFloat4_GrVertexAttribType};
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 516cee6..9b2baeb 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -296,12 +296,10 @@
             , fPaintColorSpaceXform(std::move(paintColorSpaceXform)) {
         SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt);
         fSamplers[0].reset(std::move(proxies[0]), filters[0]);
-        this->addTextureSampler(&fSamplers[0]);
         for (int i = 1; i < proxyCnt; ++i) {
             // This class has one sampler built in, the rest come from memory this processor was
             // placement-newed into and so haven't been constructed.
             new (&fSamplers[i]) TextureSampler(std::move(proxies[i]), filters[i]);
-            this->addTextureSampler(&fSamplers[i]);
         }
 
         if (perspective) {
@@ -319,7 +317,6 @@
             GrTextureProxy* dupeProxy = fSamplers[proxyCnt - 1].proxy();
             for (int i = proxyCnt; i < samplerCnt; ++i) {
                 new (&fSamplers[i]) TextureSampler(sk_ref_sp(dupeProxy), filters[proxyCnt - 1]);
-                this->addTextureSampler(&fSamplers[i]);
             }
             SkASSERT(caps.integerSupport());
             fTextureIdx = {"textureIdx", kInt_GrVertexAttribType};
@@ -337,6 +334,7 @@
             vertexAttributeCnt += 4;
         }
         this->setVertexAttributeCnt(vertexAttributeCnt);
+        this->setTextureSamplerCnt(samplerCnt);
     }
 
     const Attribute& onVertexAttribute(int i) const override {
@@ -344,6 +342,8 @@
                                        fAAEdges[0], fAAEdges[1], fAAEdges[2], fAAEdges[3]);
     }
 
+    const TextureSampler& onTextureSampler(int i) const override { return fSamplers[i]; }
+
     Attribute fPositions;
     Attribute fColors;
     Attribute fTextureCoords;
diff --git a/src/shaders/SkPerlinNoiseShader.cpp b/src/shaders/SkPerlinNoiseShader.cpp
index 4bc44a6..0fc11a3 100644
--- a/src/shaders/SkPerlinNoiseShader.cpp
+++ b/src/shaders/SkPerlinNoiseShader.cpp
@@ -764,8 +764,7 @@
             , fPermutationsSampler(std::move(permutationsProxy))
             , fNoiseSampler(std::move(noiseProxy))
             , fPaintingData(std::move(paintingData)) {
-        this->addTextureSampler(&fPermutationsSampler);
-        this->addTextureSampler(&fNoiseSampler);
+        this->setTextureSamplerCnt(2);
         fCoordTransform.reset(matrix);
         this->addCoordTransform(&fCoordTransform);
     }
@@ -779,11 +778,14 @@
             , fPermutationsSampler(that.fPermutationsSampler)
             , fNoiseSampler(that.fNoiseSampler)
             , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
-        this->addTextureSampler(&fPermutationsSampler);
-        this->addTextureSampler(&fNoiseSampler);
+        this->setTextureSamplerCnt(2);
         this->addCoordTransform(&fCoordTransform);
     }
 
+    const TextureSampler& onTextureSampler(int i) const override {
+        return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
+    }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     SkPerlinNoiseShaderImpl::Type       fType;
@@ -1185,8 +1187,7 @@
             , fPermutationsSampler(std::move(permutationsProxy))
             , fGradientSampler(std::move(gradientProxy))
             , fPaintingData(std::move(paintingData)) {
-        this->addTextureSampler(&fPermutationsSampler);
-        this->addTextureSampler(&fGradientSampler);
+        this->setTextureSamplerCnt(2);
         fCoordTransform.reset(matrix);
         this->addCoordTransform(&fCoordTransform);
     }
@@ -1199,11 +1200,14 @@
             , fPermutationsSampler(that.fPermutationsSampler)
             , fGradientSampler(that.fGradientSampler)
             , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
-        this->addTextureSampler(&fPermutationsSampler);
-        this->addTextureSampler(&fGradientSampler);
+        this->setTextureSamplerCnt(2);
         this->addCoordTransform(&fCoordTransform);
     }
 
+    const TextureSampler& onTextureSampler(int i) const override {
+        return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
+    }
+
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     GrCoordTransform                    fCoordTransform;
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index 8536dd8..aa44ae6 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -1294,8 +1294,7 @@
             fTextureSampler.reset(std::move(proxy), samplerState);
             fYCoord = SK_ScalarHalf;
         }
-
-        this->addTextureSampler(&fTextureSampler);
+        this->setTextureSamplerCnt(1);
     }
 
     this->addCoordTransform(&fCoordTransform);
@@ -1316,7 +1315,7 @@
         , fPremulType(that.fPremulType) {
     this->addCoordTransform(&fCoordTransform);
     if (fStrategy == InterpolationStrategy::kTexture) {
-        this->addTextureSampler(&fTextureSampler);
+        this->setTextureSamplerCnt(1);
     }
     if (this->useAtlas()) {
         fAtlas->lockRow(fRow);
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
index 0f3e736..6aa5da2 100644
--- a/src/shaders/gradients/SkGradientShaderPriv.h
+++ b/src/shaders/gradients/SkGradientShaderPriv.h
@@ -302,6 +302,8 @@
     void addInterval(const SkGradientShaderBase&, const SkColor4f* colors,
                      size_t idx0, size_t idx1);
 
+    const TextureSampler& onTextureSampler(int i) const override { return fTextureSampler; }
+
     static OptimizationFlags OptFlags(bool isOpaque);
 
     // Interpolation intervals, encoded as 4f tuples of (scale, bias)
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index be40208..8656501 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -637,6 +637,29 @@
     this->write("    }\n");
 }
 
+void CPPCodeGenerator::writeOnTextureSampler() {
+    bool foundSampler = false;
+    for (const auto& param : fSectionAndParameterHelper.getParameters()) {
+        if (param->fType.kind() == Type::kSampler_Kind) {
+            if (!foundSampler) {
+                this->writef(
+                        "const GrFragmentProcessor::TextureSampler& %s::onTextureSampler(int "
+                        "index) const {\n",
+                        fFullName.c_str());
+                this->writef("    return IthTextureSampler(index, %s",
+                             HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
+                foundSampler = true;
+            } else {
+                this->writef(", %s",
+                             HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
+            }
+        }
+    }
+    if (foundSampler) {
+        this->write(");\n}\n");
+    }
+}
+
 void CPPCodeGenerator::writeClone() {
     if (!this->writeSection(CLONE_SECTION)) {
         if (fSectionAndParameterHelper.getSection(FIELDS_SECTION)) {
@@ -662,15 +685,18 @@
         }
         this->writef(" {\n");
         int childCount = 0;
+        int samplerCount = 0;
         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
             if (param->fType.kind() == Type::kSampler_Kind) {
-                this->writef("    this->addTextureSampler(&%s);\n",
-                             HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
+                ++samplerCount;
             } else if (param->fType == *fContext.fFragmentProcessor_Type) {
                 this->writef("    this->registerChildProcessor(src.childProcessor(%d).clone());"
                              "\n", childCount++);
             }
         }
+        if (samplerCount) {
+            this->writef("     this->setTextureSamplerCnt(%d);", samplerCount);
+        }
         for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
             String field = HCodeGenerator::FieldName(s->fArgument.c_str());
             this->writef("    this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
@@ -819,6 +845,7 @@
     this->write("    return true;\n"
                 "}\n");
     this->writeClone();
+    this->writeOnTextureSampler();
     this->writeTest();
     this->writeSection(CPP_END_SECTION);
 
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index 77331da..40d9982 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -78,6 +78,8 @@
 
     void writeGetKey();
 
+    void writeOnTextureSampler();
+
     void writeClone();
 
     void writeTest();
diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp
index be0f1ad..0acd334 100644
--- a/src/sksl/SkSLHCodeGenerator.cpp
+++ b/src/sksl/SkSLHCodeGenerator.cpp
@@ -223,15 +223,18 @@
     }
     this->writef(" {\n");
     this->writeSection(CONSTRUCTOR_CODE_SECTION);
+    int samplerCount = 0;
     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
         if (param->fType.kind() == Type::kSampler_Kind) {
-            this->writef("        this->addTextureSampler(&%s);\n",
-                         FieldName(String(param->fName).c_str()).c_str());
+            ++samplerCount;
         } else if (param->fType == *fContext.fFragmentProcessor_Type) {
             this->writef("        this->registerChildProcessor(std::move(%s));",
                          String(param->fName).c_str());
         }
     }
+    if (samplerCount) {
+        this->writef("        this->setTextureSamplerCnt(%d);", samplerCount);
+    }
     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
         String field = FieldName(s->fArgument.c_str());
         this->writef("        this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
@@ -312,8 +315,14 @@
     this->writef("    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
                  "    void onGetGLSLProcessorKey(const GrShaderCaps&,"
                                                 "GrProcessorKeyBuilder*) const override;\n"
-                 "    bool onIsEqual(const GrFragmentProcessor&) const override;\n"
-                 "    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
+                 "    bool onIsEqual(const GrFragmentProcessor&) const override;\n");
+    for (const auto& param : fSectionAndParameterHelper.getParameters()) {
+        if (param->fType.kind() == Type::kSampler_Kind) {
+            this->writef("    const TextureSampler& onTextureSampler(int) const override;");
+            break;
+        }
+    }
+    this->writef("    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
     this->writeFields();
     this->writef("    typedef GrFragmentProcessor INHERITED;\n"
                 "};\n");