Remove FixedDynamicState from GrProgramInfo and GrPipeline

Everybody uses explicit binding now.

Change-Id: Idb6f64104eddd31d28dd2ba19f9743520a4e5170
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/277541
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/gm/tessellation.cpp b/gm/tessellation.cpp
index fe9f720..3e865d3 100644
--- a/gm/tessellation.cpp
+++ b/gm/tessellation.cpp
@@ -310,8 +310,6 @@
     void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
         GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrc,
                             state->drawOpArgs().outputSwizzle());
-        GrPipeline::FixedDynamicState fixedDynamicState;
-
         int tessellationPatchVertexCount;
         std::unique_ptr<GrGeometryProcessor> shader;
         if (fTriPositions) {
@@ -329,8 +327,8 @@
 
         GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
                                   state->proxy()->backendFormat(), state->outputView()->origin(),
-                                  &pipeline, shader.get(), &fixedDynamicState,
-                                  GrPrimitiveType::kPatches, tessellationPatchVertexCount);
+                                  &pipeline, shader.get(), GrPrimitiveType::kPatches,
+                                  tessellationPatchVertexCount);
 
         state->bindPipeline(programInfo, SkRect::MakeIWH(kWidth, kHeight));
         state->bindBuffers(nullptr, nullptr, fVertexBuffer.get());
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index 7824338..67a56b8 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -49,17 +49,11 @@
                                   this->outputView()->origin(),
                                   pipeline,
                                   fCurrDraw->fGeometryProcessor,
-                                  fCurrDraw->fFixedDynamicState,
                                   fCurrDraw->fPrimitiveType);
 
-        fOpsRenderPass->bindPipeline(programInfo, chainBounds);
-        if (programInfo.hasFixedScissor()) {
-            fOpsRenderPass->setScissorRect(programInfo.fixedScissor());
-        }
-        auto primProcTextures = (programInfo.hasFixedPrimProcTextures()) ?
-                programInfo.fixedPrimProcTextures() : nullptr;
-        fOpsRenderPass->bindTextures(programInfo.primProc(), primProcTextures,
-                                     programInfo.pipeline());
+        this->bindPipelineAndScissorClip(programInfo, chainBounds);
+        this->bindTextures(programInfo.primProc(), fCurrDraw->fPrimProcProxies,
+                           programInfo.pipeline());
         for (int i = 0; i < fCurrDraw->fMeshCnt; ++i) {
             this->drawMesh(fCurrDraw->fMeshes[i]);
         }
@@ -141,20 +135,19 @@
         const GrGeometryProcessor* gp,
         const GrSimpleMesh meshes[],
         int meshCnt,
-        const GrPipeline::FixedDynamicState* fixedDynamicState,
+        const GrSurfaceProxy* const primProcProxies[],
         GrPrimitiveType primitiveType) {
     SkASSERT(fOpArgs);
     SkDEBUGCODE(fOpArgs->validate());
     bool firstDraw = fDraws.begin() == fDraws.end();
     auto& draw = fDraws.append(&fArena);
     GrDeferredUploadToken token = fTokenTracker->issueDrawToken();
-    if (fixedDynamicState && fixedDynamicState->fPrimitiveProcessorTextures) {
-        for (int i = 0; i < gp->numTextureSamplers(); ++i) {
-            fixedDynamicState->fPrimitiveProcessorTextures[i]->ref();
-        }
+    for (int i = 0; i < gp->numTextureSamplers(); ++i) {
+        SkASSERT(primProcProxies && primProcProxies[i]);
+        primProcProxies[i]->ref();
     }
     draw.fGeometryProcessor = gp;
-    draw.fFixedDynamicState = fixedDynamicState;
+    draw.fPrimProcProxies = primProcProxies;
     draw.fMeshes = meshes;
     draw.fMeshCnt = meshCnt;
     draw.fOp = fOpArgs->op();
@@ -230,9 +223,8 @@
 //////////////////////////////////////////////////////////////////////////////
 
 GrOpFlushState::Draw::~Draw() {
-    if (fFixedDynamicState && fFixedDynamicState->fPrimitiveProcessorTextures) {
-        for (int i = 0; i < fGeometryProcessor->numTextureSamplers(); ++i) {
-            fFixedDynamicState->fPrimitiveProcessorTextures[i]->unref();
-        }
+    for (int i = 0; i < fGeometryProcessor->numTextureSamplers(); ++i) {
+        SkASSERT(fPrimProcProxies && fPrimProcProxies[i]);
+        fPrimProcProxies[i]->unref();
     }
 }
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h
index 06cf768..0fd90cb 100644
--- a/src/gpu/GrOpFlushState.h
+++ b/src/gpu/GrOpFlushState.h
@@ -119,7 +119,7 @@
     void recordDraw(const GrGeometryProcessor*,
                     const GrSimpleMesh[],
                     int meshCnt,
-                    const GrPipeline::FixedDynamicState*,
+                    const GrSurfaceProxy* const primProcProxies[],
                     GrPrimitiveType) final;
     void* makeVertexSpace(size_t vertexSize, int vertexCount, sk_sp<const GrBuffer>*,
                           int* startVertex) final;
@@ -237,7 +237,8 @@
         // the stack (for CCPR). In either case this object does not need to manage its
         // lifetime.
         const GrGeometryProcessor* fGeometryProcessor = nullptr;
-        const GrPipeline::FixedDynamicState* fFixedDynamicState = nullptr;
+        // Must have GrPrimitiveProcessor::numTextureSamplers() entries. Can be null if no samplers.
+        const GrSurfaceProxy* const* fPrimProcProxies = nullptr;
         const GrSimpleMesh* fMeshes = nullptr;
         const GrOp* fOp = nullptr;
         int fMeshCnt = 0;
diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp
index 5e44531..49608d4 100644
--- a/src/gpu/GrPathRendering.cpp
+++ b/src/gpu/GrPathRendering.cpp
@@ -61,5 +61,5 @@
                                                                   *fGpu->caps())) {
         fGpu->xferBarrier(renderTarget, barrierType);
     }
-    this->onDrawPath(renderTarget, programInfo, stencilPassSettings, path);
+    this->onDrawPath(stencilPassSettings, path);
 }
diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h
index 839cb3d..8a9743e 100644
--- a/src/gpu/GrPathRendering.h
+++ b/src/gpu/GrPathRendering.h
@@ -124,10 +124,7 @@
     GrPathRendering(GrGpu* gpu) : fGpu(gpu) { }
 
     virtual void onStencilPath(const StencilPathArgs&, const GrPath*) = 0;
-    virtual void onDrawPath(GrRenderTarget*,
-                            const GrProgramInfo&,
-                            const GrStencilSettings&,
-                            const GrPath*) = 0;
+    virtual void onDrawPath(const GrStencilSettings&, const GrPath*) = 0;
 
     GrGpu* fGpu;
 private:
diff --git a/src/gpu/GrPathRendering_none.cpp b/src/gpu/GrPathRendering_none.cpp
index 3c2878d..0e12a36 100644
--- a/src/gpu/GrPathRendering_none.cpp
+++ b/src/gpu/GrPathRendering_none.cpp
@@ -42,10 +42,7 @@
 
 sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath&, const GrStyle&) { return nullptr; }
 
-void GrGLPathRendering::onDrawPath(GrRenderTarget*,
-                                   const GrProgramInfo&,
-                                   const GrStencilSettings&,
-                                   const GrPath*) {}
+void GrGLPathRendering::onDrawPath(const GrStencilSettings&, const GrPath*) {}
 
 void GrGLPathRendering::onStencilPath(const StencilPathArgs&, const GrPath*) {}
 
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index a4f5a73..f07dbb5 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -75,19 +75,6 @@
     };
 
     /**
-     * Some state can be changed between GrMeshes without changing GrPipelines. This is generally
-     * less expensive then using multiple pipelines. Such state is called "dynamic state".
-     * Use this to specify state that does not vary between GrMeshes.
-     **/
-    struct FixedDynamicState {
-        explicit FixedDynamicState(const SkIRect& scissorRect) : fScissorRect(scissorRect) {}
-        FixedDynamicState() = default;
-        SkIRect fScissorRect = SkIRect::MakeEmpty();
-        // Must have GrPrimitiveProcessor::numTextureSamplers() entries. Can be null if no samplers.
-        GrSurfaceProxy** fPrimitiveProcessorTextures = nullptr;
-    };
-
-    /**
      * Creates a simple pipeline with default settings and no processors. The provided blend mode
      * must be "Porter Duff" (<= kLastCoeffMode). If using GrScissorTest::kEnabled, the caller must
      * specify a scissor rectangle through the DynamicState struct.
diff --git a/src/gpu/GrProgramInfo.cpp b/src/gpu/GrProgramInfo.cpp
index 7fb1053..43b307a 100644
--- a/src/gpu/GrProgramInfo.cpp
+++ b/src/gpu/GrProgramInfo.cpp
@@ -28,53 +28,27 @@
     if (flushTime) {
         SkASSERT(fPipeline->allProxiesInstantiated());
     }
-
-    if (this->hasFixedPrimProcTextures()) {
-        SkASSERT(fPrimProc->numTextureSamplers());
-    }
-
-    if (!fPipeline->isScissorTestEnabled()) {
-         SkASSERT(!this->hasFixedScissor());
-    }
 }
 
 void GrProgramInfo::checkAllInstantiated() const {
-    if (this->hasFixedPrimProcTextures()) {
-        auto fixedPrimProcTextures = this->fixedPrimProcTextures();
-        for (int s = 0; s < this->primProc().numTextureSamplers(); ++s) {
-            SkASSERT(fixedPrimProcTextures[s]->isInstantiated());
-        }
-    }
     for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(this->pipeline())) {
         SkASSERT(sampler.proxy()->isInstantiated());
     }
 }
 
 void GrProgramInfo::checkMSAAAndMIPSAreResolved() const {
-    auto assertResolved = [](GrTexture* tex, GrSamplerState sampler) {
+    for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(this->pipeline())) {
+        GrTexture* tex = sampler.peekTexture();
         SkASSERT(tex);
 
         // Ensure mipmaps were all resolved ahead of time by the DAG.
-        if (GrSamplerState::Filter::kMipMap == sampler.filter() &&
+        if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter() &&
             (tex->width() != 1 || tex->height() != 1)) {
             // There are some cases where we might be given a non-mipmapped texture with a mipmap
             // filter. See skbug.com/7094.
             SkASSERT(tex->texturePriv().mipMapped() != GrMipMapped::kYes ||
                      !tex->texturePriv().mipMapsAreDirty());
         }
-    };
-
-    if (this->hasFixedPrimProcTextures()) {
-        auto fixedPrimProcTextures = this->fixedPrimProcTextures();
-
-        for (int s = 0; s < this->primProc().numTextureSamplers(); ++s) {
-            auto* tex = fixedPrimProcTextures[s]->peekTexture();
-            assertResolved(tex, this->primProc().textureSampler(s).samplerState());
-        }
-    }
-
-    for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(this->pipeline())) {
-        assertResolved(sampler.peekTexture(), sampler.samplerState());
     }
 }
 
diff --git a/src/gpu/GrProgramInfo.h b/src/gpu/GrProgramInfo.h
index 17c3a7f..1f59811 100644
--- a/src/gpu/GrProgramInfo.h
+++ b/src/gpu/GrProgramInfo.h
@@ -22,7 +22,6 @@
                   GrSurfaceOrigin origin,
                   const GrPipeline* pipeline,
                   const GrPrimitiveProcessor* primProc,
-                  const GrPipeline::FixedDynamicState* fixedDynamicState,
                   GrPrimitiveType primitiveType,
                   uint8_t tessellationPatchVertexCount = 0)
             : fNumRasterSamples(pipeline->isStencilEnabled() ? numStencilSamples : numSamples)
@@ -31,7 +30,6 @@
             , fOrigin(origin)
             , fPipeline(pipeline)
             , fPrimProc(primProc)
-            , fFixedDynamicState(fixedDynamicState)
             , fPrimitiveType(primitiveType)
             , fTessellationPatchVertexCount(tessellationPatchVertexCount) {
         SkASSERT(fNumRasterSamples > 0);
@@ -55,25 +53,6 @@
     GrSurfaceOrigin origin() const { return fOrigin;  }
     const GrPipeline& pipeline() const { return *fPipeline; }
     const GrPrimitiveProcessor& primProc() const { return *fPrimProc; }
-    const GrPipeline::FixedDynamicState* fixedDynamicState() const { return fFixedDynamicState; }
-
-    bool hasFixedScissor() const { return fPipeline->isScissorTestEnabled() && fFixedDynamicState; }
-
-    const SkIRect& fixedScissor() const {
-        SkASSERT(this->hasFixedScissor());
-
-        return fFixedDynamicState->fScissorRect;
-    }
-
-    bool hasFixedPrimProcTextures() const {
-        return fFixedDynamicState && fFixedDynamicState->fPrimitiveProcessorTextures;
-    }
-
-    const GrSurfaceProxy* const* fixedPrimProcTextures() const {
-        SkASSERT(this->hasFixedPrimProcTextures());
-
-        return fFixedDynamicState->fPrimitiveProcessorTextures;
-    }
 
     GrPrimitiveType primitiveType() const { return fPrimitiveType; }
     uint8_t tessellationPatchVertexCount() const {
@@ -111,7 +90,6 @@
     const GrSurfaceOrigin                 fOrigin;
     const GrPipeline*                     fPipeline;
     const GrPrimitiveProcessor*           fPrimProc;
-    const GrPipeline::FixedDynamicState*  fFixedDynamicState;
     GrProcessor::CustomFeatures           fRequestedFeatures;
     GrPrimitiveType                       fPrimitiveType;
     uint8_t                               fTessellationPatchVertexCount;  // GrPrimType::kPatches.
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index 52604ae..cfd49ff 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -200,7 +200,7 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->outputView()->origin(), &pipeline, this, nullptr,
+                              flushState->outputView()->origin(), &pipeline, this,
                               this->primType());
     flushState->bindPipeline(programInfo, drawBounds);
 }
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index 8131f92..33e0645 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -138,7 +138,7 @@
     GrRenderTargetProxy* rtProxy = flushState->proxy();
     GrProgramInfo programInfo(rtProxy->numSamples(), rtProxy->numStencilSamples(),
                               rtProxy->backendFormat(), flushState->outputView()->origin(),
-                              &pipeline, this, nullptr, primitiveType);
+                              &pipeline, this, primitiveType);
 
     flushState->bindPipelineAndScissorClip(programInfo, bounds);
     flushState->bindTextures(*this, atlasProxy, pipeline);
diff --git a/src/gpu/ccpr/GrCCStroker.cpp b/src/gpu/ccpr/GrCCStroker.cpp
index c86d0b5..bbf1486 100644
--- a/src/gpu/ccpr/GrCCStroker.cpp
+++ b/src/gpu/ccpr/GrCCStroker.cpp
@@ -738,7 +738,7 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->outputView()->origin(), &pipeline, &processor, nullptr,
+                              flushState->outputView()->origin(), &pipeline, &processor,
                               GrPrimitiveType::kTriangleStrip);
 
     flushState->bindPipeline(programInfo, SkRect::Make(drawBounds));
diff --git a/src/gpu/ccpr/GrStencilAtlasOp.cpp b/src/gpu/ccpr/GrStencilAtlasOp.cpp
index 96206b0..586707f 100644
--- a/src/gpu/ccpr/GrStencilAtlasOp.cpp
+++ b/src/gpu/ccpr/GrStencilAtlasOp.cpp
@@ -152,7 +152,7 @@
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
                               flushState->outputView()->origin(), &resolvePipeline, &primProc,
-                              nullptr, GrPrimitiveType::kTriangleStrip);
+                              GrPrimitiveType::kTriangleStrip);
 
     flushState->bindPipeline(programInfo, SkRect::Make(drawBoundsRect));
     flushState->setScissorRect(drawBoundsRect);
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 5a43277..3746a76 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -109,20 +109,8 @@
     }
 }
 
-void GrGLPathRendering::onDrawPath(GrRenderTarget* renderTarget,
-                                   const GrProgramInfo& programInfo,
-                                   const GrStencilSettings& stencilPassSettings,
+void GrGLPathRendering::onDrawPath(const GrStencilSettings& stencilPassSettings,
                                    const GrPath* path) {
-    if (!this->gpu()->flushGLState(renderTarget, programInfo)) {
-        return;
-    }
-    if (programInfo.hasFixedScissor()) {
-        this->gpu()->flushScissorRect(programInfo.fixedScissor(), renderTarget->width(),
-                                      renderTarget->height(), programInfo.origin());
-    }
-    this->gpu()->currentProgram()->bindTextures(programInfo.primProc(), nullptr,
-                                                programInfo.pipeline());
-
     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
 
     this->flushPathStencilSettings(stencilPassSettings);
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index 14284b4..975e452 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -65,8 +65,7 @@
 
 protected:
     void onStencilPath(const StencilPathArgs&, const GrPath*) override;
-    void onDrawPath(GrRenderTarget*, const GrProgramInfo&, const GrStencilSettings&,
-                    const GrPath*) override;
+    void onDrawPath(const GrStencilSettings&, const GrPath*) override;
 
 private:
     /**
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 679bb2d..2793f79 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -305,16 +305,16 @@
     static_assert(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures);
     static_assert(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures);
 
-    auto fixedDynamicState = target->makeFixedDynamicState(kMaxTextures);
+    auto primProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
     for (unsigned i = 0; i < numActiveViews; ++i) {
-        fixedDynamicState->fPrimitiveProcessorTextures[i] = views[i].proxy();
+        primProcProxies[i] = views[i].proxy();
         // This op does not know its atlas proxies when it is added to a GrOpsTasks, so the proxies
         // don't get added during the visitProxies call. Thus we add them here.
         target->sampledProxyArray()->push_back(views[i].proxy());
     }
 
     FlushInfo flushInfo;
-    flushInfo.fFixedDynamicState = fixedDynamicState;
+    flushInfo.fPrimProcProxies = primProcProxies;
 
     bool vmPerspective = fGeoData[0].fDrawMatrix.hasPerspective();
     if (this->usesDistanceFields()) {
@@ -487,13 +487,13 @@
         // During preparation the number of atlas pages has increased.
         // Update the proxies used in the GP to match.
         for (unsigned i = gp->numTextureSamplers(); i < numActiveViews; ++i) {
-            flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = views[i].proxy();
+            flushInfo->fPrimProcProxies[i] = views[i].proxy();
             // This op does not know its atlas proxies when it is added to a GrOpsTasks, so the
             // proxies don't get added during the visitProxies call. Thus we add them here.
             target->sampledProxyArray()->push_back(views[i].proxy());
             // These will get unreffed when the previously recorded draws destruct.
             for (int d = 0; d < flushInfo->fNumDraws; ++d) {
-                flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i]->ref();
+                flushInfo->fPrimProcProxies[i]->ref();
             }
         }
         if (this->usesDistanceFields()) {
@@ -515,7 +515,7 @@
     mesh->setIndexedPatterned(flushInfo->fIndexBuffer, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
                               maxGlyphsPerDraw, flushInfo->fVertexBuffer, kVerticesPerGlyph,
                               flushInfo->fVertexOffset);
-    target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fFixedDynamicState,
+    target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies,
                        GrPrimitiveType::kTriangles);
     flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
     flushInfo->fGlyphsToFlush = 0;
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index bc6cfa1..3a96ac9 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -105,7 +105,7 @@
         sk_sp<const GrBuffer> fVertexBuffer;
         sk_sp<const GrBuffer> fIndexBuffer;
         GrGeometryProcessor*  fGeometryProcessor;
-        GrPipeline::FixedDynamicState* fFixedDynamicState;
+        const GrSurfaceProxy** fPrimProcProxies;
         int fGlyphsToFlush = 0;
         int fVertexOffset = 0;
         int fNumDraws = 0;
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp
index a691985..1c3f7cc 100644
--- a/src/gpu/ops/GrDrawPathOp.cpp
+++ b/src/gpu/ops/GrDrawPathOp.cpp
@@ -77,14 +77,6 @@
 }
 
 void GrDrawPathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
-    GrPipeline::FixedDynamicState* fixedDynamicState = nullptr, storage;
-
-    const GrAppliedClip* appliedClip = flushState->appliedClip();
-    if (appliedClip && appliedClip->scissorState().enabled()) {
-        storage.fScissorRect = appliedClip->scissorState().rect();
-        fixedDynamicState = &storage;
-    }
-
     GrPipeline::InputFlags pipelineFlags = GrPipeline::InputFlags::kNone;
     if (this->doAA()) {
         pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
@@ -104,9 +96,11 @@
                               flushState->outputView()->origin(),
                               pipeline,
                               pathProc.get(),
-                              fixedDynamicState,
                               GrPrimitiveType::kPath);
 
+    flushState->bindPipelineAndScissorClip(programInfo, this->bounds());
+    flushState->bindTextures(programInfo.primProc(), nullptr, programInfo.pipeline());
+
     GrStencilSettings stencil;
     init_stencil_pass_settings(*flushState, this->fillType(), &stencil);
     flushState->gpu()->pathRendering()->drawPath(proxy->peekRenderTarget(),
diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp
index 618e1af..da046e1 100644
--- a/src/gpu/ops/GrMeshDrawOp.cpp
+++ b/src/gpu/ops/GrMeshDrawOp.cpp
@@ -85,8 +85,8 @@
 void GrMeshDrawOp::PatternHelper::recordDraw(
         Target* target,
         const GrGeometryProcessor* gp,
-        const GrPipeline::FixedDynamicState* fixedDynamicState) const {
-    target->recordDraw(gp, fMesh, 1, fixedDynamicState, fPrimitiveType);
+        const GrSurfaceProxy* const primProcProxies[]) const {
+    target->recordDraw(gp, fMesh, 1, primProcProxies, fPrimitiveType);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -102,26 +102,3 @@
                GrResourceProvider::NumIndicesPerNonAAQuad(), quadsToDraw,
                GrResourceProvider::MaxNumNonAAQuads());
 }
-
-//////////////////////////////////////////////////////////////////////////////
-
-GrPipeline::FixedDynamicState* GrMeshDrawOp::Target::MakeFixedDynamicState(
-        SkArenaAlloc* arena, const GrAppliedClip* clip, int numPrimProcTextures) {
-
-    bool haveScissor = clip && clip->scissorState().enabled();
-
-    if (haveScissor || numPrimProcTextures) {
-        auto result = arena->make<GrPipeline::FixedDynamicState>();
-
-        if (haveScissor) {
-            result->fScissorRect = clip->scissorState().rect();
-        }
-
-        if (numPrimProcTextures) {
-            result->fPrimitiveProcessorTextures = arena->makeArrayDefault<GrSurfaceProxy*>(
-                        numPrimProcTextures);
-        }
-        return result;
-    }
-    return nullptr;
-}
diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h
index be68c9e..da2c3be 100644
--- a/src/gpu/ops/GrMeshDrawOp.h
+++ b/src/gpu/ops/GrMeshDrawOp.h
@@ -57,7 +57,7 @@
         /** Called to issue draws to the GrMeshDrawOp::Target.*/
         void recordDraw(Target*, const GrGeometryProcessor*) const;
         void recordDraw(Target*, const GrGeometryProcessor*,
-                        const GrPipeline::FixedDynamicState*) const;
+                        const GrSurfaceProxy* const primProcProxies[]) const;
 
         void* vertices() const { return fVertices; }
         GrSimpleMesh* mesh() { return fMesh; }
@@ -130,24 +130,23 @@
 public:
     virtual ~Target() {}
 
-    /** Adds a draw of a mesh. */
+    /** Adds a draw of a mesh. 'primProcProxies' must have
+     * GrPrimitiveProcessor::numTextureSamplers() entries. Can be null if no samplers.
+     */
     virtual void recordDraw(const GrGeometryProcessor*,
                             const GrSimpleMesh[],
                             int meshCnt,
-                            const GrPipeline::FixedDynamicState*,
+                            const GrSurfaceProxy* const primProcProxies[],
                             GrPrimitiveType) = 0;
 
     /**
-     * Helper for drawing GrSimpleMesh(es) with zero primProc textures and no dynamic state besides
-     * the scissor clip.
+     * Helper for drawing GrSimpleMesh(es) with zero primProc textures.
      */
     void recordDraw(const GrGeometryProcessor* gp,
                     const GrSimpleMesh meshes[],
                     int meshCnt,
                     GrPrimitiveType primitiveType) {
-        static constexpr int kZeroPrimProcTextures = 0;
-        auto fixedDynamicState = this->makeFixedDynamicState(kZeroPrimProcTextures);
-        this->recordDraw(gp, meshes, meshCnt, fixedDynamicState, primitiveType);
+        this->recordDraw(gp, meshes, meshCnt, nullptr, primitiveType);
     }
 
     /**
@@ -191,15 +190,8 @@
 
     GrSimpleMesh* allocMesh() { return this->allocator()->make<GrSimpleMesh>(); }
     GrSimpleMesh* allocMeshes(int n) { return this->allocator()->makeArray<GrSimpleMesh>(n); }
-
-    static GrPipeline::FixedDynamicState* MakeFixedDynamicState(SkArenaAlloc*,
-                                                                const GrAppliedClip* clip,
-                                                                int numPrimitiveProcessorTextures);
-
-
-    GrPipeline::FixedDynamicState* makeFixedDynamicState(int numPrimitiveProcessorTextures) {
-        return MakeFixedDynamicState(this->allocator(), this->appliedClip(),
-                                     numPrimitiveProcessorTextures);
+    const GrSurfaceProxy** allocPrimProcProxyPtrs(int n) {
+        return this->allocator()->makeArray<const GrSurfaceProxy*>(n);
     }
 
     virtual GrRenderTargetProxy* proxy() const = 0;
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
index e4495e8..f18717c 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
@@ -164,14 +164,7 @@
             GrProcessorSet&& processorSet,
             GrPrimitiveType primitiveType,
             GrPipeline::InputFlags pipelineFlags,
-            const GrUserStencilSettings* stencilSettings,
-            GrPipeline::FixedDynamicState* fixedDynamicState) {
-    if (!fixedDynamicState) {
-        static constexpr int kZeroPrimProcTextures = 0;
-        fixedDynamicState = GrMeshDrawOp::Target::MakeFixedDynamicState(arena, &appliedClip,
-                                                                        kZeroPrimProcTextures);
-    }
-
+            const GrUserStencilSettings* stencilSettings) {
     auto pipeline = CreatePipeline(caps,
                                    arena,
                                    outputView,
@@ -189,7 +182,6 @@
                                           outputView->origin(),
                                           pipeline,
                                           geometryProcessor,
-                                          fixedDynamicState,
                                           primitiveType);
     return tmp;
 }
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index a66c16e..16f45a8 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -154,8 +154,7 @@
                                             GrPipeline::InputFlags pipelineFlags
                                                                 = GrPipeline::InputFlags::kNone,
                                             const GrUserStencilSettings*
-                                                                = &GrUserStencilSettings::kUnused,
-                                            GrPipeline::FixedDynamicState* = nullptr);
+                                                                = &GrUserStencilSettings::kUnused);
 
     GrProgramInfo* createProgramInfo(const GrCaps*,
                                      SkArenaAlloc*,
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index 31a87aa..9d61a4a 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -306,7 +306,7 @@
         sk_sp<const GrBuffer> fVertexBuffer;
         sk_sp<const GrBuffer> fIndexBuffer;
         GrGeometryProcessor*  fGeometryProcessor;
-        GrPipeline::FixedDynamicState* fFixedDynamicState;
+        const GrSurfaceProxy** fPrimProcProxies;
         int fVertexOffset;
         int fInstancesToFlush;
     };
@@ -338,13 +338,13 @@
         static_assert(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures);
 
         FlushInfo flushInfo;
-        flushInfo.fFixedDynamicState = target->makeFixedDynamicState(kMaxTextures);
+        flushInfo.fPrimProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
         int numActiveProxies = fAtlas->numActivePages();
         const auto views = fAtlas->getViews();
         for (int i = 0; i < numActiveProxies; ++i) {
             // This op does not know its atlas proxies when it is added to a GrOpsTasks, so the
             // proxies don't get added during the visitProxies call. Thus we add them here.
-            flushInfo.fFixedDynamicState->fPrimitiveProcessorTextures[i] = views[i].proxy();
+            flushInfo.fPrimProcProxies[i] = views[i].proxy();
             target->sampledProxyArray()->push_back(views[i].proxy());
         }
 
@@ -798,7 +798,7 @@
         const auto views = fAtlas->getViews();
         if (gp->numTextureSamplers() != numAtlasTextures) {
             for (int i = gp->numTextureSamplers(); i < numAtlasTextures; ++i) {
-                flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = views[i].proxy();
+                flushInfo->fPrimProcProxies[i] = views[i].proxy();
                 // This op does not know its atlas proxies when it is added to a GrOpsTasks, so the
                 // proxies don't get added during the visitProxies call. Thus we add them here.
                 target->sampledProxyArray()->push_back(views[i].proxy());
@@ -825,8 +825,8 @@
                                       flushInfo->fVertexBuffer,
                                       GrResourceProvider::NumVertsPerNonAAQuad(),
                                       flushInfo->fVertexOffset);
-            target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1,
-                               flushInfo->fFixedDynamicState, GrPrimitiveType::kTriangles);
+            target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies,
+                               GrPrimitiveType::kTriangles);
             flushInfo->fVertexOffset += GrResourceProvider::NumVertsPerNonAAQuad() *
                                         flushInfo->fInstancesToFlush;
             flushInfo->fInstancesToFlush = 0;
diff --git a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
index 4f225ae..b66e60c 100644
--- a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
+++ b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
@@ -173,7 +173,7 @@
 
     GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
                               state->proxy()->backendFormat(), state->outputView()->origin(),
-                              &pipeline, &shader, nullptr, GrPrimitiveType::kTriangleStrip);
+                              &pipeline, &shader, GrPrimitiveType::kTriangleStrip);
 
     state->bindPipelineAndScissorClip(programInfo, this->bounds());
     state->bindTextures(shader, *fAtlasProxy, pipeline);
diff --git a/src/gpu/tessellate/GrPathShader.h b/src/gpu/tessellate/GrPathShader.h
index 09e852d..e244f1e 100644
--- a/src/gpu/tessellate/GrPathShader.h
+++ b/src/gpu/tessellate/GrPathShader.h
@@ -40,7 +40,7 @@
         ProgramInfo(const GrRenderTargetProxy* proxy, GrSurfaceOrigin origin,
                     const GrPipeline* pipeline, const GrPathShader* shader)
                 : GrProgramInfo(proxy->numSamples(), proxy->numStencilSamples(),
-                                proxy->backendFormat(), origin, pipeline, shader, nullptr,
+                                proxy->backendFormat(), origin, pipeline, shader,
                                 shader->fPrimitiveType, shader->fTessellationPatchVertexCount) {
         }
     };
diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp
index ae2d069..6d2169e 100644
--- a/tests/GrMeshTest.cpp
+++ b/tests/GrMeshTest.cpp
@@ -461,7 +461,7 @@
 
     GrProgramInfo programInfo(fState->proxy()->numSamples(), fState->proxy()->numStencilSamples(),
                               fState->proxy()->backendFormat(), fState->outputView()->origin(),
-                              pipeline, mtp, nullptr, primitiveType);
+                              pipeline, mtp, primitiveType);
 
     fState->opsRenderPass()->bindPipeline(programInfo, SkRect::MakeIWH(kImageWidth, kImageHeight));
     return fState->opsRenderPass();
diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp
index 62d273d..0328091 100644
--- a/tests/GrPipelineDynamicStateTest.cpp
+++ b/tests/GrPipelineDynamicStateTest.cpp
@@ -163,7 +163,6 @@
                                   flushState->outputView()->origin(),
                                   &pipeline,
                                   geomProc,
-                                  nullptr,
                                   GrPrimitiveType::kTriangleStrip);
 
         flushState->bindPipeline(programInfo, SkRect::MakeIWH(kScreenSize, kScreenSize));