Add GrGLSLFP::ParallelRange to iterate FP and GLSLFP trees

Bug: skia:10139

Change-Id: I379249758160ad096c9e03f25a41b00bc1987518
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/301384
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/d3d/GrD3DPipelineState.cpp b/src/gpu/d3d/GrD3DPipelineState.cpp
index c3c464e..5e3bfeb 100644
--- a/src/gpu/d3d/GrD3DPipelineState.cpp
+++ b/src/gpu/d3d/GrD3DPipelineState.cpp
@@ -27,7 +27,6 @@
         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
         std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-        int fragmentProcessorCnt,
         size_t vertexStride,
         size_t instanceStride)
     : fPipelineState(std::move(pipelineState))
@@ -36,7 +35,6 @@
     , fGeometryProcessor(std::move(geometryProcessor))
     , fXferProcessor(std::move(xferProcessor))
     , fFragmentProcessors(std::move(fragmentProcessors))
-    , fFragmentProcessorCnt(fragmentProcessorCnt)
     , fDataManager(uniforms, uniformSize)
     , fNumSamplers(numSamplers)
     , fVertexStride(vertexStride)
@@ -48,12 +46,13 @@
     this->setRenderTargetState(renderTarget, programInfo.origin());
 
     fGeometryProcessor->setData(fDataManager, programInfo.primProc());
-    GrFragmentProcessor::CIter fpIter(programInfo.pipeline());
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        glslIter->setData(fDataManager, *fpIter);
+    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
+        auto& pipelineFP = programInfo.pipeline().getFragmentProcessor(i);
+        auto& baseGLSLFP = *fFragmentProcessors[i];
+        for (auto [fp, glslFP] : GrGLSLFragmentProcessor::ParallelRange(pipelineFP, baseGLSLFP)) {
+            glslFP.setData(fDataManager, fp);
+        }
     }
-    SkASSERT(!fpIter && !glslIter);
 
     {
         SkIPoint offset;
@@ -111,20 +110,20 @@
         rangeSizes[currTextureBinding++] = 1;
     }
 
-    GrFragmentProcessor::CIter fpIter(pipeline);
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        for (int i = 0; i < fpIter->numTextureSamplers(); ++i) {
-            const auto& sampler = fpIter->textureSampler(i);
-            auto texture = static_cast<GrD3DTexture*>(sampler.peekTexture());
-            shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
-            samplers[currTextureBinding] =
-                    gpu->resourceProvider().findOrCreateCompatibleSampler(sampler.samplerState());
-            gpu->currentCommandList()->addSampledTextureRef(texture);
-            rangeSizes[currTextureBinding++] = 1;
+    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
+        for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
+            for (int s = 0; s < fp.numTextureSamplers(); ++s) {
+                const auto& sampler = fp.textureSampler(s);
+                auto texture = static_cast<GrD3DTexture*>(sampler.peekTexture());
+                shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
+                samplers[currTextureBinding] =
+                        gpu->resourceProvider().findOrCreateCompatibleSampler(
+                                sampler.samplerState());
+                gpu->currentCommandList()->addSampledTextureRef(texture);
+                rangeSizes[currTextureBinding++] = 1;
+            }
         }
     }
-    SkASSERT(!fpIter && !glslIter);
 
     if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
         auto texture = static_cast<GrD3DTexture*>(dstTexture);
diff --git a/src/gpu/d3d/GrD3DPipelineState.h b/src/gpu/d3d/GrD3DPipelineState.h
index 0925571..a9253eb 100644
--- a/src/gpu/d3d/GrD3DPipelineState.h
+++ b/src/gpu/d3d/GrD3DPipelineState.h
@@ -33,7 +33,6 @@
                        std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
                        std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
                        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragProcessors,
-                       int fragmentProcessorCnt,
                        size_t vertexStride,
                        size_t instanceStride);
 
@@ -118,7 +117,6 @@
     std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
-    int fFragmentProcessorCnt;
 
     GrD3DPipelineStateDataManager fDataManager;
 
diff --git a/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp b/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp
index 5704c1d..3a987b1 100644
--- a/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp
+++ b/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp
@@ -655,7 +655,6 @@
                                                             std::move(fGeometryProcessor),
                                                             std::move(fXferProcessor),
                                                             std::move(fFragmentProcessors),
-                                                            fFragmentProcessorCnt,
                                                             primProc.vertexStride(),
                                                             primProc.instanceStride()));
 }
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.cpp b/src/gpu/dawn/GrDawnProgramBuilder.cpp
index 99d5361..7d388ca 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.cpp
+++ b/src/gpu/dawn/GrDawnProgramBuilder.cpp
@@ -326,7 +326,6 @@
     result->fGeometryProcessor = std::move(builder.fGeometryProcessor);
     result->fXferProcessor = std::move(builder.fXferProcessor);
     result->fFragmentProcessors = std::move(builder.fFragmentProcessors);
-    result->fFragmentProcessorCnt = builder.fFragmentProcessorCnt;
     std::vector<wgpu::BindGroupLayoutEntry> uniformLayoutEntries;
     if (0 != uniformBufferSize) {
         uniformLayoutEntries.push_back({ GrSPIRVUniformHandler::kUniformBinding,
@@ -528,11 +527,15 @@
     const GrPipeline& pipeline = programInfo.pipeline();
     const GrPrimitiveProcessor& primProc = programInfo.primProc();
     fGeometryProcessor->setData(fDataManager, primProc);
-    GrFragmentProcessor::CIter fpIter(pipeline);
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        glslIter->setData(fDataManager, *fpIter);
+
+    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
+        auto& pipelineFP = programInfo.pipeline().getFragmentProcessor(i);
+        auto& baseGLSLFP = *fFragmentProcessors[i];
+        for (auto [fp, glslFP] : GrGLSLFragmentProcessor::ParallelRange(pipelineFP, baseGLSLFP)) {
+            glslFP.setData(fDataManager, fp);
+        }
     }
+
     SkIPoint offset;
     GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
     fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset);
@@ -563,14 +566,17 @@
                         &binding);
         }
     }
-    GrFragmentProcessor::CIter fpIter(pipeline);
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        for (int i = 0; i < fpIter->numTextureSamplers(); ++i) {
-            auto& s = fpIter->textureSampler(i);
-            set_texture(gpu, s.samplerState(), s.peekTexture(), &bindings, &binding);
+
+    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
+        for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
+            for (int s = 0; s < fp.numTextureSamplers(); ++s) {
+                const auto& sampler = fp.textureSampler(s);
+                set_texture(gpu, sampler.samplerState(), sampler.peekTexture(), &bindings,
+                            &binding);
+            }
         }
     }
+
     SkIPoint offset;
     if (GrTexture* dstTexture = pipeline.peekDstTexture(&offset)) {
         set_texture(gpu, GrSamplerState::Filter::kNearest, dstTexture, &bindings, &binding);
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.h b/src/gpu/dawn/GrDawnProgramBuilder.h
index af70784..65930ea 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.h
+++ b/src/gpu/dawn/GrDawnProgramBuilder.h
@@ -56,7 +56,6 @@
     std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
-    int fFragmentProcessorCnt;
     std::vector<wgpu::BindGroupLayout> fBindGroupLayouts;
     wgpu::RenderPipeline fRenderPipeline;
     GrDawnProgramDataManager fDataManager;
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 55a9120..ee19309 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -35,7 +35,6 @@
         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
         std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps,
-        int fragmentProcessorCnt,
         std::unique_ptr<Attribute[]> attributes,
         int vertexAttributeCnt,
         int instanceAttributeCnt,
@@ -50,7 +49,6 @@
                                                std::move(geometryProcessor),
                                                std::move(xferProcessor),
                                                std::move(fps),
-                                               fragmentProcessorCnt,
                                                std::move(attributes),
                                                vertexAttributeCnt,
                                                instanceAttributeCnt,
@@ -72,7 +70,6 @@
         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
         std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps,
-        int fragmentProcessorCnt,
         std::unique_ptr<Attribute[]> attributes,
         int vertexAttributeCnt,
         int instanceAttributeCnt,
@@ -83,7 +80,6 @@
         , fPrimitiveProcessor(std::move(geometryProcessor))
         , fXferProcessor(std::move(xferProcessor))
         , fFragmentProcessors(std::move(fps))
-        , fFragmentProcessorCnt(fragmentProcessorCnt)
         , fAttributes(std::move(attributes))
         , fVertexAttributeCnt(vertexAttributeCnt)
         , fInstanceAttributeCnt(instanceAttributeCnt)
@@ -118,12 +114,13 @@
     // primProc, fragProcs, XP.
     fPrimitiveProcessor->setData(fProgramDataManager, programInfo.primProc());
 
-    GrFragmentProcessor::CIter fpIter(programInfo.pipeline());
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        glslIter->setData(fProgramDataManager, *fpIter);
+    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
+        auto& pipelineFP = programInfo.pipeline().getFragmentProcessor(i);
+        auto& baseGLSLFP = *fFragmentProcessors[i];
+        for (auto [fp, glslFP] : GrGLSLFragmentProcessor::ParallelRange(pipelineFP, baseGLSLFP)) {
+            glslFP.setData(fProgramDataManager, fp);
+        }
     }
-    SkASSERT(!fpIter && !glslIter);
 
     const GrXferProcessor& xp = programInfo.pipeline().getXferProcessor();
     SkIPoint offset;
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index ce9e262..08da3f3 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -57,7 +57,6 @@
                                    std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
                                    std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
                                    std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps,
-                                   int fragmentProcessorCnt,
                                    std::unique_ptr<Attribute[]>,
                                    int vertexAttributeCnt,
                                    int instanceAttributeCnt,
@@ -150,7 +149,6 @@
                 std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
                 std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
                 std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps,
-                int fragmentProcessorCnt,
                 std::unique_ptr<Attribute[]>,
                 int vertexAttributeCnt,
                 int instanceAttributeCnt,
@@ -169,7 +167,6 @@
     std::unique_ptr<GrGLSLPrimitiveProcessor> fPrimitiveProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
-    int fFragmentProcessorCnt;
 
     std::unique_ptr<Attribute[]> fAttributes;
     int fVertexAttributeCnt;
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 5973b89..b50fc30 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -559,7 +559,6 @@
                              std::move(fGeometryProcessor),
                              std::move(fXferProcessor),
                              std::move(fFragmentProcessors),
-                             fFragmentProcessorCnt,
                              std::move(fAttributes),
                              fVertexAttributeCnt,
                              fInstanceAttributeCnt,
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index ad9b5ba..6d1ac02 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -144,6 +144,27 @@
     }
 }
 
+GrGLSLFragmentProcessor::ParallelIter::ParallelIter(const GrFragmentProcessor& fp,
+                                                    GrGLSLFragmentProcessor& glslFP)
+        : fpIter(fp), glslIter(glslFP) {}
+
+GrGLSLFragmentProcessor::ParallelIter& GrGLSLFragmentProcessor::ParallelIter::operator++() {
+    ++fpIter;
+    ++glslIter;
+    SkASSERT(static_cast<bool>(fpIter) == static_cast<bool>(glslIter));
+    return *this;
+}
+
+std::tuple<const GrFragmentProcessor&, GrGLSLFragmentProcessor&>
+GrGLSLFragmentProcessor::ParallelIter::operator*() const {
+    return {*fpIter, *glslIter};
+}
+
+bool GrGLSLFragmentProcessor::ParallelIter::operator==(const ParallelIterEnd& end) const {
+    SkASSERT(static_cast<bool>(fpIter) == static_cast<bool>(glslIter));
+    return !fpIter;
+}
+
 GrGLSLFragmentProcessor& GrGLSLFragmentProcessor::Iter::operator*() const {
     return *fFPStack.back();
 }
@@ -161,3 +182,7 @@
     }
     return *this;
 }
+
+GrGLSLFragmentProcessor::ParallelRange::ParallelRange(const GrFragmentProcessor& fp,
+                                                      GrGLSLFragmentProcessor& glslFP)
+        : fInitialFP(fp), fInitialGLSLFP(glslFP) {}
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index 5eb265d..f04e0c0 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -190,6 +190,7 @@
     class Iter {
     public:
         Iter(std::unique_ptr<GrGLSLFragmentProcessor> fps[], int cnt);
+        Iter(GrGLSLFragmentProcessor& fp) { fFPStack.push_back(&fp); }
 
         GrGLSLFragmentProcessor& operator*() const;
         GrGLSLFragmentProcessor* operator->() const;
@@ -204,6 +205,43 @@
         SkSTArray<4, GrGLSLFragmentProcessor*, true> fFPStack;
     };
 
+    class ParallelIterEnd {};
+
+    /**
+     * Walks parallel trees of GrFragmentProcessor and associated GrGLSLFragmentProcessors. The
+     * GrGLSLFragmentProcessor used to initialize the iterator must have been created by calling
+     * GrFragmentProcessor::createGLSLInstance() on the passed GrFragmentProcessor.
+     */
+    class ParallelIter {
+    public:
+        ParallelIter(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor& glslFP);
+
+        ParallelIter& operator++();
+
+        std::tuple<const GrFragmentProcessor&, GrGLSLFragmentProcessor&> operator*() const;
+
+        bool operator==(const ParallelIterEnd& end) const;
+
+        bool operator!=(const ParallelIterEnd& end) const { return !(*this == end); }
+
+    private:
+        GrFragmentProcessor::CIter fpIter;
+        GrGLSLFragmentProcessor::Iter glslIter;
+    };
+
+    class ParallelRange {
+    public:
+        ParallelRange(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor& glslFP);
+
+        ParallelIter begin() { return {fInitialFP, fInitialGLSLFP}; }
+
+        ParallelIterEnd end() { return {}; }
+
+    private:
+        const GrFragmentProcessor& fInitialFP;
+        GrGLSLFragmentProcessor& fInitialGLSLFP;
+    };
+
 protected:
     /** A GrGLSLFragmentProcessor instance can be reused with any GrFragmentProcessor that produces
     the same stage key; this function reads data from a GrFragmentProcessor and uploads any
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 627f380..1ec0e62 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -144,9 +144,9 @@
         }
         **inOut = output;
     }
-    fFragmentProcessorCnt = glslFragmentProcessors.count();
-    fFragmentProcessors.reset(new std::unique_ptr<GrGLSLFragmentProcessor>[fFragmentProcessorCnt]);
-    for (int i = 0; i < fFragmentProcessorCnt; ++i) {
+    int fpCount = glslFragmentProcessors.count();
+    fFragmentProcessors.reset(new std::unique_ptr<GrGLSLFragmentProcessor>[fpCount]);
+    for (int i = 0; i < fpCount; ++i) {
         fFragmentProcessors[i] = std::move(glslFragmentProcessors[i]);
     }
 }
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 3fe7816..fcda22d 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -113,7 +113,6 @@
     std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
-    int fFragmentProcessorCnt;
 
 protected:
     explicit GrGLSLProgramBuilder(GrRenderTarget*, const GrProgramDesc&, const GrProgramInfo&);
diff --git a/src/gpu/mtl/GrMtlPipelineState.h b/src/gpu/mtl/GrMtlPipelineState.h
index 978f4b6..10cb1d7 100644
--- a/src/gpu/mtl/GrMtlPipelineState.h
+++ b/src/gpu/mtl/GrMtlPipelineState.h
@@ -41,8 +41,7 @@
             uint32_t numSamplers,
             std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
             std::unique_ptr<GrGLSLXferProcessor> xferPRocessor,
-            std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-            int fFragmentProcessorCnt);
+            std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors);
 
     id<MTLRenderPipelineState> mtlPipelineState() { return fPipelineState; }
 
@@ -129,7 +128,6 @@
     std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
-    int fFragmentProcessorCnt;
 
     GrMtlPipelineStateDataManager fDataManager;
 };
diff --git a/src/gpu/mtl/GrMtlPipelineState.mm b/src/gpu/mtl/GrMtlPipelineState.mm
index 0415418..e4a1e2d 100644
--- a/src/gpu/mtl/GrMtlPipelineState.mm
+++ b/src/gpu/mtl/GrMtlPipelineState.mm
@@ -41,8 +41,7 @@
         uint32_t numSamplers,
         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
-        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-        int fragmentProcessorCnt)
+        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors)
         : fGpu(gpu)
         , fPipelineState(pipelineState)
         , fPixelFormat(pixelFormat)
@@ -51,7 +50,6 @@
         , fGeometryProcessor(std::move(geometryProcessor))
         , fXferProcessor(std::move(xferProcessor))
         , fFragmentProcessors(std::move(fragmentProcessors))
-        , fFragmentProcessorCnt(fragmentProcessorCnt)
         , fDataManager(uniforms, uniformBufferSize) {
     (void) fPixelFormat; // Suppress unused-var warning.
 }
@@ -61,12 +59,13 @@
     this->setRenderTargetState(renderTarget, programInfo.origin());
     fGeometryProcessor->setData(fDataManager, programInfo.primProc());
 
-    GrFragmentProcessor::CIter fpIter(programInfo.pipeline());
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        glslIter->setData(fDataManager, *fpIter);
+    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
+        auto& pipelineFP = programInfo.pipeline().getFragmentProcessor(i);
+        auto& baseGLSLFP = *fFragmentProcessors[i];
+        for (auto [fp, glslFP] : GrGLSLFragmentProcessor::ParallelRange(pipelineFP, baseGLSLFP)) {
+            glslFP.setData(fDataManager, fp);
+        }
     }
-    SkASSERT(!fpIter && !glslIter);
 
     {
         SkIPoint offset;
@@ -98,11 +97,12 @@
         fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
     }
 
-    GrFragmentProcessor::CIter fpIter(pipeline);
-    for (; fpIter; ++fpIter) {
-        for (int i = 0; i < fpIter->numTextureSamplers(); ++i) {
-            const auto& sampler = fpIter->textureSampler(i);
-            fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
+    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
+        for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
+            for (int s = 0; s < fp.numTextureSamplers(); ++s) {
+                const auto& sampler = fp.textureSampler(s);
+                fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
+            }
         }
     }
 
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index 0bfd4ee..0f93d15 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -536,8 +536,7 @@
                                   (uint32_t)fUniformHandler.numSamplers(),
                                   std::move(fGeometryProcessor),
                                   std::move(fXferProcessor),
-                                  std::move(fFragmentProcessors),
-                                  fFragmentProcessorCnt);
+                                  std::move(fFragmentProcessors));
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 33bac85..7ebed80 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -36,15 +36,13 @@
         const UniformInfoArray& samplers,
         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
-        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-        int fragmentProcessorCnt)
+        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors)
         : fPipeline(pipeline)
         , fSamplerDSHandle(samplerDSHandle)
         , fBuiltinUniformHandles(builtinUniformHandles)
         , fGeometryProcessor(std::move(geometryProcessor))
         , fXferProcessor(std::move(xferProcessor))
         , fFragmentProcessors(std::move(fragmentProcessors))
-        , fFragmentProcessorCnt(fragmentProcessorCnt)
         , fDataManager(uniforms, uniformSize) {
     fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, uniformSize));
 
@@ -80,12 +78,13 @@
     this->setRenderTargetState(renderTarget, programInfo.origin());
 
     fGeometryProcessor->setData(fDataManager, programInfo.primProc());
-    GrFragmentProcessor::CIter fpIter(programInfo.pipeline());
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        glslIter->setData(fDataManager, *fpIter);
+    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
+        auto& pipelineFP = programInfo.pipeline().getFragmentProcessor(i);
+        auto& baseGLSLFP = *fFragmentProcessors[i];
+        for (auto [fp, glslFP] : GrGLSLFragmentProcessor::ParallelRange(pipelineFP, baseGLSLFP)) {
+            glslFP.setData(fDataManager, fp);
+        }
     }
-    SkASSERT(!fpIter && !glslIter);
 
     {
         SkIPoint offset;
@@ -127,16 +126,15 @@
         samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture};
     }
 
-    GrFragmentProcessor::CIter fpIter(pipeline);
-    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
-    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
-        for (int i = 0; i < fpIter->numTextureSamplers(); ++i) {
-            const auto& sampler = fpIter->textureSampler(i);
-            samplerBindings[currTextureBinding++] =
-                    {sampler.samplerState(), static_cast<GrVkTexture*>(sampler.peekTexture())};
+    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
+        for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
+            for (int s = 0; s < fp.numTextureSamplers(); ++s) {
+                const auto& sampler = fp.textureSampler(s);
+                samplerBindings[currTextureBinding++] = {
+                        sampler.samplerState(), static_cast<GrVkTexture*>(sampler.peekTexture())};
+            }
         }
     }
-    SkASSERT(!fpIter && !glslIter);
 
     if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
         samplerBindings[currTextureBinding++] = {
diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h
index b175e19..82f79f4 100644
--- a/src/gpu/vk/GrVkPipelineState.h
+++ b/src/gpu/vk/GrVkPipelineState.h
@@ -47,8 +47,7 @@
             const UniformInfoArray& samplers,
             std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
             std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
-            std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-            int fFragmentProcessorCnt);
+            std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors);
 
     ~GrVkPipelineState();
 
@@ -125,7 +124,6 @@
     std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
-    int fFragmentProcessorCnt;
 
     GrVkPipelineStateDataManager fDataManager;
 
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 1e04c61..7ccecc2 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -341,6 +341,5 @@
                                  fUniformHandler.fSamplers,
                                  std::move(fGeometryProcessor),
                                  std::move(fXferProcessor),
-                                 std::move(fFragmentProcessors),
-                                 fFragmentProcessorCnt);
+                                 std::move(fFragmentProcessors));
 }