[graphite] Separate gradient data handling from PipelineDataGatherer

 * The PipelineDataGatherer was responsible for both collecting uniform data and managing storage for gradient color/stop data. This commit separates these concerns by introducing a new FloatStorageManager.

 * The FloatStorageManager is now solely responsible for allocating and de-duplicating gradient data buffers. The PipelineDataGatherer continues to manage uniform and texture data for each draw.

 * This change provides better separation of concerns and simplifies the PipelineDataGatherer.

 * As part of this refactoring, the `gatherer` parameter was removed from many key-creation functions. The gatherer and the new float storage manager are now accessed via the KeyContext, simplifying function signatures throughout the precompile and paint params key generation code.

Change-Id: I33b36e08750760d2725c57ad12bd9c2891db0fb7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1031636
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Thomas Smith <thomsmit@google.com>
diff --git a/fuzz/FuzzPrecompile.cpp b/fuzz/FuzzPrecompile.cpp
index 2d4f459..9107dc3 100644
--- a/fuzz/FuzzPrecompile.cpp
+++ b/fuzz/FuzzPrecompile.cpp
@@ -307,18 +307,18 @@
 
     SkColorInfo ci = SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType,
                                  SkColorSpace::MakeSRGB());
-
-    std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
-    KeyContext precompileKeyContext(recorder->priv().caps(), dict, rtDict.get(), ci);
-
-    DrawTypeFlags kDrawType = DrawTypeFlags::kSimpleShape;
-    SkPath path = make_path();
-
     Layout layout = context->backend() == skgpu::BackendApi::kMetal ? Layout::kMetal
                                                                     : Layout::kStd140;
 
+    FloatStorageManager floatStorageManager;
     PaintParamsKeyBuilder builder(dict);
     PipelineDataGatherer gatherer(layout);
+    std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
+    KeyContext precompileKeyContext(recorder->priv().caps(), &floatStorageManager,
+                                    &builder, &gatherer, dict, rtDict.get(), ci);
+
+    DrawTypeFlags kDrawType = DrawTypeFlags::kSimpleShape;
+    SkPath path = make_path();
 
     auto [paint, paintOptions] = create_random_paint(fuzz, depth);
 
@@ -335,6 +335,7 @@
                                                              coverage)
                                    : false;
     UniquePaintParamsID paintID = ExtractPaintData(recorder.get(),
+                                                   &floatStorageManager,
                                                    &gatherer,
                                                    &builder,
                                                    layout,
@@ -352,7 +353,6 @@
 
     std::vector<UniquePaintParamsID> precompileIDs;
     paintOptions.priv().buildCombinations(precompileKeyContext,
-                                          &gatherer,
                                           DrawTypeFlags::kNone,
                                           /* withPrimitiveBlender= */ false,
                                           coverage,
diff --git a/include/gpu/graphite/precompile/PaintOptions.h b/include/gpu/graphite/precompile/PaintOptions.h
index 0928a7b..f3e8ba2 100644
--- a/include/gpu/graphite/precompile/PaintOptions.h
+++ b/include/gpu/graphite/precompile/PaintOptions.h
@@ -32,7 +32,6 @@
 class KeyContext;
 class PaintOptionsPriv;
 class PaintParamsKeyBuilder;
-class PipelineDataGatherer;
 struct RenderPassDesc;
 class UniquePaintParamsID;
 
@@ -174,8 +173,6 @@
     // 'desiredCombination' must be less than the result of the numCombinations call
     void createKey(const KeyContext&,
                    TextureFormat,
-                   PaintParamsKeyBuilder*,
-                   PipelineDataGatherer*,
                    int desiredCombination,
                    bool addPrimitiveBlender,
                    bool addAnalyticClip,
@@ -188,7 +185,6 @@
                                const RenderPassDesc&)> ProcessCombination;
 
     void buildCombinations(const KeyContext&,
-                           PipelineDataGatherer*,
                            DrawTypeFlags,
                            bool addPrimitiveBlender,
                            Coverage,
diff --git a/include/gpu/graphite/precompile/PrecompileBase.h b/include/gpu/graphite/precompile/PrecompileBase.h
index f4b425b..e8e1412 100644
--- a/include/gpu/graphite/precompile/PrecompileBase.h
+++ b/include/gpu/graphite/precompile/PrecompileBase.h
@@ -15,7 +15,6 @@
 
 class KeyContext;
 class PaintParamsKeyBuilder;
-class PipelineDataGatherer;
 class PrecompileBasePriv;
 
 /** \class PrecompileBase
@@ -51,10 +50,7 @@
         return this->numIntrinsicCombinations() * this->numChildCombinations();
     }
 
-    virtual void addToKey(const KeyContext&,
-                          PaintParamsKeyBuilder*,
-                          PipelineDataGatherer*,
-                          int desiredCombination) const = 0;
+    virtual void addToKey(const KeyContext&, int desiredCombination) const = 0;
 
     // This returns the desired option along with the child options.
     template<typename T>
@@ -64,11 +60,7 @@
     // In general, derived classes should use AddToKey to select the desired child option from
     // a span and then have it added to the key with its reduced/nested child option.
     template<typename T>
-    static void AddToKey(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         SkSpan<const sk_sp<T>> options,
-                         int desiredOption);
+    static void AddToKey(const KeyContext&, SkSpan<const sk_sp<T>> options, int desiredOption);
 
 private:
     friend class PrecompileBasePriv;
diff --git a/include/gpu/graphite/precompile/PrecompileImageFilter.h b/include/gpu/graphite/precompile/PrecompileImageFilter.h
index d81482a..1fc0597 100644
--- a/include/gpu/graphite/precompile/PrecompileImageFilter.h
+++ b/include/gpu/graphite/precompile/PrecompileImageFilter.h
@@ -52,20 +52,15 @@
     // The PrecompileImageFilter classes do not use the PrecompileBase::addToKey virtual since
     // they, in general, do not themselves contribute to a given SkPaint/Pipeline but, rather,
     // create separate SkPaints/Pipelines from whole cloth (in onCreatePipelines).
-    void addToKey(const KeyContext& /* keyContext */,
-                  PaintParamsKeyBuilder* /* builder */,
-                  PipelineDataGatherer* /* gatherer */,
-                  int /* desiredCombination */) const final {
+    void addToKey(const KeyContext& /* keyContext */, int /* desiredCombination */) const final {
         SkASSERT(false);
     }
 
     virtual void onCreatePipelines(const KeyContext&,
-                                   PipelineDataGatherer*,
                                    const RenderPassDesc&,
                                    const PaintOptions::ProcessCombination&) const = 0;
 
     void createPipelines(const KeyContext&,
-                         PipelineDataGatherer*,
                          const RenderPassDesc&,
                          const PaintOptions::ProcessCombination&);
 
diff --git a/include/gpu/graphite/precompile/PrecompileMaskFilter.h b/include/gpu/graphite/precompile/PrecompileMaskFilter.h
index 718d7df..b6ca477 100644
--- a/include/gpu/graphite/precompile/PrecompileMaskFilter.h
+++ b/include/gpu/graphite/precompile/PrecompileMaskFilter.h
@@ -24,13 +24,9 @@
     PrecompileMaskFilter() : PrecompileBase(Type::kMaskFilter) {}
     ~PrecompileMaskFilter() override;
 
-    void addToKey(const KeyContext&,
-                  PaintParamsKeyBuilder*,
-                  PipelineDataGatherer*,
-                  int desiredCombination) const final;
+    void addToKey(const KeyContext&, int desiredCombination) const final;
 
     virtual void createPipelines(const KeyContext&,
-                                 PipelineDataGatherer*,
                                  const PaintOptions&,
                                  const RenderPassDesc&,
                                  const PaintOptions::ProcessCombination&) const = 0;
diff --git a/src/gpu/graphite/ContextUtils.cpp b/src/gpu/graphite/ContextUtils.cpp
index 8b2da5a..ffebe3e 100644
--- a/src/gpu/graphite/ContextUtils.cpp
+++ b/src/gpu/graphite/ContextUtils.cpp
@@ -42,6 +42,7 @@
 namespace skgpu::graphite {
 
 UniquePaintParamsID ExtractPaintData(Recorder* recorder,
+                                     FloatStorageManager* floatStorageManager,
                                      PipelineDataGatherer* gatherer,
                                      PaintParamsKeyBuilder* builder,
                                      const Layout layout,
@@ -53,13 +54,16 @@
     SkDEBUGCODE(gatherer->checkReset());
 
     KeyContext keyContext(recorder,
+                          floatStorageManager,
+                          builder,
+                          gatherer,
                           local2Dev,
                           targetColorInfo,
                           geometry.isShape() || geometry.isEdgeAAQuad()
                                   ? KeyGenFlags::kDefault
                                   : KeyGenFlags::kDisableSamplingOptimization,
                           p.color());
-    p.toKey(keyContext, builder, gatherer);
+    p.toKey(keyContext);
 
     return recorder->priv().shaderCodeDictionary()->findOrCreate(builder);
 }
diff --git a/src/gpu/graphite/ContextUtils.h b/src/gpu/graphite/ContextUtils.h
index 92df908..80cce94 100644
--- a/src/gpu/graphite/ContextUtils.h
+++ b/src/gpu/graphite/ContextUtils.h
@@ -27,6 +27,7 @@
 class Caps;
 class ComputeStep;
 enum class Coverage;
+class FloatStorageManager;
 class Geometry;
 class PaintParams;
 class PaintParamsKeyBuilder;
@@ -44,6 +45,7 @@
 enum class Layout : uint8_t;
 
 UniquePaintParamsID ExtractPaintData(Recorder*,
+                                     FloatStorageManager* floatStorageManager,
                                      PipelineDataGatherer* gatherer,
                                      PaintParamsKeyBuilder* builder,
                                      const Layout layout,
diff --git a/src/gpu/graphite/DrawPass.cpp b/src/gpu/graphite/DrawPass.cpp
index 7917176..9205535 100644
--- a/src/gpu/graphite/DrawPass.cpp
+++ b/src/gpu/graphite/DrawPass.cpp
@@ -430,6 +430,8 @@
     // The initial layout we pass here is not important as it will be re-assigned when writing
     // shading and geometry uniforms below.
     PipelineDataGatherer gatherer(uniformLayout);
+    // Track the grad buffers
+    FloatStorageManager floatStorageManager;
 
     std::vector<SortKey> keys;
     keys.reserve(draws->renderStepCount());
@@ -442,6 +444,7 @@
 
         if (draw.fPaintParams.has_value()) {
             shaderID = ExtractPaintData(recorder,
+                                        &floatStorageManager,
                                         &gatherer,
                                         &builder,
                                         uniformLayout,
@@ -486,7 +489,7 @@
     }
 
     GradientBufferTracker gradientBufferTracker;
-    if (!gradientBufferTracker.writeData(gatherer.gradientBufferData(), bufferMgr)) {
+    if (!gradientBufferTracker.writeData(floatStorageManager.data(), bufferMgr)) {
         // The necessary uniform data couldn't be written to the GPU, so the DrawPass is invalid.
         // Early out now since the next Recording snap will fail.
         return nullptr;
diff --git a/src/gpu/graphite/KeyContext.cpp b/src/gpu/graphite/KeyContext.cpp
index 75df34d..f9b5714 100644
--- a/src/gpu/graphite/KeyContext.cpp
+++ b/src/gpu/graphite/KeyContext.cpp
@@ -15,11 +15,17 @@
 namespace skgpu::graphite {
 
 KeyContext::KeyContext(skgpu::graphite::Recorder* recorder,
+                       FloatStorageManager* floatStorageManager,
+                       PaintParamsKeyBuilder* paintParamsKeyBuilder,
+                       PipelineDataGatherer* pipelineDataGatherer,
                        const SkM44& local2Dev,
                        const SkColorInfo& dstColorInfo,
                        SkEnumBitMask<KeyGenFlags> initialFlags,
                        const SkColor4f& paintColor)
         : fRecorder(recorder)
+        , fFloatStorageManager(floatStorageManager)
+        , fPaintParamsKeyBuilder(paintParamsKeyBuilder)
+        , fPipelineDataGatherer(pipelineDataGatherer)
         , fLocal2Dev(local2Dev)
         , fLocalMatrix(nullptr)
         , fDstColorInfo(dstColorInfo)
@@ -33,6 +39,9 @@
 
 KeyContext::KeyContext(const KeyContext& other)
         : fRecorder(other.fRecorder)
+        , fFloatStorageManager(other.fFloatStorageManager)
+        , fPaintParamsKeyBuilder(other.fPaintParamsKeyBuilder)
+        , fPipelineDataGatherer(other.fPipelineDataGatherer)
         , fLocal2Dev(other.fLocal2Dev)
         , fLocalMatrix(other.fLocalMatrix)
         , fDictionary(other.fDictionary)
diff --git a/src/gpu/graphite/KeyContext.h b/src/gpu/graphite/KeyContext.h
index 24ec2b3..f0d7fe4 100644
--- a/src/gpu/graphite/KeyContext.h
+++ b/src/gpu/graphite/KeyContext.h
@@ -22,6 +22,9 @@
 
 class Caps;
 enum class DstReadStrategy : uint8_t;
+class FloatStorageManager;
+class PaintParamsKeyBuilder;
+class PipelineDataGatherer;
 class Recorder;
 class RuntimeEffectDictionary;
 class ShaderCodeDictionary;
@@ -50,16 +53,25 @@
 public:
     // Constructor for the pre-compile code path (i.e., no Recorder)
     KeyContext(const Caps* caps,
+               FloatStorageManager* floatStorageManager,
+               PaintParamsKeyBuilder* paintParamsKeyBuilder,
+               PipelineDataGatherer* pipelineDataGatherer,
                ShaderCodeDictionary* dict,
                RuntimeEffectDictionary* rtEffectDict,
                const SkColorInfo& dstColorInfo)
-            : fDictionary(dict)
+            : fFloatStorageManager(floatStorageManager)
+            , fPaintParamsKeyBuilder(paintParamsKeyBuilder)
+            , fPipelineDataGatherer(pipelineDataGatherer)
+            , fDictionary(dict)
             , fRTEffectDict(rtEffectDict)
             , fDstColorInfo(dstColorInfo)
             , fCaps(caps) {}
 
     // Constructor for the ExtractPaintData code path (i.e., with a Recorder)
     KeyContext(Recorder*,
+               FloatStorageManager* floatStorageManager,
+               PaintParamsKeyBuilder* paintParamsKeyBuilder,
+               PipelineDataGatherer* pipelineDataGatherer,
                const SkM44& local2Dev,
                const SkColorInfo& dstColorInfo,
                SkEnumBitMask<KeyGenFlags> initialFlags,
@@ -74,6 +86,9 @@
     const SkM44& local2Dev() const { return fLocal2Dev; }
     const SkMatrix* localMatrix() const { return fLocalMatrix; }
 
+    FloatStorageManager* floatStorageManager() const { return fFloatStorageManager; }
+    PaintParamsKeyBuilder* paintParamsKeyBuilder() const { return fPaintParamsKeyBuilder; }
+    PipelineDataGatherer* pipelineDataGatherer() const { return fPipelineDataGatherer; }
     ShaderCodeDictionary* dict() const { return fDictionary; }
     RuntimeEffectDictionary* rtEffectDict() const { return fRTEffectDict; }
 
@@ -85,6 +100,9 @@
 
 protected:
     Recorder* fRecorder = nullptr;
+    FloatStorageManager* fFloatStorageManager;
+    PaintParamsKeyBuilder* fPaintParamsKeyBuilder;
+    PipelineDataGatherer* fPipelineDataGatherer;
     SkM44 fLocal2Dev;
     SkMatrix* fLocalMatrix = nullptr;
     ShaderCodeDictionary* fDictionary;
diff --git a/src/gpu/graphite/KeyHelpers.cpp b/src/gpu/graphite/KeyHelpers.cpp
index 941b23d..fc25cf0 100644
--- a/src/gpu/graphite/KeyHelpers.cpp
+++ b/src/gpu/graphite/KeyHelpers.cpp
@@ -91,10 +91,9 @@
 // Automatically registers uniform expectations in debug builds.
 class ScopedUniformWriter {
 public:
-    ScopedUniformWriter(PipelineDataGatherer* gatherer,
-                        const ShaderCodeDictionary* dict,
-                        BuiltInCodeSnippetID codeSnippetID)
-            : ScopedUniformWriter(gatherer, dict->getEntry(codeSnippetID)) {}
+    ScopedUniformWriter(const KeyContext& keyContext, BuiltInCodeSnippetID codeSnippetID)
+            : ScopedUniformWriter(keyContext.pipelineDataGatherer(),
+                                  keyContext.dict()->getEntry(codeSnippetID)) {}
 
     ~ScopedUniformWriter() {
         if (fGatherer) {
@@ -120,61 +119,45 @@
     SkDEBUGCODE(UniformExpectationsValidator fValidator;)
 };
 
-#define BEGIN_WRITE_UNIFORMS(gatherer, dict, codeSnippetID) \
-    ScopedUniformWriter scope{gatherer, dict, codeSnippetID};
+#define BEGIN_WRITE_UNIFORMS(keyContext, codeSnippetID) \
+    ScopedUniformWriter scope{keyContext, codeSnippetID};
 
-void add_solid_uniform_data(const ShaderCodeDictionary* dict,
-                            const SkPMColor4f& premulColor,
-                            PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kSolidColorShader)
-    gatherer->write(premulColor);
+void add_solid_uniform_data(const KeyContext& keyContext, const SkPMColor4f& premulColor) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kSolidColorShader)
+    keyContext.pipelineDataGatherer()->write(premulColor);
 }
 
 } // anonymous namespace
 
-void SolidColorShaderBlock::AddBlock(const KeyContext& keyContext,
-                                     PaintParamsKeyBuilder* builder,
-                                     PipelineDataGatherer* gatherer,
-                                     const SkPMColor4f& premulColor) {
-    add_solid_uniform_data(keyContext.dict(), premulColor, gatherer);
-
-    builder->addBlock(BuiltInCodeSnippetID::kSolidColorShader);
+void SolidColorShaderBlock::AddBlock(const KeyContext& keyContext, const SkPMColor4f& premulColor) {
+    add_solid_uniform_data(keyContext, premulColor);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kSolidColorShader);
 }
 
 //--------------------------------------------------------------------------------------------------
 
 namespace {
 
-void add_rgb_paint_color_uniform_data(const ShaderCodeDictionary* dict,
-                                      const SkPMColor4f& premulColor,
-                                      PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kRGBPaintColor)
-    gatherer->writePaintColor(premulColor);
+void add_rgb_paint_color_uniform_data(const KeyContext& keyContext) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kRGBPaintColor)
+    keyContext.pipelineDataGatherer()->writePaintColor(keyContext.paintColor());
 }
 
-void add_alpha_only_paint_color_uniform_data(const ShaderCodeDictionary* dict,
-                                             const SkPMColor4f& premulColor,
-                                             PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kAlphaOnlyPaintColor)
-    gatherer->writePaintColor(premulColor);
+void add_alpha_only_paint_color_uniform_data(const KeyContext& keyContext) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kAlphaOnlyPaintColor)
+    keyContext.pipelineDataGatherer()->writePaintColor(keyContext.paintColor());
 }
 
 } // anonymous namespace
 
-void RGBPaintColorBlock::AddBlock(const KeyContext& keyContext,
-                                  PaintParamsKeyBuilder* builder,
-                                  PipelineDataGatherer* gatherer) {
-    add_rgb_paint_color_uniform_data(keyContext.dict(), keyContext.paintColor(), gatherer);
-
-    builder->addBlock(BuiltInCodeSnippetID::kRGBPaintColor);
+void RGBPaintColorBlock::AddBlock(const KeyContext& keyContext) {
+    add_rgb_paint_color_uniform_data(keyContext);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kRGBPaintColor);
 }
 
-void AlphaOnlyPaintColorBlock::AddBlock(const KeyContext& keyContext,
-                                        PaintParamsKeyBuilder* builder,
-                                        PipelineDataGatherer* gatherer) {
-    add_alpha_only_paint_color_uniform_data(keyContext.dict(), keyContext.paintColor(), gatherer);
-
-    builder->addBlock(BuiltInCodeSnippetID::kAlphaOnlyPaintColor);
+void AlphaOnlyPaintColorBlock::AddBlock(const KeyContext& keyContext) {
+    add_alpha_only_paint_color_uniform_data(keyContext);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kAlphaOnlyPaintColor);
 }
 
 //--------------------------------------------------------------------------------------------------
@@ -236,47 +219,43 @@
     gatherer->write(static_cast<int>(inputPremul));
 }
 
-void add_linear_gradient_uniform_data(const ShaderCodeDictionary* dict,
+void add_linear_gradient_uniform_data(const KeyContext& keyContext,
                                       BuiltInCodeSnippetID codeSnippetID,
                                       const GradientShaderBlocks::GradientData& gradData,
-                                      int bufferOffset,
-                                      PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, codeSnippetID)
+                                      int bufferOffset) {
+    BEGIN_WRITE_UNIFORMS(keyContext, codeSnippetID)
 
-    add_gradient_preamble(gradData, gatherer);
-    add_gradient_postamble(gradData, bufferOffset, gatherer);
+    add_gradient_preamble(gradData, keyContext.pipelineDataGatherer());
+    add_gradient_postamble(gradData, bufferOffset, keyContext.pipelineDataGatherer());
 };
 
-void add_radial_gradient_uniform_data(const ShaderCodeDictionary* dict,
+void add_radial_gradient_uniform_data(const KeyContext& keyContext,
                                       BuiltInCodeSnippetID codeSnippetID,
                                       const GradientShaderBlocks::GradientData& gradData,
-                                      int bufferOffset,
-                                      PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, codeSnippetID)
+                                      int bufferOffset) {
+    BEGIN_WRITE_UNIFORMS(keyContext, codeSnippetID)
 
-    add_gradient_preamble(gradData, gatherer);
-    add_gradient_postamble(gradData, bufferOffset, gatherer);
+    add_gradient_preamble(gradData, keyContext.pipelineDataGatherer());
+    add_gradient_postamble(gradData, bufferOffset, keyContext.pipelineDataGatherer());
 };
 
-void add_sweep_gradient_uniform_data(const ShaderCodeDictionary* dict,
+void add_sweep_gradient_uniform_data(const KeyContext& keyContext,
                                      BuiltInCodeSnippetID codeSnippetID,
                                      const GradientShaderBlocks::GradientData& gradData,
-                                     int bufferOffset,
-                                     PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, codeSnippetID)
+                                     int bufferOffset) {
+    BEGIN_WRITE_UNIFORMS(keyContext, codeSnippetID)
 
-    add_gradient_preamble(gradData, gatherer);
-    gatherer->write(gradData.fBias);
-    gatherer->write(gradData.fScale);
-    add_gradient_postamble(gradData, bufferOffset, gatherer);
+    add_gradient_preamble(gradData, keyContext.pipelineDataGatherer());
+    keyContext.pipelineDataGatherer()->write(gradData.fBias);
+    keyContext.pipelineDataGatherer()->write(gradData.fScale);
+    add_gradient_postamble(gradData, bufferOffset, keyContext.pipelineDataGatherer());
 };
 
-void add_conical_gradient_uniform_data(const ShaderCodeDictionary* dict,
-                                       BuiltInCodeSnippetID codeSnippetID,
-                                       const GradientShaderBlocks::GradientData& gradData,
-                                       int bufferOffset,
-                                       PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, codeSnippetID)
+void add_conical_gradient_uniform_data(const KeyContext& keyContext,
+                                     BuiltInCodeSnippetID codeSnippetID,
+                                     const GradientShaderBlocks::GradientData& gradData,
+                                     int bufferOffset) {
+    BEGIN_WRITE_UNIFORMS(keyContext, codeSnippetID)
 
     float dRadius = gradData.fRadii[1] - gradData.fRadii[0];
     bool isRadial = SkPoint::Distance(gradData.fPoints[1], gradData.fPoints[0])
@@ -299,12 +278,12 @@
         dRadius = gradData.fRadii[0] > 0 ? 1 : -1;
     }
 
-    add_gradient_preamble(gradData, gatherer);
-    gatherer->write(gradData.fRadii[0]);
-    gatherer->write(dRadius);
-    gatherer->write(a);
-    gatherer->write(invA);
-    add_gradient_postamble(gradData, bufferOffset, gatherer);
+    add_gradient_preamble(gradData, keyContext.pipelineDataGatherer());
+    keyContext.pipelineDataGatherer()->write(gradData.fRadii[0]);
+    keyContext.pipelineDataGatherer()->write(dRadius);
+    keyContext.pipelineDataGatherer()->write(a);
+    keyContext.pipelineDataGatherer()->write(invA);
+    add_gradient_postamble(gradData, bufferOffset, keyContext.pipelineDataGatherer());
 };
 
 } // anonymous namespace
@@ -315,8 +294,8 @@
                                            const SkPMColor4f* colors,
                                            const float* offsets,
                                            const SkGradientBaseShader* shader,
-                                           PipelineDataGatherer* gatherer) {
-    auto [dstData, bufferOffset] = gatherer->allocateGradientData(numStops, shader);
+                                           FloatStorageManager* floatStorageManager) {
+    auto [dstData, bufferOffset] = floatStorageManager->allocateGradientData(numStops, shader);
     if (dstData) {
         // Data doesn't already exist so we need to write it.
         // Writes all offset data, then color data. This way when binary searching through the
@@ -407,12 +386,7 @@
     }
 }
 
-void GradientShaderBlocks::AddBlock(const KeyContext& keyContext,
-                                    PaintParamsKeyBuilder* builder,
-                                    PipelineDataGatherer* gatherer,
-                                    const GradientData& gradData) {
-    auto dict = keyContext.dict();
-
+void GradientShaderBlocks::AddBlock(const KeyContext& keyContext, const GradientData& gradData) {
     int bufferOffset = 0;
     if (gradData.fNumStops > GradientData::kNumInternalStorageStops && keyContext.recorder()) {
         if (gradData.fUseStorageBuffer) {
@@ -420,10 +394,10 @@
                                                           gradData.fSrcColors,
                                                           gradData.fSrcOffsets,
                                                           gradData.fSrcShader,
-                                                          gatherer);
+                                                          keyContext.floatStorageManager());
         } else {
             SkASSERT(gradData.fColorsAndOffsetsProxy);
-            gatherer->add(gradData.fColorsAndOffsetsProxy,
+            keyContext.pipelineDataGatherer()->add(gradData.fColorsAndOffsetsProxy,
                           {SkFilterMode::kNearest, SkTileMode::kClamp});
         }
     }
@@ -437,7 +411,7 @@
                         : gradData.fUseStorageBuffer
                             ? BuiltInCodeSnippetID::kLinearGradientShaderBuffer
                             : BuiltInCodeSnippetID::kLinearGradientShaderTexture;
-            add_linear_gradient_uniform_data(dict, codeSnippetID, gradData, bufferOffset, gatherer);
+            add_linear_gradient_uniform_data(keyContext, codeSnippetID, gradData, bufferOffset);
             break;
         case SkShaderBase::GradientType::kRadial:
             codeSnippetID =
@@ -446,7 +420,7 @@
                         : gradData.fUseStorageBuffer
                             ? BuiltInCodeSnippetID::kRadialGradientShaderBuffer
                             : BuiltInCodeSnippetID::kRadialGradientShaderTexture;
-            add_radial_gradient_uniform_data(dict, codeSnippetID, gradData, bufferOffset, gatherer);
+            add_radial_gradient_uniform_data(keyContext, codeSnippetID, gradData, bufferOffset);
             break;
         case SkShaderBase::GradientType::kSweep:
             codeSnippetID =
@@ -455,7 +429,7 @@
                         : gradData.fUseStorageBuffer
                             ? BuiltInCodeSnippetID::kSweepGradientShaderBuffer
                             : BuiltInCodeSnippetID::kSweepGradientShaderTexture;
-            add_sweep_gradient_uniform_data(dict, codeSnippetID, gradData, bufferOffset, gatherer);
+            add_sweep_gradient_uniform_data(keyContext, codeSnippetID, gradData, bufferOffset);
             break;
         case SkShaderBase::GradientType::kConical:
             codeSnippetID =
@@ -464,7 +438,7 @@
                         : gradData.fUseStorageBuffer
                             ? BuiltInCodeSnippetID::kConicalGradientShaderBuffer
                             : BuiltInCodeSnippetID::kConicalGradientShaderTexture;
-            add_conical_gradient_uniform_data(dict, codeSnippetID, gradData, bufferOffset, gatherer);
+            add_conical_gradient_uniform_data(keyContext, codeSnippetID, gradData, bufferOffset);
             break;
         case SkShaderBase::GradientType::kNone:
         default:
@@ -472,33 +446,31 @@
             break;
     }
 
-    builder->addBlock(codeSnippetID);
+    keyContext.paintParamsKeyBuilder()->addBlock(codeSnippetID);
 }
 
 //--------------------------------------------------------------------------------------------------
 
 void LocalMatrixShaderBlock::BeginBlock(const KeyContext& keyContext,
-                                        PaintParamsKeyBuilder* builder,
-                                        PipelineDataGatherer* gatherer,
                                         const LMShaderData& lmShaderData) {
-    const ShaderCodeDictionary* dict = keyContext.dict();
     const SkMatrix& m = lmShaderData.fLocalMatrix;
 
     if (lmShaderData.fLocalMatrix.hasPerspective()) {
         // Perspective local matrices are rare enough and add enough extra instructions that it's
         // worth specializing since it has to perform a per-pixel division.
-        builder->beginBlock(BuiltInCodeSnippetID::kLocalMatrixShaderPersp);
-        BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kLocalMatrixShaderPersp)
-        gatherer->write(m);
+        keyContext.paintParamsKeyBuilder()->beginBlock(
+                BuiltInCodeSnippetID::kLocalMatrixShaderPersp);
+        BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kLocalMatrixShaderPersp)
+        keyContext.pipelineDataGatherer()->write(m);
     } else {
         // For an affine 2D transform, we only need to upload the upper 2x2 and XY translation.
-        builder->beginBlock(BuiltInCodeSnippetID::kLocalMatrixShader);
+        keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kLocalMatrixShader);
 
-        BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kLocalMatrixShader)
+        BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kLocalMatrixShader)
         // The upper 2x2 is expected to be in column major order, but SkMatrix is 3x3 row major.
-        gatherer->write(SkV4{m.getScaleX(), m.getSkewY(),
+        keyContext.pipelineDataGatherer()->write(SkV4{m.getScaleX(), m.getSkewY(),
                              m.getSkewX(),  m.getScaleY()});
-        gatherer->write(SkV2{m.getTranslateX(), m.getTranslateY()});
+        keyContext.pipelineDataGatherer()->write(SkV2{m.getTranslateX(), m.getTranslateY()});
     }
 }
 
@@ -506,26 +478,26 @@
 
 namespace {
 
-void add_image_uniform_data(const ShaderCodeDictionary* dict,
-                            const ImageShaderBlock::ImageData& imgData,
-                            PipelineDataGatherer* gatherer) {
+void add_image_uniform_data(const KeyContext& keyContext,
+                            const ImageShaderBlock::ImageData& imgData) {
     SkASSERT(!imgData.fSampling.useCubic);
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kImageShader)
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kImageShader)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
-    gatherer->write(imgData.fSubset);
-    gatherer->write(SkTo<int>(imgData.fTileModes.first));
-    gatherer->write(SkTo<int>(imgData.fTileModes.second));
-    gatherer->write(SkTo<int>(imgData.fSampling.filter));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                             1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(imgData.fSubset);
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.first));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.second));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fSampling.filter));
 }
 
-void add_clamp_image_uniform_data(const ShaderCodeDictionary* dict,
-                                  const ImageShaderBlock::ImageData& imgData,
-                                  PipelineDataGatherer* gatherer) {
+void add_clamp_image_uniform_data(const KeyContext& keyContext,
+                                  const ImageShaderBlock::ImageData& imgData) {
     SkASSERT(!imgData.fSampling.useCubic);
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kImageShaderClamp)
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kImageShaderClamp)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                                          1.f/imgData.fImgSize.height()));
 
     // Matches GrTextureEffect::kLinearInset, to make sure we don't touch an outer row or column
     // with a weight of 0 when linear filtering.
@@ -538,21 +510,22 @@
         subsetInsetClamp.roundOut(&subsetInsetClamp);
     }
     subsetInsetClamp.inset(kLinearInset, kLinearInset);
-    gatherer->write(subsetInsetClamp);
+    keyContext.pipelineDataGatherer()->write(subsetInsetClamp);
 }
 
-void add_cubic_image_uniform_data(const ShaderCodeDictionary* dict,
-                                  const ImageShaderBlock::ImageData& imgData,
-                                  PipelineDataGatherer* gatherer) {
+void add_cubic_image_uniform_data(const KeyContext& keyContext,
+                                  const ImageShaderBlock::ImageData& imgData) {
     SkASSERT(imgData.fSampling.useCubic);
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCubicImageShader)
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kCubicImageShader)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
-    gatherer->write(imgData.fSubset);
-    gatherer->write(SkTo<int>(imgData.fTileModes.first));
-    gatherer->write(SkTo<int>(imgData.fTileModes.second));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                                          1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(imgData.fSubset);
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.first));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.second));
     const SkCubicResampler& cubic = imgData.fSampling.cubic;
-    gatherer->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
+    keyContext.pipelineDataGatherer()->writeHalf(
+            SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
 }
 
 // If clampToBorderSupport is unavailable, kDecal will be substituted to clamp in most cases.
@@ -566,13 +539,13 @@
             imgData.fSubset.contains(SkRect::Make(imgData.fImgSize));
 }
 
-void add_sampler_data_to_key(PaintParamsKeyBuilder* builder, const SamplerDesc& samplerDesc) {
+void add_sampler_data_to_key(const KeyContext& keyContext, const SamplerDesc& samplerDesc) {
     if (samplerDesc.isImmutable()) {
-        builder->addData(samplerDesc.asSpan());
+        keyContext.paintParamsKeyBuilder()->addData(samplerDesc.asSpan());
     } else {
         // Means we have a regular dynamic sampler. Append a default SamplerDesc to convey this,
         // allowing the key to maintain and convey sampler binding order.
-        builder->addData({});
+        keyContext.paintParamsKeyBuilder()->addData({});
     }
 }
 
@@ -591,13 +564,10 @@
         , fImmutableSamplerInfo(immutableSamplerInfo) {
 }
 
-void ImageShaderBlock::AddBlock(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
-                                const ImageData& imgData) {
 
+void ImageShaderBlock::AddBlock(const KeyContext& keyContext, const ImageData& imgData) {
     if (keyContext.recorder() && !imgData.fTextureProxy) {
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
@@ -606,18 +576,18 @@
 
     if (doTilingInHw) {
         CoordNormalizeShaderBlock::CoordNormalizeData data(SkSize::Make(imgData.fImgSize));
-        CoordNormalizeShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
-        builder->beginBlock(BuiltInCodeSnippetID::kHWImageShader);
+        CoordNormalizeShaderBlock::BeginBlock(keyContext, data);
+        keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kHWImageShader);
     } else if (imgData.fSampling.useCubic) {
-        add_cubic_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->beginBlock(BuiltInCodeSnippetID::kCubicImageShader);
+        add_cubic_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kCubicImageShader);
     } else if (imgData.fTileModes.first == SkTileMode::kClamp &&
                imgData.fTileModes.second == SkTileMode::kClamp) {
-        add_clamp_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->beginBlock(BuiltInCodeSnippetID::kImageShaderClamp);
+        add_clamp_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kImageShaderClamp);
     } else {
-        add_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->beginBlock(BuiltInCodeSnippetID::kImageShader);
+        add_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kImageShader);
     }
 
     // Image shaders must append immutable sampler data (or '0' in the more common case where
@@ -630,71 +600,75 @@
     auto tileModeWithSubstitution = doTilingInHw ? imgData.fTileModes :
                                     std::make_pair(SkTileMode::kClamp, SkTileMode::kClamp);
     SamplerDesc samplerDesc{imgData.fSampling, tileModeWithSubstitution, info};
-    gatherer->add(imgData.fTextureProxy, samplerDesc);
-    add_sampler_data_to_key(builder, samplerDesc);
+    keyContext.pipelineDataGatherer()->add(imgData.fTextureProxy, samplerDesc);
+    add_sampler_data_to_key(keyContext, samplerDesc);
 
-    builder->endBlock();
+    keyContext.paintParamsKeyBuilder()->endBlock();
 
     if (doTilingInHw) {
         // Additional block for coord normalization.
-        builder->endBlock();
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 }
 
+
 //--------------------------------------------------------------------------------------------------
 
 // makes use of ImageShader functions, above
 namespace {
 
-void add_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
-                                const YUVImageShaderBlock::ImageData& imgData,
-                                PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kYUVImageShader)
+void add_yuv_image_uniform_data(const KeyContext& keyContext,
+                                const YUVImageShaderBlock::ImageData& imgData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kYUVImageShader)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
-    gatherer->write(imgData.fSubset);
-    gatherer->write(imgData.fLinearFilterUVInset);
-    gatherer->write(SkTo<int>(imgData.fTileModes.first));
-    gatherer->write(SkTo<int>(imgData.fTileModes.second));
-    gatherer->write(SkTo<int>(imgData.fSampling.filter));
-    gatherer->write(SkTo<int>(imgData.fSamplingUV.filter));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                                          1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(),
+                                                          1.f/imgData.fImgSizeUV.height()));
+    keyContext.pipelineDataGatherer()->write(imgData.fSubset);
+    keyContext.pipelineDataGatherer()->write(imgData.fLinearFilterUVInset);
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.first));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.second));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fSampling.filter));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fSamplingUV.filter));
 
     for (int i = 0; i < 4; ++i) {
-        gatherer->writeHalf(imgData.fChannelSelect[i]);
+        keyContext.pipelineDataGatherer()->writeHalf(imgData.fChannelSelect[i]);
     }
-    gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
-    gatherer->writeHalf(imgData.fYUVtoRGBTranslate);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBMatrix);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBTranslate);
 }
 
-void add_cubic_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
-                                      const YUVImageShaderBlock::ImageData& imgData,
-                                      PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCubicYUVImageShader)
+void add_cubic_yuv_image_uniform_data(const KeyContext& keyContext,
+                                      const YUVImageShaderBlock::ImageData& imgData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kCubicYUVImageShader)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
-    gatherer->write(imgData.fSubset);
-    gatherer->write(SkTo<int>(imgData.fTileModes.first));
-    gatherer->write(SkTo<int>(imgData.fTileModes.second));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                                          1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(),
+                                                          1.f/imgData.fImgSizeUV.height()));
+    keyContext.pipelineDataGatherer()->write(imgData.fSubset);
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.first));
+    keyContext.pipelineDataGatherer()->write(SkTo<int>(imgData.fTileModes.second));
     const SkCubicResampler& cubic = imgData.fSampling.cubic;
-    gatherer->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
+    keyContext.pipelineDataGatherer()->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
 
     for (int i = 0; i < 4; ++i) {
-        gatherer->writeHalf(imgData.fChannelSelect[i]);
+        keyContext.pipelineDataGatherer()->writeHalf(imgData.fChannelSelect[i]);
     }
-    gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
-    gatherer->writeHalf(imgData.fYUVtoRGBTranslate);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBMatrix);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBTranslate);
 }
 
-void add_hw_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
-                                   const YUVImageShaderBlock::ImageData& imgData,
-                                   PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kHWYUVImageShader)
+void add_hw_yuv_image_uniform_data(const KeyContext& keyContext,
+                                   const YUVImageShaderBlock::ImageData& imgData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kHWYUVImageShader)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
-    gatherer->write(imgData.fSubset);
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                                          1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(),
+                                                          1.f/imgData.fImgSizeUV.height()));
+    keyContext.pipelineDataGatherer()->write(imgData.fSubset);
 
     SkPoint linearFilterUVInset = imgData.fLinearFilterUVInset;
     // We sign-encode whether we need to adjust the UV coords by applying `fLinearFilterUVInset` for
@@ -710,23 +684,24 @@
                  imgData.fTileModes.second == SkTileMode::kClamp);
         linearFilterUVInset.fY = -linearFilterUVInset.fY;
     }
-    gatherer->write(linearFilterUVInset);
+    keyContext.pipelineDataGatherer()->write(linearFilterUVInset);
 
     for (int i = 0; i < 4; ++i) {
-        gatherer->writeHalf(imgData.fChannelSelect[i]);
+        keyContext.pipelineDataGatherer()->writeHalf(imgData.fChannelSelect[i]);
     }
-    gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
-    gatherer->writeHalf(imgData.fYUVtoRGBTranslate);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBMatrix);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBTranslate);
 }
 
-void add_hw_yuv_no_swizzle_image_uniform_data(const ShaderCodeDictionary* dict,
-                                              const YUVImageShaderBlock::ImageData& imgData,
-                                              PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kHWYUVNoSwizzleImageShader)
+void add_hw_yuv_no_swizzle_image_uniform_data(const KeyContext& keyContext,
+                                              const YUVImageShaderBlock::ImageData& imgData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kHWYUVNoSwizzleImageShader)
 
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
-    gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
-    gatherer->write(imgData.fSubset);
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSize.width(),
+                                                          1.f/imgData.fImgSize.height()));
+    keyContext.pipelineDataGatherer()->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(),
+                                                          1.f/imgData.fImgSizeUV.height()));
+    keyContext.pipelineDataGatherer()->write(imgData.fSubset);
 
     SkPoint linearFilterUVInset = imgData.fLinearFilterUVInset;
     // We sign-encode whether we need to adjust the UV coords by applying `fLinearFilterUVInset` for
@@ -742,16 +717,16 @@
                  imgData.fTileModes.second == SkTileMode::kClamp);
         linearFilterUVInset.fY = -linearFilterUVInset.fY;
     }
-    gatherer->write(linearFilterUVInset);
+    keyContext.pipelineDataGatherer()->write(linearFilterUVInset);
 
-    gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
+    keyContext.pipelineDataGatherer()->writeHalf(imgData.fYUVtoRGBMatrix);
     SkV4 yuvToRGBXlateAlphaParam = {
         imgData.fYUVtoRGBTranslate.fX,
         imgData.fYUVtoRGBTranslate.fY,
         imgData.fYUVtoRGBTranslate.fZ,
         imgData.fAlphaParam
     };
-    gatherer->writeHalf(yuvToRGBXlateAlphaParam);
+    keyContext.pipelineDataGatherer()->writeHalf(yuvToRGBXlateAlphaParam);
 }
 
 } // anonymous namespace
@@ -794,14 +769,11 @@
     return false;
 }
 
-void YUVImageShaderBlock::AddBlock(const KeyContext& keyContext,
-                                   PaintParamsKeyBuilder* builder,
-                                   PipelineDataGatherer* gatherer,
-                                   const ImageData& imgData) {
+void YUVImageShaderBlock::AddBlock(const KeyContext& keyContext, const ImageData& imgData) {
     if (keyContext.recorder() &&
         (!imgData.fTextureProxies[0] || !imgData.fTextureProxies[1] ||
          !imgData.fTextureProxies[2] || !imgData.fTextureProxies[3])) {
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
@@ -816,23 +788,31 @@
                                             ? SkTileMode::kClamp : imgData.fTileModes.second);
     auto yAlphaTileModes = doTilingInHw ? imgData.fTileModes :
                            std::make_pair(SkTileMode::kClamp, SkTileMode::kClamp);
-    gatherer->add(imgData.fTextureProxies[0], {imgData.fSampling, yAlphaTileModes});
-    gatherer->add(imgData.fTextureProxies[1], {imgData.fSamplingUV, uvTileModes});
-    gatherer->add(imgData.fTextureProxies[2], {imgData.fSamplingUV, uvTileModes});
-    gatherer->add(imgData.fTextureProxies[3], {imgData.fSampling, yAlphaTileModes});
+    keyContext.pipelineDataGatherer()->add(imgData.fTextureProxies[0],
+                                           {imgData.fSampling, yAlphaTileModes});
+    keyContext.pipelineDataGatherer()->add(imgData.fTextureProxies[1],
+                                           {imgData.fSamplingUV, uvTileModes});
+    keyContext.pipelineDataGatherer()->add(imgData.fTextureProxies[2],
+                                           {imgData.fSamplingUV, uvTileModes});
+    keyContext.pipelineDataGatherer()->add(imgData.fTextureProxies[3],
+                                           {imgData.fSampling, yAlphaTileModes});
 
     if (doTilingInHw && noYUVSwizzle) {
-        add_hw_yuv_no_swizzle_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kHWYUVNoSwizzleImageShader);
+        add_hw_yuv_no_swizzle_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->addBlock(
+                BuiltInCodeSnippetID::kHWYUVNoSwizzleImageShader);
     } else if (doTilingInHw) {
-        add_hw_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kHWYUVImageShader);
+        add_hw_yuv_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->addBlock(
+                BuiltInCodeSnippetID::kHWYUVImageShader);
     } else if (imgData.fSampling.useCubic) {
-        add_cubic_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kCubicYUVImageShader);
+        add_cubic_yuv_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->addBlock(
+                BuiltInCodeSnippetID::kCubicYUVImageShader);
     } else {
-        add_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kYUVImageShader);
+        add_yuv_image_uniform_data(keyContext, imgData);
+        keyContext.paintParamsKeyBuilder()->addBlock(
+                BuiltInCodeSnippetID::kYUVImageShader);
     }
 }
 
@@ -840,83 +820,70 @@
 
 namespace {
 
-void add_coord_normalize_uniform_data(const ShaderCodeDictionary* dict,
-                                      const CoordNormalizeShaderBlock::CoordNormalizeData& data,
-                                      PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCoordNormalizeShader)
-
-    gatherer->write(data.fInvDimensions);
+void add_coord_normalize_uniform_data(const KeyContext& keyContext,
+                                      const CoordNormalizeShaderBlock::CoordNormalizeData& data) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kCoordNormalizeShader)
+    keyContext.pipelineDataGatherer()->write(data.fInvDimensions);
 }
 
 } // anonymous namespace
 
 void CoordNormalizeShaderBlock::BeginBlock(const KeyContext& keyContext,
-                                           PaintParamsKeyBuilder* builder,
-                                           PipelineDataGatherer* gatherer,
                                            const CoordNormalizeData& data) {
-    add_coord_normalize_uniform_data(keyContext.dict(), data, gatherer);
-
-    builder->beginBlock(BuiltInCodeSnippetID::kCoordNormalizeShader);
+    add_coord_normalize_uniform_data(keyContext, data);
+    keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kCoordNormalizeShader);
 }
 
 //--------------------------------------------------------------------------------------------------
 
 namespace {
 
-void add_coordclamp_uniform_data(const ShaderCodeDictionary* dict,
-                                 const CoordClampShaderBlock::CoordClampData& clampData,
-                                 PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCoordClampShader)
-
-    gatherer->write(clampData.fSubset);
+void add_coordclamp_uniform_data(const KeyContext& keyContext,
+                                 const CoordClampShaderBlock::CoordClampData& clampData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kCoordClampShader)
+    keyContext.pipelineDataGatherer()->write(clampData.fSubset);
 }
 
 } // anonymous namespace
 
 void CoordClampShaderBlock::BeginBlock(const KeyContext& keyContext,
-                                       PaintParamsKeyBuilder* builder,
-                                       PipelineDataGatherer* gatherer,
                                        const CoordClampData& clampData) {
-    add_coordclamp_uniform_data(keyContext.dict(), clampData, gatherer);
-
-    builder->beginBlock(BuiltInCodeSnippetID::kCoordClampShader);
+    add_coordclamp_uniform_data(keyContext, clampData);
+    keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kCoordClampShader);
 }
 
 //--------------------------------------------------------------------------------------------------
 
 namespace {
 
-void add_dither_uniform_data(const ShaderCodeDictionary* dict,
-                             const DitherShaderBlock::DitherData& ditherData,
-                             PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kDitherShader)
+void add_dither_uniform_data(const KeyContext& keyContext,
+                             const DitherShaderBlock::DitherData& ditherData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kDitherShader)
 
-    gatherer->writeHalf(ditherData.fRange);
+    keyContext.pipelineDataGatherer()->writeHalf(ditherData.fRange);
 }
 
 } // anonymous namespace
 
-void DitherShaderBlock::AddBlock(const KeyContext& keyContext,
-                                 PaintParamsKeyBuilder* builder,
-                                 PipelineDataGatherer* gatherer,
-                                 const DitherData& data) {
-    add_dither_uniform_data(keyContext.dict(), data, gatherer);
+void DitherShaderBlock::AddBlock(const KeyContext& keyContext, const DitherData& data) {
+    auto gatherer = keyContext.pipelineDataGatherer();
+    add_dither_uniform_data(keyContext, data);
 
     SkASSERT(data.fLUTProxy || !keyContext.recorder());
     gatherer->add(data.fLUTProxy, {SkFilterMode::kNearest, SkTileMode::kRepeat});
 
-    builder->addBlock(BuiltInCodeSnippetID::kDitherShader);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kDitherShader);
 }
 
 //--------------------------------------------------------------------------------------------------
 
 namespace {
 
-void add_perlin_noise_uniform_data(const ShaderCodeDictionary* dict,
-                                   const PerlinNoiseShaderBlock::PerlinNoiseData& noiseData,
-                                   PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kPerlinNoiseShader)
+void add_perlin_noise_uniform_data(const KeyContext& keyContext,
+                                   const PerlinNoiseShaderBlock::PerlinNoiseData& noiseData) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kPerlinNoiseShader)
 
+    auto gatherer = keyContext.pipelineDataGatherer();
     gatherer->write(noiseData.fBaseFrequency);
     gatherer->write(noiseData.fStitchData);
     gatherer->write(static_cast<int>(noiseData.fType));
@@ -932,66 +899,54 @@
 } // anonymous namespace
 
 void PerlinNoiseShaderBlock::AddBlock(const KeyContext& keyContext,
-                                      PaintParamsKeyBuilder* builder,
-                                      PipelineDataGatherer* gatherer,
                                       const PerlinNoiseData& noiseData) {
-    add_perlin_noise_uniform_data(keyContext.dict(), noiseData, gatherer);
+    add_perlin_noise_uniform_data(keyContext, noiseData);
 
-    builder->addBlock(BuiltInCodeSnippetID::kPerlinNoiseShader);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPerlinNoiseShader);
 }
 
 //--------------------------------------------------------------------------------------------------
 
-void BlendComposeBlock::BeginBlock(const KeyContext& keyContext,
-                                  PaintParamsKeyBuilder* builder,
-                                  PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kBlendCompose)
+void BlendComposeBlock::BeginBlock(const KeyContext& keyContext) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kBlendCompose)
 
-    builder->beginBlock(BuiltInCodeSnippetID::kBlendCompose);
+    keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kBlendCompose);
 }
 
 //--------------------------------------------------------------------------------------------------
 
-void PorterDuffBlenderBlock::AddBlock(const KeyContext& keyContext,
-                                      PaintParamsKeyBuilder* builder,
-                                      PipelineDataGatherer* gatherer,
-                                      SkSpan<const float> coeffs) {
-    BEGIN_WRITE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kPorterDuffBlender)
+void PorterDuffBlenderBlock::AddBlock(const KeyContext& keyContext, SkSpan<const float> coeffs) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kPorterDuffBlender)
     SkASSERT(coeffs.size() == 4);
-    gatherer->writeHalf(SkV4{coeffs[0], coeffs[1], coeffs[2], coeffs[3]});
+    keyContext.pipelineDataGatherer()->writeHalf(SkV4{coeffs[0], coeffs[1], coeffs[2], coeffs[3]});
 
-    builder->addBlock(BuiltInCodeSnippetID::kPorterDuffBlender);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPorterDuffBlender);
 }
 
 //--------------------------------------------------------------------------------------------------
 
-void HSLCBlenderBlock::AddBlock(const KeyContext& keyContext,
-                                 PaintParamsKeyBuilder* builder,
-                                 PipelineDataGatherer* gatherer,
-                                 SkSpan<const float> coeffs) {
-    BEGIN_WRITE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kHSLCBlender)
+void HSLCBlenderBlock::AddBlock(const KeyContext& keyContext, SkSpan<const float> coeffs) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kHSLCBlender)
     SkASSERT(coeffs.size() == 2);
-    gatherer->writeHalf(SkV2{coeffs[0], coeffs[1]});
+    keyContext.pipelineDataGatherer()->writeHalf(SkV2{coeffs[0], coeffs[1]});
 
-    builder->addBlock(BuiltInCodeSnippetID::kHSLCBlender);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kHSLCBlender);
 }
 
 //--------------------------------------------------------------------------------------------------
 
-void ComposeBlock::BeginBlock(const KeyContext& keyContext,
-                              PaintParamsKeyBuilder* builder,
-                              PipelineDataGatherer* gatherer) {
-    builder->beginBlock(BuiltInCodeSnippetID::kCompose);
+void ComposeBlock::BeginBlock(const KeyContext& keyContext) {
+    keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kCompose);
 }
 
 //--------------------------------------------------------------------------------------------------
 
 namespace {
 
-void add_matrix_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
-                                         const MatrixColorFilterBlock::MatrixColorFilterData& data,
-                                         PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kMatrixColorFilter)
+void add_matrix_colorfilter_uniform_data(const KeyContext& keyContext,
+                                         const MatrixColorFilterBlock::MatrixColorFilterData& data) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kMatrixColorFilter)
+    auto gatherer = keyContext.pipelineDataGatherer();
     gatherer->writeHalf(data.fMatrix);
     gatherer->writeHalf(data.fTranslate);
     if (data.fClamp) {
@@ -1006,10 +961,10 @@
 }
 
 void add_hsl_matrix_colorfilter_uniform_data(
-        const ShaderCodeDictionary* dict,
-        const MatrixColorFilterBlock::MatrixColorFilterData& data,
-        PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kHSLMatrixColorFilter)
+        const KeyContext& keyContext,
+        const MatrixColorFilterBlock::MatrixColorFilterData& data) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kHSLMatrixColorFilter)
+    auto gatherer = keyContext.pipelineDataGatherer();
     gatherer->writeHalf(data.fMatrix);
     gatherer->writeHalf(data.fTranslate);
 }
@@ -1017,17 +972,15 @@
 } // anonymous namespace
 
 void MatrixColorFilterBlock::AddBlock(const KeyContext& keyContext,
-                                      PaintParamsKeyBuilder* builder,
-                                      PipelineDataGatherer* gatherer,
                                       const MatrixColorFilterData& matrixCFData) {
     if (matrixCFData.fInHSLA) {
-        add_hsl_matrix_colorfilter_uniform_data(keyContext.dict(), matrixCFData, gatherer);
+        add_hsl_matrix_colorfilter_uniform_data(keyContext, matrixCFData);
 
-        builder->addBlock(BuiltInCodeSnippetID::kHSLMatrixColorFilter);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kHSLMatrixColorFilter);
     } else {
-        add_matrix_colorfilter_uniform_data(keyContext.dict(), matrixCFData, gatherer);
+        add_matrix_colorfilter_uniform_data(keyContext, matrixCFData);
 
-        builder->addBlock(BuiltInCodeSnippetID::kMatrixColorFilter);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kMatrixColorFilter);
     }
 }
 
@@ -1035,25 +988,22 @@
 
 namespace {
 
-void add_table_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
-                                        const TableColorFilterBlock::TableColorFilterData& data,
-                                        PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kTableColorFilter)
+void add_table_colorfilter_uniform_data(const KeyContext& keyContext,
+                                        const TableColorFilterBlock::TableColorFilterData& data) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kTableColorFilter)
 
-    gatherer->add(data.fTextureProxy, {SkFilterMode::kNearest, SkTileMode::kClamp});
+    keyContext.pipelineDataGatherer()->add(data.fTextureProxy, {SkFilterMode::kNearest, SkTileMode::kClamp});
 }
 
 } // anonymous namespace
 
 void TableColorFilterBlock::AddBlock(const KeyContext& keyContext,
-                                     PaintParamsKeyBuilder* builder,
-                                     PipelineDataGatherer* gatherer,
                                      const TableColorFilterData& data) {
     SkASSERT(data.fTextureProxy || !keyContext.recorder());
 
-    add_table_colorfilter_uniform_data(keyContext.dict(), data, gatherer);
+    add_table_colorfilter_uniform_data(keyContext, data);
 
-    builder->addBlock(BuiltInCodeSnippetID::kTableColorFilter);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kTableColorFilter);
 }
 
 //--------------------------------------------------------------------------------------------------
@@ -1061,16 +1011,15 @@
 
 // There are three variations of color space transforms with increasing complexity, but they are
 // built on the same techniques for managing variations w/o adding branches in the shader.
-void add_color_space_uniforms(BuiltInCodeSnippetID id,
-                              const ShaderCodeDictionary* dict,
+void add_color_space_uniforms(const KeyContext& keyContext,
+                              BuiltInCodeSnippetID id,
                               const SkColorSpaceXformSteps& steps,
-                              ReadSwizzle readSwizzle,
-                              PipelineDataGatherer* gatherer) {
+                              ReadSwizzle readSwizzle) {
     SkASSERT(id == BuiltInCodeSnippetID::kColorSpaceXformPremul ||     // premul/unpremul/opaque
              id == BuiltInCodeSnippetID::kColorSpaceXformSRGB ||       // + sRGB [d]encode/gamut
              id == BuiltInCodeSnippetID::kColorSpaceXformColorFilter); // + everything else
 
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, id)
+    BEGIN_WRITE_UNIFORMS(keyContext, id)
 
     // To encode whether to do premul/unpremul or make the output opaque, we use
     // srcDEF_args.w and dstDEF_args.w:
@@ -1102,7 +1051,7 @@
         SkASSERT(!(steps.fFlags.unpremul && steps.fFlags.premul));
         // And given these assertions, the 6 cases encoded in srcW and dstW are reduced to:
         //    identity, do unpremul, do premul, and make opaque (alpha swizzle 1)
-        gatherer->writeHalf(SkV2{srcW, dstW});
+        keyContext.pipelineDataGatherer()->writeHalf(SkV2{srcW, dstW});
         return;
     }
 
@@ -1131,7 +1080,7 @@
                             m[1], m[4], m[7],
                             m[2], m[5], m[8]);
     }
-    gatherer->writeHalf(gamutTransform);
+    keyContext.pipelineDataGatherer()->writeHalf(gamutTransform);
 
     // To encode which transfer function to apply, we use the src and dst gamma values:
     // - identity: 0
@@ -1147,17 +1096,19 @@
                            type == skcms_TFType_PQish ? -2.f :
                            type == skcms_TFType_HLGish ? -1.f :
                                                          0.f;
-        gatherer->write(SkV4{srcG, steps.fSrcTF.a, steps.fSrcTF.b, steps.fSrcTF.c});
-        gatherer->write(SkV4{steps.fSrcTF.d, steps.fSrcTF.e, steps.fSrcTF.f, srcW});
+        keyContext.pipelineDataGatherer()->write(SkV4{srcG, steps.fSrcTF.a,
+                                                      steps.fSrcTF.b, steps.fSrcTF.c});
+        keyContext.pipelineDataGatherer()->write(SkV4{steps.fSrcTF.d, steps.fSrcTF.e,
+                                                      steps.fSrcTF.f, srcW});
     } else if (treatLinearAsSRGB) {
         // Branchless identity function with g=1 (sRGB-ish)
         static constexpr skcms_TransferFunction kI = SkNamedTransferFn::kLinear;
-        gatherer->write(SkV4{kI.g, kI.a, kI.b, kI.c});
-        gatherer->write(SkV4{kI.d, kI.e, kI.f, srcW});
+        keyContext.pipelineDataGatherer()->write(SkV4{kI.g, kI.a, kI.b, kI.c});
+        keyContext.pipelineDataGatherer()->write(SkV4{kI.d, kI.e, kI.f, srcW});
     } else {
         // Branched identity that actually skips all operations
-        gatherer->write(SkV4{0.f, 0.f, 0.f, 0.f});
-        gatherer->write(SkV4{0.f, 0.f, 0.f, srcW});
+        keyContext.pipelineDataGatherer()->write(SkV4{0.f, 0.f, 0.f, 0.f});
+        keyContext.pipelineDataGatherer()->write(SkV4{0.f, 0.f, 0.f, srcW});
     }
 
     if (steps.fFlags.encode) {
@@ -1166,15 +1117,17 @@
                            type == skcms_TFType_PQish ? -2.f :
                            type == skcms_TFType_HLGinvish ? -1.f :
                                                             0.f;
-        gatherer->write(SkV4{dstG, steps.fDstTFInv.a, steps.fDstTFInv.b, steps.fDstTFInv.c});
-        gatherer->write(SkV4{steps.fDstTFInv.d, steps.fDstTFInv.e, steps.fDstTFInv.f, dstW});
+        keyContext.pipelineDataGatherer()->write(SkV4{dstG, steps.fDstTFInv.a,
+                                                      steps.fDstTFInv.b, steps.fDstTFInv.c});
+        keyContext.pipelineDataGatherer()->write(SkV4{steps.fDstTFInv.d, steps.fDstTFInv.e,
+                                                      steps.fDstTFInv.f, dstW});
     } else if (treatLinearAsSRGB) {
         static constexpr skcms_TransferFunction kI = SkNamedTransferFn::kLinear;
-        gatherer->write(SkV4{kI.g, kI.a, kI.b, kI.c});
-        gatherer->write(SkV4{kI.d, kI.e, kI.f, dstW});
+        keyContext.pipelineDataGatherer()->write(SkV4{kI.g, kI.a, kI.b, kI.c});
+        keyContext.pipelineDataGatherer()->write(SkV4{kI.d, kI.e, kI.f, dstW});
     } else {
-        gatherer->write(SkV4{0.f, 0.f, 0.f, 0.f});
-        gatherer->write(SkV4{0.f, 0.f, 0.f, dstW});
+        keyContext.pipelineDataGatherer()->write(SkV4{0.f, 0.f, 0.f, 0.f});
+        keyContext.pipelineDataGatherer()->write(SkV4{0.f, 0.f, 0.f, dstW});
     }
 
     const bool hasOOTFUniforms = id == BuiltInCodeSnippetID::kColorSpaceXformColorFilter;
@@ -1202,8 +1155,8 @@
           }
         }
 
-        gatherer->write(src_ootf);
-        gatherer->write(dst_ootf);
+        keyContext.pipelineDataGatherer()->write(src_ootf);
+        keyContext.pipelineDataGatherer()->write(dst_ootf);
     } else {
       SkASSERT(!steps.fFlags.src_ootf);
       SkASSERT(!steps.fFlags.dst_ootf);
@@ -1219,8 +1172,6 @@
         : fSteps(src, srcAT, dst, dstAT) {}
 
 void ColorSpaceTransformBlock::AddBlock(const KeyContext& keyContext,
-                                        PaintParamsKeyBuilder* builder,
-                                        PipelineDataGatherer* gatherer,
                                         const ColorSpaceTransformData& data) {
     const bool xformNeedsGamutOrXferFn = data.fSteps.fFlags.linearize ||
                                          data.fSteps.fFlags.encode    ||
@@ -1237,13 +1188,13 @@
         if (SkToBool(keyContext.flags() & KeyGenFlags::kEnableIdentityColorSpaceXform) &&
             data.fReadSwizzle == ReadSwizzle::kRGBA &&
             !data.fSteps.fFlags.premul && !data.fSteps.fFlags.unpremul) {
-            builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+            keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
             return;
         }
 
-        add_color_space_uniforms(BuiltInCodeSnippetID::kColorSpaceXformPremul,
-                                 keyContext.dict(), data.fSteps, data.fReadSwizzle, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kColorSpaceXformPremul);
+        add_color_space_uniforms(keyContext, BuiltInCodeSnippetID::kColorSpaceXformPremul,
+                                 data.fSteps, data.fReadSwizzle);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kColorSpaceXformPremul);
         return;
     }
 
@@ -1253,58 +1204,52 @@
     // most general colorspace option.
     if ((!data.fSteps.fFlags.linearize || skcms_TransferFunction_isSRGBish(&data.fSteps.fSrcTF)) &&
         (!data.fSteps.fFlags.encode || skcms_TransferFunction_isSRGBish(&data.fSteps.fDstTFInv))) {
-        add_color_space_uniforms(BuiltInCodeSnippetID::kColorSpaceXformSRGB,
-                                 keyContext.dict(), data.fSteps, data.fReadSwizzle, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kColorSpaceXformSRGB);
+        add_color_space_uniforms(keyContext, BuiltInCodeSnippetID::kColorSpaceXformSRGB,
+                                 data.fSteps, data.fReadSwizzle);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kColorSpaceXformSRGB);
         return;
     }
 
     // Use the most general color space transform shader if no specializations can be used.
-    add_color_space_uniforms(BuiltInCodeSnippetID::kColorSpaceXformColorFilter,
-                             keyContext.dict(), data.fSteps, data.fReadSwizzle, gatherer);
-    builder->addBlock(BuiltInCodeSnippetID::kColorSpaceXformColorFilter);
+    add_color_space_uniforms(keyContext, BuiltInCodeSnippetID::kColorSpaceXformColorFilter,
+                             data.fSteps, data.fReadSwizzle);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kColorSpaceXformColorFilter);
 }
 
 //--------------------------------------------------------------------------------------------------
 namespace {
 
-void add_analytic_clip_data(
-        const ShaderCodeDictionary* dict,
-        const NonMSAAClipBlock::NonMSAAClipData& data,
-        PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kAnalyticClip)
-    gatherer->write(data.fRect);
-    gatherer->write(data.fRadiusPlusHalf);
-    gatherer->writeHalf(data.fEdgeSelect);
+void add_analytic_clip_data(const KeyContext& keyContext,
+                            const NonMSAAClipBlock::NonMSAAClipData& data) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kAnalyticClip)
+    keyContext.pipelineDataGatherer()->write(data.fRect);
+    keyContext.pipelineDataGatherer()->write(data.fRadiusPlusHalf);
+    keyContext.pipelineDataGatherer()->writeHalf(data.fEdgeSelect);
 }
 
-void add_analytic_and_atlas_clip_data(
-        const ShaderCodeDictionary* dict,
-        const NonMSAAClipBlock::NonMSAAClipData& data,
-        PipelineDataGatherer* gatherer) {
-    BEGIN_WRITE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kAnalyticAndAtlasClip)
-    gatherer->write(data.fRect);
-    gatherer->write(data.fRadiusPlusHalf);
-    gatherer->writeHalf(data.fEdgeSelect);
-    gatherer->write(data.fTexCoordOffset);
-    gatherer->write(data.fMaskBounds);
+void add_analytic_and_atlas_clip_data(const KeyContext& keyContext,
+                                      const NonMSAAClipBlock::NonMSAAClipData& data) {
+    BEGIN_WRITE_UNIFORMS(keyContext, BuiltInCodeSnippetID::kAnalyticAndAtlasClip)
+    keyContext.pipelineDataGatherer()->write(data.fRect);
+    keyContext.pipelineDataGatherer()->write(data.fRadiusPlusHalf);
+    keyContext.pipelineDataGatherer()->writeHalf(data.fEdgeSelect);
+    keyContext.pipelineDataGatherer()->write(data.fTexCoordOffset);
+    keyContext.pipelineDataGatherer()->write(data.fMaskBounds);
     if (data.fAtlasTexture) {
-        gatherer->write(SkSize::Make(1.f/data.fAtlasTexture->dimensions().width(),
-                                     1.f/data.fAtlasTexture->dimensions().height()));
+        keyContext.pipelineDataGatherer()->write(
+                SkSize::Make(1.f/data.fAtlasTexture->dimensions().width(),
+                             1.f/data.fAtlasTexture->dimensions().height()));
     } else {
-        gatherer->write(SkSize::Make(0, 0));
+        keyContext.pipelineDataGatherer()->write(SkSize::Make(0, 0));
     }
 }
 
 }  // anonymous namespace
 
-void NonMSAAClipBlock::AddBlock(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
-                                const NonMSAAClipData& data) {
+void NonMSAAClipBlock::AddBlock(const KeyContext& keyContext, const NonMSAAClipData& data) {
     if (data.fAtlasTexture) {
-        add_analytic_and_atlas_clip_data(keyContext.dict(), data, gatherer);
-        builder->beginBlock(BuiltInCodeSnippetID::kAnalyticAndAtlasClip);
+        add_analytic_and_atlas_clip_data(keyContext, data);
+        keyContext.paintParamsKeyBuilder()->beginBlock(BuiltInCodeSnippetID::kAnalyticAndAtlasClip);
 
         const Caps* caps = keyContext.caps();
         ImmutableSamplerInfo info =
@@ -1312,63 +1257,56 @@
         SamplerDesc samplerDesc {SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone),
                                  {SkTileMode::kClamp, SkTileMode::kClamp},
                                  info};
-        gatherer->add(data.fAtlasTexture, samplerDesc);
+        keyContext.pipelineDataGatherer()->add(data.fAtlasTexture, samplerDesc);
 
-        builder->endBlock();
+        keyContext.paintParamsKeyBuilder()->endBlock();
     } else {
-        add_analytic_clip_data(keyContext.dict(), data, gatherer);
-        builder->addBlock(BuiltInCodeSnippetID::kAnalyticClip);
+        add_analytic_clip_data(keyContext, data);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kAnalyticClip);
     }
 }
 
 //--------------------------------------------------------------------------------------------------
 
-void AddPrimitiveColor(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       bool skipColorXform) {
+void AddPrimitiveColor(const KeyContext& keyContext, bool skipColorXform) {
     /**
      * When skipColorXform is true, we assume the primitive color is already in the dst color space.
     */
     if (skipColorXform) {
-         builder->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
+         keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
          return;
     }
 
     /**
      * If skipColorXform is false (most cases), the primitive color is assumed to be in sRGB.
     */
-    ColorSpaceTransformBlock::ColorSpaceTransformData toDst(
-            sk_srgb_singleton(),
-            kPremul_SkAlphaType,
-            keyContext.dstColorInfo().colorSpace(),
-            keyContext.dstColorInfo().alphaType());
+    ColorSpaceTransformBlock::ColorSpaceTransformData toDst(sk_srgb_singleton(),
+                                                            kPremul_SkAlphaType,
+                                                            keyContext.dstColorInfo().colorSpace(),
+                                                            keyContext.dstColorInfo().alphaType());
 
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                builder->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
+                keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
             },
             /* addOuterToKey= */ [&]() -> void {
-                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, toDst);
+                ColorSpaceTransformBlock::AddBlock(keyContext, toDst);
             });
 }
 
 //--------------------------------------------------------------------------------------------------
 
-void AddBlendModeColorFilter(const KeyContext& keyContext,
-                             PaintParamsKeyBuilder* builder,
-                             PipelineDataGatherer* gatherer,
-                             SkBlendMode bm,
+void AddBlendModeColorFilter(const KeyContext& keyContext, SkBlendMode bm,
                              const SkPMColor4f& srcColor) {
-    Blend(keyContext, builder, gatherer,
+    Blend(keyContext,
           /* addBlendToKey= */ [&] () -> void {
-              AddBlendMode(keyContext, builder, gatherer, bm);
+              AddBlendMode(keyContext, bm);
           },
           /* addSrcToKey= */ [&]() -> void {
-              SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, srcColor);
+              SolidColorShaderBlock::AddBlock(keyContext, srcColor);
           },
           /* addDstToKey= */ [&]() -> void {
-              builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+              keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
           });
 }
 
@@ -1418,10 +1356,7 @@
 
 // TODO(robertphillips): when BeginBlock fails we should mark the 'builder' as having failed
 // and explicitly handle the failure in ShaderCodeDictionary::findOrCreate.
-bool RuntimeEffectBlock::BeginBlock(const KeyContext& keyContext,
-                                    PaintParamsKeyBuilder* builder,
-                                    PipelineDataGatherer* gatherer,
-                                    const ShaderData& shaderData) {
+bool RuntimeEffectBlock::BeginBlock(const KeyContext& keyContext, const ShaderData& shaderData) {
     ShaderCodeDictionary* dict = keyContext.dict();
     int codeSnippetID = dict->findOrCreateRuntimeEffectSnippet(shaderData.fEffect.get());
 
@@ -1442,36 +1377,29 @@
                                    shaderData.fEffect.get(),
                                    entry->fUniforms,
                                    shaderData.fUniforms.get(),
-                                   gatherer);
+                                   keyContext.pipelineDataGatherer());
 
-    builder->beginBlock(codeSnippetID);
+    keyContext.paintParamsKeyBuilder()->beginBlock(codeSnippetID);
     return true;
 }
 
 // TODO(robertphillips): fuse this with the similar code in add_children_to_key and
 // PrecompileRTEffect::addToKey.
-void RuntimeEffectBlock::AddNoOpEffect(const KeyContext& keyContext,
-                                       PaintParamsKeyBuilder* builder,
-                                       PipelineDataGatherer* gatherer,
-                                       SkRuntimeEffect* effect) {
+void RuntimeEffectBlock::AddNoOpEffect(const KeyContext& keyContext, SkRuntimeEffect* effect) {
     if (effect->allowShader()) {
         // A missing shader returns transparent black
-        SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer,
-                                        SK_PMColor4fTRANSPARENT);
+        SolidColorShaderBlock::AddBlock(keyContext, SK_PMColor4fTRANSPARENT);
     } else if (effect->allowColorFilter()) {
         // A "passthrough" color filter returns the input color as-is.
-        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
     } else {
         SkASSERT(effect->allowBlender());
         // A "passthrough" blender performs `blend_src_over(src, dest)`.
-        AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kSrcOver);
+        AddFixedBlendMode(keyContext, SkBlendMode::kSrcOver);
     }
 }
 
-void RuntimeEffectBlock::HandleIntrinsics(const KeyContext& keyContext,
-                                          PaintParamsKeyBuilder* builder,
-                                          PipelineDataGatherer* gatherer,
-                                          const SkRuntimeEffect* effect) {
+void RuntimeEffectBlock::HandleIntrinsics(const KeyContext& keyContext, const SkRuntimeEffect* effect) {
     // Runtime effects that reference color transform intrinsics have two extra children that
     // are bound to the colorspace xform snippet with values to go to and from the linear srgb
     // to the current working/dst color space.
@@ -1496,8 +1424,8 @@
                                                                       dstCS,
                                                                       kUnpremul_SkAlphaType);
 
-        ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, dstToLinear);
-        ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, linearToDst);
+        ColorSpaceTransformBlock::AddBlock(keyContext, dstToLinear);
+        ColorSpaceTransformBlock::AddBlock(keyContext, linearToDst);
     }
 }
 
@@ -1505,19 +1433,13 @@
 
 namespace {
 
-void add_to_key(const KeyContext& keyContext,
-                PaintParamsKeyBuilder* builder,
-                PipelineDataGatherer* gatherer,
-                const SkBlendModeBlender* blender) {
+void add_to_key(const KeyContext& keyContext, const SkBlendModeBlender* blender) {
     SkASSERT(blender);
-
-    AddBlendMode(keyContext, builder, gatherer, blender->mode());
+    AddBlendMode(keyContext, blender->mode());
 }
 
 // Be sure to keep this function in sync w/ the code in PrecompileRTEffect::addToKey
 void add_children_to_key(const KeyContext& keyContext,
-                         PaintParamsKeyBuilder* builder,
-                         PipelineDataGatherer* gatherer,
                          SkSpan<const SkRuntimeEffect::ChildPtr> children,
                          const SkRuntimeEffect* effect) {
     SkSpan<const SkRuntimeEffect::Child> childInfo = effect->children();
@@ -1531,40 +1453,37 @@
 
         std::optional<ChildType> type = child.type();
         if (type == ChildType::kShader) {
-            AddToKey(childContext, builder, gatherer, child.shader());
+            AddToKey(childContext, child.shader());
         } else if (type == ChildType::kColorFilter) {
-            AddToKey(childContext, builder, gatherer, child.colorFilter());
+            AddToKey(childContext, child.colorFilter());
         } else if (type == ChildType::kBlender) {
-            AddToKey(childContext, builder, gatherer, child.blender());
+            AddToKey(childContext, child.blender());
         } else {
             // We don't have a child effect. Substitute in a no-op effect.
             switch (childInfo[index].type) {
                 case ChildType::kShader:
                     // A missing shader returns transparent black
-                    SolidColorShaderBlock::AddBlock(childContext, builder, gatherer,
+                    SolidColorShaderBlock::AddBlock(childContext,
                                                     SK_PMColor4fTRANSPARENT);
                     break;
 
                 case ChildType::kColorFilter:
                     // A "passthrough" color filter returns the input color as-is.
-                    builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+                    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
                     break;
 
                 case ChildType::kBlender:
                     // A "passthrough" blender performs `blend_src_over(src, dest)`.
-                    AddFixedBlendMode(childContext, builder, gatherer, SkBlendMode::kSrcOver);
+                    AddFixedBlendMode(childContext, SkBlendMode::kSrcOver);
                     break;
             }
         }
     }
 
-    RuntimeEffectBlock::HandleIntrinsics(keyContext, builder, gatherer, effect);
+    RuntimeEffectBlock::HandleIntrinsics(keyContext, effect);
 }
 
-void add_to_key(const KeyContext& keyContext,
-                PaintParamsKeyBuilder* builder,
-                PipelineDataGatherer* gatherer,
-                const SkRuntimeBlender* blender) {
+void add_to_key(const KeyContext& keyContext, const SkRuntimeBlender* blender) {
     SkASSERT(blender);
     sk_sp<SkRuntimeEffect> effect = blender->effect();
     SkASSERT(effect);
@@ -1574,16 +1493,14 @@
             keyContext.dstColorInfo().colorSpace());
     SkASSERT(uniforms);
 
-    if (!RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
-                                        { effect, std::move(uniforms) })) {
-        RuntimeEffectBlock::AddNoOpEffect(keyContext, builder, gatherer, effect.get());
+    if (!RuntimeEffectBlock::BeginBlock(keyContext, { effect, std::move(uniforms) })) {
+        RuntimeEffectBlock::AddNoOpEffect(keyContext, effect.get());
         return;
     }
 
-    add_children_to_key(keyContext, builder, gatherer,
-                        blender->children(), effect.get());
+    add_children_to_key(keyContext, blender->children(), effect.get());
 
-    builder->endBlock();
+    keyContext.paintParamsKeyBuilder()->endBlock();
 }
 
 void notify_in_use(Recorder* recorder,
@@ -1608,24 +1525,19 @@
 
 } // anonymous namespace
 
-void AddToKey(const KeyContext& keyContext,
-              PaintParamsKeyBuilder* builder,
-              PipelineDataGatherer* gatherer,
-              const SkBlender* blender) {
+void AddToKey(const KeyContext& keyContext, const SkBlender* blender) {
     if (!blender) {
         // Calling code assumes a block will be appended. Add a fixed block to preserve shader
         // and PaintParamsKey structure in release builds but assert since this should either not
         // happen or should be changing high-level logic within PaintParams::toKey().
         SkASSERT(false);
-        AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kSrcOver);
+        AddFixedBlendMode(keyContext, SkBlendMode::kSrcOver);
         return;
     }
     switch (as_BB(blender)->type()) {
 #define M(type)                                                     \
     case SkBlenderBase::BlenderType::k##type:                       \
         add_to_key(keyContext,                                      \
-                   builder,                                         \
-                   gatherer,                                        \
                    static_cast<const Sk##type##Blender*>(blender)); \
         return;
         SK_ALL_BLENDERS(M)
@@ -1651,69 +1563,51 @@
     SkColorSpaceXformSteps(src, kUnpremul_SkAlphaType, dst, kPremul_SkAlphaType).apply(color.vec());
     return color;
 }
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkBlendModeColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkBlendModeColorFilter* filter) {
     SkASSERT(filter);
 
     SkPMColor4f color = map_color(filter->color(), sk_srgb_singleton(),
                                   keyContext.dstColorInfo().colorSpace());
 
-    AddBlendModeColorFilter(keyContext, builder, gatherer, filter->mode(), color);
+    AddBlendModeColorFilter(keyContext, filter->mode(), color);
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkColorSpaceXformColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkColorSpaceXformColorFilter* filter) {
     SkASSERT(filter);
 
     constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
     ColorSpaceTransformBlock::ColorSpaceTransformData csData(filter->src().get(), kAlphaType,
                                                              filter->dst().get(), kAlphaType);
-    ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
+    ColorSpaceTransformBlock::AddBlock(keyContext, csData);
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* keyBuilder,
-                       PipelineDataGatherer* gatherer,
-                       const SkComposeColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkComposeColorFilter* filter) {
     SkASSERT(filter);
 
-    Compose(keyContext, keyBuilder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                AddToKey(keyContext, keyBuilder, gatherer, filter->inner().get());
+                AddToKey(keyContext, filter->inner().get());
             },
             /* addOuterToKey= */ [&]() -> void {
-                AddToKey(keyContext, keyBuilder, gatherer, filter->outer().get());
+                AddToKey(keyContext, filter->outer().get());
             });
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkGaussianColorFilter*) {
-    builder->addBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
+static void add_to_key(const KeyContext& keyContext, const SkGaussianColorFilter*) {
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkMatrixColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkMatrixColorFilter* filter) {
     SkASSERT(filter);
 
     bool inHSLA = filter->domain() == SkMatrixColorFilter::Domain::kHSLA;
     bool clamp = filter->clamp() == SkMatrixColorFilter::Clamp::kYes;
     MatrixColorFilterBlock::MatrixColorFilterData matrixCFData(filter->matrix(), inHSLA, clamp);
 
-    MatrixColorFilterBlock::AddBlock(keyContext, builder, gatherer, matrixCFData);
+    MatrixColorFilterBlock::AddBlock(keyContext, matrixCFData);
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkRuntimeColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkRuntimeColorFilter* filter) {
     SkASSERT(filter);
 
     sk_sp<SkRuntimeEffect> effect = filter->effect();
@@ -1721,22 +1615,17 @@
             effect->uniforms(), filter->uniforms(), keyContext.dstColorInfo().colorSpace());
     SkASSERT(uniforms);
 
-    if (!RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
-                                        { effect, std::move(uniforms) })) {
-        RuntimeEffectBlock::AddNoOpEffect(keyContext, builder, gatherer, effect.get());
+    if (!RuntimeEffectBlock::BeginBlock(keyContext, { effect, std::move(uniforms) })) {
+        RuntimeEffectBlock::AddNoOpEffect(keyContext, effect.get());
         return;
     }
 
-    add_children_to_key(keyContext, builder, gatherer,
-                        filter->children(), effect.get());
+    add_children_to_key(keyContext, filter->children(), effect.get());
 
-    builder->endBlock();
+    keyContext.paintParamsKeyBuilder()->endBlock();
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkTableColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkTableColorFilter* filter) {
     SkASSERT(filter);
 
     sk_sp<TextureProxy> proxy = RecorderPriv::CreateCachedProxy(keyContext.recorder(),
@@ -1746,19 +1635,16 @@
         SKGPU_LOG_W("Couldn't create TableColorFilter's table");
 
         // Return the input color as-is.
-        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
         return;
     }
 
     TableColorFilterBlock::TableColorFilterData data(std::move(proxy));
 
-    TableColorFilterBlock::AddBlock(keyContext, builder, gatherer, data);
+    TableColorFilterBlock::AddBlock(keyContext, data);
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkWorkingFormatColorFilter* filter) {
+static void add_to_key(const KeyContext& keyContext, const SkWorkingFormatColorFilter* filter) {
     SkASSERT(filter);
 
     const SkColorInfo& dstInfo = keyContext.dstColorInfo();
@@ -1775,52 +1661,46 @@
 
     // Use two nested compose blocks to chain (dst->working), child, and (working->dst) together
     // while appearing as one block to the parent node.
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
                 // Inner compose
-                Compose(keyContext, builder, gatherer,
+                Compose(keyContext,
                         /* addInnerToKey= */ [&]() -> void {
                             // Innermost (inner of inner compose)
                             ColorSpaceTransformBlock::ColorSpaceTransformData data1(
                                     dstCS.get(), dstAT, workingCS.get(), workingAT);
-                            ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
-                                                               data1);
+                            ColorSpaceTransformBlock::AddBlock(keyContext, data1);
                         },
                         /* addOuterToKey= */ [&]() -> void {
                             // Middle (outer of inner compose)
-                            AddToKey(workingContext, builder, gatherer, filter->child().get());
+                            AddToKey(workingContext, filter->child().get());
                         });
             },
             /* addOuterToKey= */ [&]() -> void {
                 // Outermost (outer of outer compose)
                 ColorSpaceTransformBlock::ColorSpaceTransformData data2(
                         workingCS.get(), workingAT, dstCS.get(), dstAT);
-                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data2);
+                ColorSpaceTransformBlock::AddBlock(keyContext, data2);
             });
 }
 
-void AddToKey(const KeyContext& keyContext,
-              PaintParamsKeyBuilder* builder,
-              PipelineDataGatherer* gatherer,
-              const SkColorFilter* filter) {
+void AddToKey(const KeyContext& keyContext, const SkColorFilter* filter) {
     if (!filter) {
         // Calling code assumes a block will be appended. Add a fixed block to preserve shader
         // and PaintParamsKey structure in release builds but assert since this should either not
         // happen or should be changing high-level logic within PaintParams::toKey().
         SkASSERT(false);
-        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
         return;
     }
     switch (as_CFB(filter)->type()) {
     case SkColorFilterBase::Type::kNoop:
         // Return the input color as-is.
-        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
         return;
 #define M(type)                                                        \
     case SkColorFilterBase::Type::k##type:                             \
         add_to_key(keyContext,                                         \
-                   builder,                                            \
-                   gatherer,                                           \
                    static_cast<const Sk##type##ColorFilter*>(filter)); \
         return;
         SK_ALL_COLOR_FILTERS(M)
@@ -1851,21 +1731,18 @@
 
 // ==================================================================
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkBlendShader* shader) {
+static void add_to_key(const KeyContext& keyContext, const SkBlendShader* shader) {
     SkASSERT(shader);
 
-    Blend(keyContext, builder, gatherer,
+    Blend(keyContext,
             /* addBlendToKey= */ [&] () -> void {
-                AddBlendMode(keyContext, builder, gatherer, shader->mode());
+                AddBlendMode(keyContext, shader->mode());
             },
             /* addSrcToKey= */ [&]() -> void {
-                AddToKey(keyContext, builder, gatherer, shader->src().get());
+                AddToKey(keyContext, shader->src().get());
             },
             /* addDstToKey= */ [&]() -> void {
-                AddToKey(keyContext, builder, gatherer, shader->dst().get());
+                AddToKey(keyContext, shader->dst().get());
             });
 }
 static void notify_in_use(Recorder* recorder,
@@ -1885,10 +1762,7 @@
     return inverseMatrix;
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkCTMShader* shader) {
+static void add_to_key(const KeyContext& keyContext, const SkCTMShader* shader) {
     // CTM shaders are always given device coordinates, so we don't have to modify the CTM itself
     // with keyContext's local transform.
 
@@ -1897,43 +1771,37 @@
 
     KeyContextWithLocalMatrix newContext(keyContext, shader->ctm());
 
-    LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
+    LocalMatrixShaderBlock::BeginBlock(newContext, lmShaderData);
 
-    AddToKey(newContext, builder, gatherer, shader->proxyShader().get());
+    AddToKey(newContext, shader->proxyShader().get());
 
-    builder->endBlock();
+    keyContext.paintParamsKeyBuilder()->endBlock();
 }
 static void notify_in_use(Recorder* recorder, DrawContext* drawContext, const SkCTMShader* shader) {
     NotifyImagesInUse(recorder, drawContext, shader->proxyShader().get());
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkColorShader* shader) {
+static void add_to_key(const KeyContext& keyContext, const SkColorShader* shader) {
     SkASSERT(shader);
 
     SkPMColor4f color = map_color(shader->color(), sk_srgb_singleton(),
                                   keyContext.dstColorInfo().colorSpace());
 
-    SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, color);
+    SolidColorShaderBlock::AddBlock(keyContext, color);
 }
 static void notify_in_use(Recorder*, DrawContext*, const SkColorShader*) {
     // No-op
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkColorFilterShader* shader) {
+static void add_to_key(const KeyContext& keyContext, const SkColorFilterShader* shader) {
     SkASSERT(shader);
 
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                AddToKey(keyContext, builder, gatherer, shader->shader().get());
+                AddToKey(keyContext, shader->shader().get());
             },
             /* addOuterToKey= */ [&]() -> void {
-                AddToKey(keyContext, builder, gatherer, shader->filter().get());
+                AddToKey(keyContext, shader->filter().get());
             });
 }
 static void notify_in_use(Recorder* recorder,
@@ -1943,18 +1811,15 @@
     NotifyImagesInUse(recorder, drawContext, shader->filter().get());
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkCoordClampShader* shader) {
+static void add_to_key(const KeyContext& keyContext, const SkCoordClampShader* shader) {
     SkASSERT(shader);
 
     CoordClampShaderBlock::CoordClampData data(shader->subset());
 
     KeyContextWithCoordClamp childContext(keyContext);
-    CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
-    AddToKey(childContext, builder, gatherer, shader->shader().get());
-    builder->endBlock();
+    CoordClampShaderBlock::BeginBlock(keyContext, data);
+    AddToKey(childContext, shader->shader().get());
+    keyContext.paintParamsKeyBuilder()->endBlock();
 }
 static void notify_in_use(Recorder* recorder,
                           DrawContext* drawContext,
@@ -1962,19 +1827,14 @@
     NotifyImagesInUse(recorder, drawContext, shader->shader().get());
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkEmptyShader*) {
-    builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+static void add_to_key(const KeyContext& keyContext, const SkEmptyShader*) {
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
 }
 static void notify_in_use(Recorder*, DrawContext*, const SkEmptyShader*) {
     // No-op
 }
 
 static void add_yuv_image_to_key(const KeyContext& keyContext,
-                                 PaintParamsKeyBuilder* builder,
-                                 PipelineDataGatherer* gatherer,
                                  const SkImageShader* origShader,
                                  sk_sp<const SkImage> imageToDraw,
                                  SkSamplingOptions sampling) {
@@ -2114,18 +1974,16 @@
     }
     ColorSpaceTransformBlock::ColorSpaceTransformData data(steps);
 
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
+                YUVImageShaderBlock::AddBlock(keyContext, imgData);
             },
             /* addOuterToKey= */ [&]() -> void {
-                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
+                ColorSpaceTransformBlock::AddBlock(keyContext, data);
             });
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkImageShader* shader) {
     SkASSERT(shader);
 
@@ -2134,7 +1992,7 @@
                                                           shader->sampling());
     if (!imageToDraw) {
         SKGPU_LOG_W("Couldn't convert ImageShader's image to a Graphite-backed image");
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
     if (!as_IB(shader->image())->isGraphiteBacked()) {
@@ -2156,11 +2014,9 @@
     }
     if (as_IB(imageToDraw)->isYUVA()) {
         return add_yuv_image_to_key(keyContext,
-                                      builder,
-                                      gatherer,
-                                      shader,
-                                      std::move(imageToDraw),
-                                      newSampling);
+                                    shader,
+                                    std::move(imageToDraw),
+                                    newSampling);
     }
 
     auto view = AsView(imageToDraw.get());
@@ -2211,34 +2067,34 @@
             // NOTE: Alpha is not affected by colorspace conversion to the dst, and the paint color
             // is already xformed to the dst, but the ColorSpaceTransformBlock is necessary to apply
             // any read swizzle, which is often necessary for alpha-only color types.
-            Blend(keyContext, builder, gatherer,
+            Blend(keyContext,
                   /* addBlendToKey= */ [&] () -> void {
-                      AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kDstIn);
+                      AddFixedBlendMode(keyContext, SkBlendMode::kDstIn);
                   },
                   /* addSrcToKey= */ [&] () -> void {
-                      Compose(keyContext, builder, gatherer,
+                      Compose(keyContext,
                               /* addInnerToKey= */ [&]() -> void {
-                                  ImageShaderBlock::AddBlock(keyContext, builder, gatherer,
+                                  ImageShaderBlock::AddBlock(keyContext,
                                                              imgData);
                               },
                               /* addOuterToKey= */ [&]() -> void {
-                                  ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
+                                  ColorSpaceTransformBlock::AddBlock(keyContext,
                                                                      colorXformData);
                               });
                   },
                   /* addDstToKey= */ [&]() -> void {
-                      RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
+                      RGBPaintColorBlock::AddBlock(keyContext);
                   });
             return;
         }
     }
 
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
+                ImageShaderBlock::AddBlock(keyContext, imgData);
             },
             /* addOuterToKey= */ [&]() -> void {
-                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, colorXformData);
+                ColorSpaceTransformBlock::AddBlock(keyContext, colorXformData);
             });
 }
 static void notify_in_use(Recorder* recorder,
@@ -2253,10 +2109,7 @@
     static_cast<Image_Base*>(image)->notifyInUse(recorder, drawContext);
 }
 
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkLocalMatrixShader* shader) {
+static void add_to_key(const KeyContext& keyContext, const SkLocalMatrixShader* shader) {
     SkASSERT(shader);
     auto wrappedShader = shader->wrappedShader().get();
 
@@ -2307,7 +2160,7 @@
                 conicalMatrix.postScale(scale, scale);
             } else {
                 auto mx = (SkConicalGradient::MapToUnitX(conicalShader->getStartCenter(),
-                                                             conicalShader->getEndCenter()));
+                                                         conicalShader->getEndCenter()));
                 SkASSERT(mx);
                 conicalMatrix = mx.value_or(SkMatrix::I());
             }
@@ -2322,11 +2175,11 @@
 
     KeyContextWithLocalMatrix newContext(keyContext, shader->localMatrix());
 
-    LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
+    LocalMatrixShaderBlock::BeginBlock(newContext, lmShaderData);
 
-    AddToKey(newContext, builder, gatherer, wrappedShader);
+    AddToKey(newContext, wrappedShader);
 
-    builder->endBlock();
+    keyContext.paintParamsKeyBuilder()->endBlock();
 }
 
 static void notify_in_use(Recorder* recorder,
@@ -2341,10 +2194,8 @@
               (int)PerlinNoiseShaderBlock::Type::kFractalNoise);
 static_assert((int)SkPerlinNoiseShaderType::kTurbulence ==
               (int)PerlinNoiseShaderBlock::Type::kTurbulence);
-static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       const SkPerlinNoiseShader* shader) {
+
+static void add_to_key(const KeyContext& keyContext, const SkPerlinNoiseShader* shader) {
     SkASSERT(shader);
     SkASSERT(shader->numOctaves());
 
@@ -2362,7 +2213,7 @@
 
     if (!perm || !noise) {
         SKGPU_LOG_W("Couldn't create tables for PerlinNoiseShader");
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
@@ -2375,15 +2226,13 @@
     perlinData.fPermutationsProxy = std::move(perm);
     perlinData.fNoiseProxy = std::move(noise);
 
-    PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, perlinData);
+    PerlinNoiseShaderBlock::AddBlock(keyContext, perlinData);
 }
 static void notify_in_use(Recorder*, DrawContext*, const SkPerlinNoiseShader*) {
     // No-op, perlin noise has no children.
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkPictureShader* shader) {
     SkASSERT(shader);
 
@@ -2406,7 +2255,7 @@
                                                        props);
     if (!info.success) {
         SKGPU_LOG_W("Couldn't access PictureShaders' Image info");
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
@@ -2426,7 +2275,7 @@
                                            &info.props);
     if (!surface) {
         SKGPU_LOG_W("Could not create surface to render PictureShader");
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
@@ -2440,7 +2289,7 @@
     // list this works out okay, but will need to be addressed before we move off that system.
     if (!img) {
         SKGPU_LOG_W("Couldn't create SkImage for PictureShader");
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
@@ -2449,11 +2298,11 @@
                                                 SkSamplingOptions(shader->filter()), &shaderLM);
     if (!imgShader) {
         SKGPU_LOG_W("Couldn't create SkImageShader for PictureShader");
-        builder->addBlock(BuiltInCodeSnippetID::kError);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
         return;
     }
 
-    AddToKey(keyContext, builder, gatherer, imgShader.get());
+    AddToKey(keyContext, imgShader.get());
 }
 static void notify_in_use(Recorder*, DrawContext*, const SkPictureShader*) {
     // While the SkPicture the shader points to, may have Graphite-backed shaders that need to be
@@ -2461,8 +2310,6 @@
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkRuntimeShader* shader) {
     SkASSERT(shader);
     sk_sp<SkRuntimeEffect> effect = shader->effect();
@@ -2472,16 +2319,14 @@
             keyContext.dstColorInfo().colorSpace());
     SkASSERT(uniforms);
 
-    if (!RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
-                                        { effect, std::move(uniforms) })) {
-        RuntimeEffectBlock::AddNoOpEffect(keyContext, builder, gatherer, effect.get());
+    if (!RuntimeEffectBlock::BeginBlock(keyContext, { effect, std::move(uniforms) })) {
+        RuntimeEffectBlock::AddNoOpEffect(keyContext, effect.get());
         return;
     }
 
-    add_children_to_key(keyContext, builder, gatherer,
-                        shader->children(), effect.get());
+    add_children_to_key(keyContext, shader->children(), effect.get());
 
-    builder->endBlock();
+    keyContext.paintParamsKeyBuilder()->endBlock();
 }
 static void notify_in_use(Recorder* recorder,
                           DrawContext* drawContext,
@@ -2490,30 +2335,24 @@
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkTransformShader* shader) {
     SKGPU_LOG_W("Raster-only SkShader (SkTransformShader) encountered");
-    builder->addBlock(BuiltInCodeSnippetID::kError);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
 }
 static void notify_in_use(Recorder*, DrawContext*, const SkTransformShader*) {
     // no-op
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkTriColorShader* shader) {
     SKGPU_LOG_W("Raster-only SkShader (SkTriColorShader) encountered");
-    builder->addBlock(BuiltInCodeSnippetID::kError);
+    keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
 }
 static void notify_in_use(Recorder*, DrawContext*, const SkTriColorShader*) {
     // no-op
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkWorkingColorSpaceShader* shader) {
     SkASSERT(shader);
 
@@ -2529,15 +2368,15 @@
     KeyContextWithColorInfo workingContext(keyContext, workingInfo);
 
     // Compose the inner shader (in the working space) with a (working->dst) transform:
-    Compose(keyContext, builder, gatherer,
-        /* addInnerToKey= */ [&]() -> void {
-            AddToKey(workingContext, builder, gatherer, shader->shader().get());
-        },
-        /* addOuterToKey= */ [&]() -> void {
-            ColorSpaceTransformBlock::ColorSpaceTransformData data(
-                    workingCS.get(), dstAT, dstCS.get(), dstAT);
-            ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
-        });
+    Compose(keyContext,
+            /* addInnerToKey= */ [&]() -> void {
+                AddToKey(workingContext, shader->shader().get());
+            },
+            /* addOuterToKey= */ [&]() -> void {
+                ColorSpaceTransformBlock::ColorSpaceTransformData data(
+                        workingCS.get(), dstAT, dstCS.get(), dstAT);
+                ColorSpaceTransformBlock::AddBlock(keyContext, data);
+            });
 }
 static void notify_in_use(Recorder* recorder,
                           DrawContext* drawContext,
@@ -2591,8 +2430,6 @@
 // Please see GrGradientShader.cpp::make_interpolated_to_dst for substantial comments
 // as to why this code is structured this way.
 static void make_interpolated_to_dst(const KeyContext& keyContext,
-                                     PaintParamsKeyBuilder* builder,
-                                     PipelineDataGatherer* gatherer,
                                      const GradientShaderBlocks::GradientData& gradData,
                                      const SkGradientShader::Interpolation& interp,
                                      SkColorSpace* intermediateCS) {
@@ -2628,18 +2465,16 @@
     // The gradient block and colorSpace conversion block need to be combined
     // (via the Compose block) so that the localMatrix block can treat them as
     // one child.
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
+                GradientShaderBlocks::AddBlock(keyContext, gradData);
             },
             /* addOuterToKey= */ [&]() -> void {
-                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
+                ColorSpaceTransformBlock::AddBlock(keyContext, data);
             });
 }
 
 static void add_gradient_to_key(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
                                 const SkGradientBaseShader* shader,
                                 SkPoint point0,
                                 SkPoint point1,
@@ -2662,7 +2497,7 @@
                     create_color_and_offset_bitmap(colorCount, colors, positions);
             if (colorsAndOffsetsBitmap.empty()) {
                 SKGPU_LOG_W("Couldn't create GradientShader's color and offset bitmap");
-                builder->addBlock(BuiltInCodeSnippetID::kError);
+                keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
                 return;
             }
             shader->setCachedBitmap(colorsAndOffsetsBitmap);
@@ -2672,7 +2507,7 @@
                                                 "GradientTexture");
         if (!proxy) {
             SKGPU_LOG_W("Couldn't create GradientShader's color and offset bitmap proxy");
-            builder->addBlock(BuiltInCodeSnippetID::kError);
+            keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kError);
             return;
         }
     }
@@ -2694,16 +2529,12 @@
                                             shader->getInterpolation());
 
     make_interpolated_to_dst(keyContext,
-                             builder,
-                             gatherer,
                              data,
                              shader->getInterpolation(),
                              xformedColors.fIntermediateColorSpace.get());
 }
 
 static void add_gradient_to_key(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
                                 const SkConicalGradient* shader) {
     SkScalar r0 = shader->getStartRadius();
     SkScalar r1 = shader->getEndRadius();
@@ -2719,8 +2550,6 @@
     }
 
     add_gradient_to_key(keyContext,
-                        builder,
-                        gatherer,
                         shader,
                         shader->getStartCenter(),
                         shader->getEndCenter(),
@@ -2731,12 +2560,8 @@
 }
 
 static void add_gradient_to_key(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
                                 const SkLinearGradient* shader) {
     add_gradient_to_key(keyContext,
-                        builder,
-                        gatherer,
                         shader,
                         shader->start(),
                         shader->end(),
@@ -2747,12 +2572,8 @@
 }
 
 static void add_gradient_to_key(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
                                 const SkRadialGradient* shader) {
     add_gradient_to_key(keyContext,
-                        builder,
-                        gatherer,
                         shader,
                         shader->center(),
                         { 0.0f, 0.0f },
@@ -2763,12 +2584,8 @@
 }
 
 static void add_gradient_to_key(const KeyContext& keyContext,
-                                PaintParamsKeyBuilder* builder,
-                                PipelineDataGatherer* gatherer,
                                 const SkSweepGradient* shader) {
     add_gradient_to_key(keyContext,
-                        builder,
-                        gatherer,
                         shader,
                         shader->center(),
                         { 0.0f, 0.0f },
@@ -2779,16 +2596,12 @@
 }
 
 static void add_to_key(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
                        const SkGradientBaseShader* shader) {
     SkASSERT(shader);
     switch (shader->asGradient()) {
 #define M(type)                                                               \
     case SkShaderBase::GradientType::k##type:                                 \
         add_gradient_to_key(keyContext,                                       \
-                            builder,                                          \
-                            gatherer,                                         \
                             static_cast<const Sk##type##Gradient*>(shader));  \
         return;
         SK_ALL_GRADIENTS(M)
@@ -2803,25 +2616,20 @@
     // Gradients do not have children, so no images to notify
 }
 
-void AddToKey(const KeyContext& keyContext,
-              PaintParamsKeyBuilder* builder,
-              PipelineDataGatherer* gatherer,
-              const SkShader* shader) {
+void AddToKey(const KeyContext& keyContext, const SkShader* shader) {
     if (!shader) {
         // Calling code assumes a block will be appended. Add a fixed block to preserve shader
         // and PaintParamsKey structure in release builds but assert since this should either not
         // happen or should be changing high-level logic within PaintParams::toKey().
         SkASSERT(false);
-        SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, SK_PMColor4fTRANSPARENT);
+        SolidColorShaderBlock::AddBlock(keyContext, SK_PMColor4fTRANSPARENT);
         return;
     }
     switch (as_SB(shader)->type()) {
 #define M(type)                                                        \
     case SkShaderBase::ShaderType::k##type:                            \
         add_to_key(keyContext,                                         \
-                   builder,                                            \
-                   gatherer,                                           \
-                   static_cast<const Sk##type##Shader*>(shader)); \
+                   static_cast<const Sk##type##Shader*>(shader));      \
         return;
         SK_ALL_SHADERS(M)
 #undef M
diff --git a/src/gpu/graphite/KeyHelpers.h b/src/gpu/graphite/KeyHelpers.h
index 5001bcd..154e6d5 100644
--- a/src/gpu/graphite/KeyHelpers.h
+++ b/src/gpu/graphite/KeyHelpers.h
@@ -21,6 +21,7 @@
 #include "include/private/base/SkTArray.h"
 #include "src/core/SkColorData.h"
 #include "src/core/SkColorSpaceXformSteps.h"
+#include "src/gpu/graphite/KeyContext.h"
 #include "src/gpu/graphite/PaintParamsKey.h"
 #include "src/gpu/graphite/ReadSwizzle.h"
 #include "src/gpu/graphite/ResourceTypes.h"
@@ -35,8 +36,7 @@
 namespace skgpu::graphite {
 
 class DrawContext;
-class KeyContext;
-class PaintParamsKeyBuilder;
+class FloatStorageManager;
 class PipelineDataGatherer;
 class UniquePaintParamsID;
 enum class ReadSwizzle;
@@ -60,22 +60,15 @@
  */
 
 struct SolidColorShaderBlock {
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const SkPMColor4f&);
+    static void AddBlock(const KeyContext&, const SkPMColor4f&);
 };
 
 struct RGBPaintColorBlock {
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*);
+    static void AddBlock(const KeyContext&);
 };
 
 struct AlphaOnlyPaintColorBlock {
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*);
+    static void AddBlock(const KeyContext&);
 };
 
 struct GradientShaderBlocks {
@@ -136,10 +129,7 @@
         SkGradientShader::Interpolation fInterpolation;
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const GradientData&);
+    static void AddBlock(const KeyContext&, const GradientData&);
 };
 
 struct LocalMatrixShaderBlock {
@@ -153,10 +143,7 @@
         const SkMatrix fLocalMatrix;
     };
 
-    static void BeginBlock(const KeyContext&,
-                           PaintParamsKeyBuilder*,
-                           PipelineDataGatherer*,
-                           const LMShaderData&);
+    static void BeginBlock(const KeyContext&, const LMShaderData&);
 };
 
 struct ImageShaderBlock {
@@ -178,10 +165,7 @@
         ImmutableSamplerInfo fImmutableSamplerInfo;
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const ImageData&);
+    static void AddBlock(const KeyContext&, const ImageData&);
 };
 
 struct YUVImageShaderBlock {
@@ -210,10 +194,7 @@
         sk_sp<TextureProxy> fTextureProxies[4];
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const ImageData&);
+    static void AddBlock(const KeyContext&, const ImageData&);
 };
 
 struct CoordNormalizeShaderBlock {
@@ -224,10 +205,7 @@
         SkSize fInvDimensions;
     };
 
-    static void BeginBlock(const KeyContext&,
-                           PaintParamsKeyBuilder*,
-                           PipelineDataGatherer*,
-                           const CoordNormalizeData&);
+    static void BeginBlock(const KeyContext&, const CoordNormalizeData&);
 };
 
 struct CoordClampShaderBlock {
@@ -237,11 +215,7 @@
         SkRect fSubset;
     };
 
-    // The gatherer and data should be null or non-null together
-    static void BeginBlock(const KeyContext&,
-                           PaintParamsKeyBuilder*,
-                           PipelineDataGatherer*,
-                           const CoordClampData&);
+    static void BeginBlock(const KeyContext&, const CoordClampData&);
 };
 
 struct DitherShaderBlock {
@@ -254,10 +228,7 @@
         sk_sp<TextureProxy> fLUTProxy;
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const DitherData&);
+    static void AddBlock(const KeyContext&, const DitherData&);
 };
 
 struct PerlinNoiseShaderBlock {
@@ -288,35 +259,23 @@
         sk_sp<TextureProxy> fNoiseProxy;
     };
 
-    // The gatherer and data should be null or non-null together
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const PerlinNoiseData&);
+    static void AddBlock(const KeyContext&, const PerlinNoiseData&);
 };
 
 struct BlendComposeBlock {
-    static void BeginBlock(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*);
+    static void BeginBlock(const KeyContext&);
 };
 
 struct PorterDuffBlenderBlock {
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         SkSpan<const float> coeffs);
+    static void AddBlock(const KeyContext&, SkSpan<const float> coeffs);
 };
 
 struct HSLCBlenderBlock {
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         SkSpan<const float> coeffs);
+    static void AddBlock(const KeyContext&, SkSpan<const float> coeffs);
 };
 
 struct ComposeBlock {
-    static void BeginBlock(const KeyContext&,
-                           PaintParamsKeyBuilder*,
-                           PipelineDataGatherer*);
+    static void BeginBlock(const KeyContext&);
 };
 
 struct MatrixColorFilterBlock {
@@ -337,11 +296,7 @@
         bool  fClamp;
     };
 
-    // The gatherer and matrixCFData should be null or non-null together
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const MatrixColorFilterData&);
+    static void AddBlock(const KeyContext&, const MatrixColorFilterData&);
 };
 
 struct TableColorFilterBlock {
@@ -351,10 +306,7 @@
         sk_sp<TextureProxy> fTextureProxy;
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const TableColorFilterData&);
+    static void AddBlock(const KeyContext&, const TableColorFilterData&);
 };
 
 struct ColorSpaceTransformBlock {
@@ -371,10 +323,7 @@
         ReadSwizzle            fReadSwizzle = ReadSwizzle::kRGBA;
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const ColorSpaceTransformData&);
+    static void AddBlock(const KeyContext&, const ColorSpaceTransformData&);
 };
 
 struct NonMSAAClipBlock {
@@ -404,28 +353,20 @@
         sk_sp<TextureProxy> fAtlasTexture;
     };
 
-    static void AddBlock(const KeyContext&,
-                         PaintParamsKeyBuilder*,
-                         PipelineDataGatherer*,
-                         const NonMSAAClipData&);
+    static void AddBlock(const KeyContext&, const NonMSAAClipData&);
 };
 
 /**
  * Adds a block that references the primitive color produced by the RenderStep and accounts for
  * color space transformation.
  */
-void AddPrimitiveColor(const KeyContext&,
-                       PaintParamsKeyBuilder*,
-                       PipelineDataGatherer*,
-                       bool skipColorXform);
+void AddPrimitiveColor(const KeyContext&, bool skipColorXform);
 
 /**
  * Blend mode color filters blend their input (as the dst color) with some given color (supplied
  * via a uniform) as the src color.
  */
 void AddBlendModeColorFilter(const KeyContext&,
-                             PaintParamsKeyBuilder*,
-                             PipelineDataGatherer*,
                              SkBlendMode,
                              const SkPMColor4f& srcColor);
 
@@ -448,56 +389,34 @@
     };
 
     // On a false return, no block has been started
-    static bool BeginBlock(const KeyContext&,
-                           PaintParamsKeyBuilder*,
-                           PipelineDataGatherer*,
-                           const ShaderData&);
+    static bool BeginBlock(const KeyContext&, const ShaderData&);
 
     // Add a no-op placeholder for an incorrect runtime effect
-    static void AddNoOpEffect(const KeyContext&,
-                              PaintParamsKeyBuilder*,
-                              PipelineDataGatherer*,
-                              SkRuntimeEffect*);
+    static void AddNoOpEffect(const KeyContext&, SkRuntimeEffect*);
 
     // Add a post-amble for runtime effects that use the toLinearSrgb/fromLinearSrgb intrinsics
-    static void HandleIntrinsics(const KeyContext&,
-                                 PaintParamsKeyBuilder*,
-                                 PipelineDataGatherer*,
-                                 const SkRuntimeEffect*);
+    static void HandleIntrinsics(const KeyContext&, const SkRuntimeEffect*);
 };
 
-void AddToKey(const KeyContext&,
-              PaintParamsKeyBuilder*,
-              PipelineDataGatherer*,
-              const SkBlender*);
+void AddToKey(const KeyContext&, const SkBlender*);
 
 /**
  *  Add implementation details, for the specified backend, of this SkColorFilter to the
  *  provided key.
  *
  *  @param keyContext backend context for key creation
- *  @param builder    builder for creating the key for this SkShader
- *  @param gatherer   if non-null, storage for this colorFilter's data
  *  @param filter     This function is a no-op if filter is null.
  */
-void AddToKey(const KeyContext& keyContext,
-              PaintParamsKeyBuilder* builder,
-              PipelineDataGatherer* gatherer,
-              const SkColorFilter* filter);
+void AddToKey(const KeyContext& keyContext, const SkColorFilter* filter);
 
 /**
  *  Add implementation details, for the specified backend, of this SkShader to the
  *  provided key.
  *
  *  @param keyContext backend context for key creation
- *  @param builder    builder for creating the key for this SkShader
- *  @param gatherer   if non-null, storage for this colorFilter's data
  *  @param shader     This function is a no-op if shader is null.
  */
-void AddToKey(const KeyContext& keyContext,
-              PaintParamsKeyBuilder* builder,
-              PipelineDataGatherer* gatherer,
-              const SkShader* shader);
+void AddToKey(const KeyContext& keyContext, const SkShader* shader);
 
 // TODO(b/330864257) These visitation functions are redundant with AddToKey, except that they are
 // executed in the Device::drawGeometry() stack frame, whereas the keys are currently deferred until
@@ -509,12 +428,10 @@
 
 template <typename AddBlendToKeyT, typename AddSrcToKeyT, typename AddDstToKeyT>
 void Blend(const KeyContext& keyContext,
-           PaintParamsKeyBuilder* keyBuilder,
-           PipelineDataGatherer* gatherer,
            AddBlendToKeyT addBlendToKey,
            AddSrcToKeyT addSrcToKey,
            AddDstToKeyT addDstToKey) {
-    BlendComposeBlock::BeginBlock(keyContext, keyBuilder, gatherer);
+    BlendComposeBlock::BeginBlock(keyContext);
 
         addSrcToKey();
 
@@ -522,22 +439,20 @@
 
         addBlendToKey();
 
-    keyBuilder->endBlock();  // BlendComposeBlock
+    keyContext.paintParamsKeyBuilder()->endBlock();  // BlendComposeBlock
 }
 
 template <typename AddInnerToKeyT, typename AddOuterToKeyT>
 void Compose(const KeyContext& keyContext,
-             PaintParamsKeyBuilder* keyBuilder,
-             PipelineDataGatherer* gatherer,
              AddInnerToKeyT addInnerToKey,
              AddOuterToKeyT addOuterToKey) {
-    ComposeBlock::BeginBlock(keyContext, keyBuilder, gatherer);
+    ComposeBlock::BeginBlock(keyContext);
 
         addInnerToKey();
 
         addOuterToKey();
 
-    keyBuilder->endBlock();  // ComposeBlock
+    keyContext.paintParamsKeyBuilder()->endBlock();  // ComposeBlock
 }
 
 } // namespace skgpu::graphite
diff --git a/src/gpu/graphite/PaintParams.cpp b/src/gpu/graphite/PaintParams.cpp
index ebb5d65..35e1168 100644
--- a/src/gpu/graphite/PaintParams.cpp
+++ b/src/gpu/graphite/PaintParams.cpp
@@ -111,61 +111,50 @@
     return result;
 }
 
-void AddFixedBlendMode(const KeyContext& keyContext,
-                       PaintParamsKeyBuilder* builder,
-                       PipelineDataGatherer* gatherer,
-                       SkBlendMode bm) {
+void AddFixedBlendMode(const KeyContext& keyContext, SkBlendMode bm) {
     SkASSERT(bm <= SkBlendMode::kLastMode);
     BuiltInCodeSnippetID id = static_cast<BuiltInCodeSnippetID>(kFixedBlendIDOffset +
                                                                 static_cast<int>(bm));
-    builder->addBlock(id);
+    keyContext.paintParamsKeyBuilder()->addBlock(id);
 }
 
-void AddBlendMode(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  SkBlendMode bm) {
+void AddBlendMode(const KeyContext& keyContext, SkBlendMode bm) {
     // For non-fixed blends, coefficient blend modes are combined into the same shader snippet.
     // The same goes for the HSLC advanced blends. The remaining advanced blends are fairly unique
     // in their implementations. To avoid having to compile all of their SkSL, they are treated as
     // fixed blend modes.
     SkSpan<const float> coeffs = skgpu::GetPorterDuffBlendConstants(bm);
     if (!coeffs.empty()) {
-        PorterDuffBlenderBlock::AddBlock(keyContext, builder, gatherer, coeffs);
+        PorterDuffBlenderBlock::AddBlock(keyContext, coeffs);
     } else if (bm >= SkBlendMode::kHue) {
         ReducedBlendModeInfo blendInfo = GetReducedBlendModeInfo(bm);
-        HSLCBlenderBlock::AddBlock(keyContext, builder, gatherer, blendInfo.fUniformData);
+        HSLCBlenderBlock::AddBlock(keyContext, blendInfo.fUniformData);
     } else {
-        AddFixedBlendMode(keyContext, builder, gatherer, bm);
+        AddFixedBlendMode(keyContext, bm);
     }
 }
 
-void AddDitherBlock(const KeyContext& keyContext,
-                    PaintParamsKeyBuilder* builder,
-                    PipelineDataGatherer* gatherer,
-                    SkColorType ct) {
+void AddDitherBlock(const KeyContext& keyContext, SkColorType ct) {
     static const SkBitmap gLUT = skgpu::MakeDitherLUT();
 
     sk_sp<TextureProxy> proxy = RecorderPriv::CreateCachedProxy(keyContext.recorder(), gLUT,
                                                                 "DitherLUT");
     if (keyContext.recorder() && !proxy) {
         SKGPU_LOG_W("Couldn't create dither shader's LUT");
-        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
         return;
     }
 
     DitherShaderBlock::DitherData data(skgpu::DitherRangeForConfig(ct), std::move(proxy));
 
-    DitherShaderBlock::AddBlock(keyContext, builder, gatherer, data);
+    DitherShaderBlock::AddBlock(keyContext, data);
 }
 
-void PaintParams::addPaintColorToKey(const KeyContext& keyContext,
-                                     PaintParamsKeyBuilder* keyBuilder,
-                                     PipelineDataGatherer* gatherer) const {
+void PaintParams::addPaintColorToKey(const KeyContext& keyContext) const {
     if (fShader) {
-        AddToKey(keyContext, keyBuilder, gatherer, fShader.get());
+        AddToKey(keyContext, fShader.get());
     } else {
-        RGBPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
+        RGBPaintColorBlock::AddBlock(keyContext);
     }
 }
 
@@ -174,14 +163,12 @@
  * with a primitive color emitted by certain draw geometry calls (drawVertices, drawAtlas, etc.).
  * Dst: primitiveColor Src: Paint color/shader output
  */
-void PaintParams::handlePrimitiveColor(const KeyContext& keyContext,
-                                       PaintParamsKeyBuilder* keyBuilder,
-                                       PipelineDataGatherer* gatherer) const {
+void PaintParams::handlePrimitiveColor(const KeyContext& keyContext) const {
     /**
      * If no primitive blending is required, simply add the paint color.
     */
     if (!fPrimitiveBlender) {
-        this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
+        this->addPaintColorToKey(keyContext);
         return;
     }
 
@@ -195,92 +182,84 @@
         as_BB(fPrimitiveBlender.get())->asBlendMode().value() == SkBlendMode::kDst;
 
     if (canSkipBlendStep) {
-        AddPrimitiveColor(keyContext, keyBuilder, gatherer, fSkipColorXform);
+        AddPrimitiveColor(keyContext, fSkipColorXform);
         return;
     }
 
-    Blend(keyContext, keyBuilder, gatherer,
+    Blend(keyContext,
         /* addBlendToKey= */ [&] () -> void {
-            AddToKey(keyContext, keyBuilder, gatherer, fPrimitiveBlender.get());
+            AddToKey(keyContext, fPrimitiveBlender.get());
         },
         /* addSrcToKey= */ [&] () -> void {
-            this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
+            this->addPaintColorToKey(keyContext);
         },
         /* addDstToKey= */ [&] () -> void {
-            AddPrimitiveColor(keyContext, keyBuilder, gatherer, fSkipColorXform);
+            AddPrimitiveColor(keyContext, fSkipColorXform);
         });
 }
 
 // Apply the paint's alpha value.
-void PaintParams::handlePaintAlpha(const KeyContext& keyContext,
-                                   PaintParamsKeyBuilder* keyBuilder,
-                                   PipelineDataGatherer* gatherer) const {
+void PaintParams::handlePaintAlpha(const KeyContext& keyContext) const {
 
     if (!fShader && !fPrimitiveBlender) {
         // If there is no shader and no primitive blending the input to the colorFilter stage
         // is just the premultiplied paint color.
         SkPMColor4f paintColor = PaintParams::Color4fPrepForDst(fColor,
                                                                 keyContext.dstColorInfo()).premul();
-        SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, paintColor);
+        SolidColorShaderBlock::AddBlock(keyContext, paintColor);
         return;
     }
 
     if (fColor.fA != 1.0f) {
-        Blend(keyContext, keyBuilder, gatherer,
+        Blend(keyContext,
               /* addBlendToKey= */ [&] () -> void {
-                  AddFixedBlendMode(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
+                  AddFixedBlendMode(keyContext, SkBlendMode::kSrcIn);
               },
               /* addSrcToKey= */ [&]() -> void {
-                  this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
+                  this->handlePrimitiveColor(keyContext);
               },
               /* addDstToKey= */ [&]() -> void {
-                  AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
+                  AlphaOnlyPaintColorBlock::AddBlock(keyContext);
               });
     } else {
-        this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
+        this->handlePrimitiveColor(keyContext);
     }
 }
 
-void PaintParams::handleColorFilter(const KeyContext& keyContext,
-                                    PaintParamsKeyBuilder* builder,
-                                    PipelineDataGatherer* gatherer) const {
+void PaintParams::handleColorFilter(const KeyContext& keyContext) const {
     if (fColorFilter) {
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    this->handlePaintAlpha(keyContext, builder, gatherer);
+                    this->handlePaintAlpha(keyContext);
                 },
                 /* addOuterToKey= */ [&]() -> void {
-                    AddToKey(keyContext, builder, gatherer, fColorFilter.get());
+                    AddToKey(keyContext, fColorFilter.get());
                 });
     } else {
-        this->handlePaintAlpha(keyContext, builder, gatherer);
+        this->handlePaintAlpha(keyContext);
     }
 }
 
-void PaintParams::handleDithering(const KeyContext& keyContext,
-                                  PaintParamsKeyBuilder* builder,
-                                  PipelineDataGatherer* gatherer) const {
+void PaintParams::handleDithering(const KeyContext& keyContext) const {
 
 #ifndef SK_IGNORE_GPU_DITHER
     SkColorType ct = keyContext.dstColorInfo().colorType();
     if (should_dither(*this, ct)) {
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    this->handleColorFilter(keyContext, builder, gatherer);
+                    this->handleColorFilter(keyContext);
                 },
                 /* addOuterToKey= */ [&]() -> void {
-                    AddDitherBlock(keyContext, builder, gatherer, ct);
+                    AddDitherBlock(keyContext, ct);
                 });
     } else
 #endif
     {
-        this->handleColorFilter(keyContext, builder, gatherer);
+        this->handleColorFilter(keyContext);
     }
 }
 
-void PaintParams::handleClipping(const KeyContext& keyContext,
-                                 PaintParamsKeyBuilder* builder,
-                                 PipelineDataGatherer* gatherer) const {
+void PaintParams::handleClipping(const KeyContext& keyContext) const {
     if (!fNonMSAAClip.isEmpty()) {
         const AnalyticClip& analyticClip = fNonMSAAClip.fAnalyticClip;
         SkPoint radiusPair;
@@ -317,52 +296,50 @@
         if (fClipShader) {
             // For both an analytic clip and clip shader, we need to compose them together into
             // a single clipping root node.
-            Blend(keyContext, builder, gatherer,
+            Blend(keyContext,
                   /* addBlendToKey= */ [&]() -> void {
-                      AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kModulate);
+                      AddFixedBlendMode(keyContext, SkBlendMode::kModulate);
                   },
                   /* addSrcToKey= */ [&]() -> void {
-                      NonMSAAClipBlock::AddBlock(keyContext, builder, gatherer, data);
+                      NonMSAAClipBlock::AddBlock(keyContext, data);
                   },
                   /* addDstToKey= */ [&]() -> void {
-                      AddToKey(keyContext, builder, gatherer, fClipShader.get());
+                      AddToKey(keyContext, fClipShader.get());
                   });
         } else {
             // Without a clip shader, the analytic clip can be the clipping root node.
-            NonMSAAClipBlock::AddBlock(keyContext, builder, gatherer, data);
+            NonMSAAClipBlock::AddBlock(keyContext, data);
         }
     } else if (fClipShader) {
         // Since there's no analytic clip, the clipping root node can be fClipShader directly.
-        AddToKey(keyContext, builder, gatherer, fClipShader.get());
+        AddToKey(keyContext, fClipShader.get());
     }
 }
 
-void PaintParams::toKey(const KeyContext& keyContext,
-                        PaintParamsKeyBuilder* builder,
-                        PipelineDataGatherer* gatherer) const {
+void PaintParams::toKey(const KeyContext& keyContext) const {
     // Root Node 0 is the source color, which is the output of all effects post dithering
-    this->handleDithering(keyContext, builder, gatherer);
+    this->handleDithering(keyContext);
 
     // Root Node 1 is the final blender
     std::optional<SkBlendMode> finalBlendMode = this->asFinalBlendMode();
     if (finalBlendMode) {
         if (!fDstReadRequired) {
             // With no shader blending, be as explicit as possible about the final blend
-            AddFixedBlendMode(keyContext, builder, gatherer, *finalBlendMode);
+            AddFixedBlendMode(keyContext, *finalBlendMode);
         } else {
             // With shader blending, use AddBlendMode() to select the more universal blend functions
             // when possible. Technically we could always use a fixed blend mode but would then
             // over-generate when encountering certain classes of blends. This is most problematic
             // on devices that wouldn't support dual-source blending, so help them out by at least
             // not requiring lots of pipelines.
-            AddBlendMode(keyContext, builder, gatherer, *finalBlendMode);
+            AddBlendMode(keyContext, *finalBlendMode);
         }
     } else {
-        AddToKey(keyContext, builder, gatherer, fFinalBlender.get());
+        AddToKey(keyContext, fFinalBlender.get());
     }
 
     // Optional Root Node 2 is the clip
-    this->handleClipping(keyContext, builder, gatherer);
+    this->handleClipping(keyContext);
 }
 
 // TODO(b/330864257): Can be deleted once keys are determined by the Device draw.
diff --git a/src/gpu/graphite/PaintParams.h b/src/gpu/graphite/PaintParams.h
index 3821961..c5b009b 100644
--- a/src/gpu/graphite/PaintParams.h
+++ b/src/gpu/graphite/PaintParams.h
@@ -20,6 +20,7 @@
 
 class DrawContext;
 class KeyContext;
+class FloatStorageManager;
 class PaintParamsKeyBuilder;
 class PipelineDataGatherer;
 class Recorder;
@@ -67,19 +68,18 @@
     /** Converts an SkColor4f to the destination color space. */
     static SkColor4f Color4fPrepForDst(SkColor4f srgb, const SkColorInfo& dstColorInfo);
 
-    void toKey(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
+    void toKey(const KeyContext&) const;
 
     void notifyImagesInUse(Recorder*, DrawContext*) const;
 
 private:
-    void addPaintColorToKey(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handlePrimitiveColor(
-            const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handlePaintAlpha(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handleColorFilter(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handleDithering(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handleDstRead(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handleClipping(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
+    void addPaintColorToKey(const KeyContext&) const;
+    void handlePrimitiveColor(const KeyContext&) const;
+    void handlePaintAlpha(const KeyContext&) const;
+    void handleColorFilter(const KeyContext&) const;
+    void handleDithering(const KeyContext&) const;
+    void handleDstRead(const KeyContext&) const;
+    void handleClipping(const KeyContext&) const;
 
     SkColor4f            fColor;
     sk_sp<SkBlender>     fFinalBlender; // A nullptr here means SrcOver blending
@@ -97,13 +97,10 @@
 };
 
 // Add a fixed blend mode node for a specific SkBlendMode.
-void AddFixedBlendMode(const KeyContext&,
-                       PaintParamsKeyBuilder*,
-                       PipelineDataGatherer*,
-                       SkBlendMode);
+void AddFixedBlendMode(const KeyContext&, SkBlendMode);
 // Add a blend mode node for an SkBlendMode that can vary
-void AddBlendMode(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*, SkBlendMode);
-void AddDitherBlock(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*, SkColorType);
+void AddBlendMode(const KeyContext&, SkBlendMode);
+void AddDitherBlock(const KeyContext&, SkColorType);
 
 } // namespace skgpu::graphite
 
diff --git a/src/gpu/graphite/PipelineData.h b/src/gpu/graphite/PipelineData.h
index d6214e1..e152c6d 100644
--- a/src/gpu/graphite/PipelineData.h
+++ b/src/gpu/graphite/PipelineData.h
@@ -18,7 +18,6 @@
 #include "src/base/SkArenaAlloc.h"
 #include "src/core/SkColorData.h"
 #include "src/core/SkTHash.h"
-#include "src/gpu/graphite/Caps.h"
 #include "src/gpu/graphite/DrawList.h"
 #include "src/gpu/graphite/DrawTypes.h"
 #include "src/gpu/graphite/TextureProxy.h"
@@ -164,7 +163,8 @@
 class DenseBiMap {
 public:
     using Index = uint32_t;
-    static constexpr Index kInvalidIndex = 4096;// 1 << SkNextLog2_portable(DrawList::kMaxRenderSteps);
+    // 1 << SkNextLog2_portable(DrawList::kMaxRenderSteps);
+    static constexpr Index kInvalidIndex = 4096;
 
     Index insert(K data) {
         Index* index = fDataToIndex.find(data);
@@ -336,7 +336,7 @@
 public:
     PipelineDataGatherer(Layout layout) : fUniformManager(layout) {}
 
-    // Fully resets uniforms and textures, but does not reset gradient storage.
+    // Fully resets uniforms and textures
     void resetForDraw() {
         fUniformManager.reset();
         fTextures.clear();
@@ -357,9 +357,6 @@
     }
 #endif // SK_DEBUG
 
-    // All accumulated gradient data or empty if no draw requires this feature.
-    SkSpan<const float> gradientBufferData() const { return fGradientStorage; }
-
     // Mark the end of extracting paint uniforms and textures from the current draw's PaintParams.
     UniformDataBlock endPaintData() {
         // Save the end of the paint textures for rewind(), but return the current state of the
@@ -419,33 +416,7 @@
     void beginStruct(int baseAligment) { fUniformManager.beginStruct(baseAligment); }
     void endStruct() { fUniformManager.endStruct(); }
 
-    // Checks if data already exists for the requested gradient shader, and returns a nullptr
-    // and the offset the data begins at. If it doesn't exist, it allocates the data for the
-    // required number of stops and caches the start index, returning the data pointer
-    // and index offset the data will begin at.
-    std::pair<float*, int> allocateGradientData(int numStops, const SkGradientBaseShader* shader) {
-        int* existingOfffset = fGradientOffsetCache.find(shader);
-        if (existingOfffset) {
-            return std::make_pair(nullptr, *existingOfffset);
-        }
-
-        auto dataPair = this->allocateFloatData(numStops * 5);
-        fGradientOffsetCache.set(shader, dataPair.second);
-
-        return dataPair;
-    }
-
 private:
-    // Allocates the data for the requested number of bytes and returns the
-    // pointer and buffer index offset the data will begin at.
-    std::pair<float*, int> allocateFloatData(int size) {
-        int lastSize = fGradientStorage.size();
-        fGradientStorage.resize(lastSize + size);
-        float* startPtr = fGradientStorage.begin() + lastSize;
-
-        return std::make_pair(startPtr, lastSize);
-    }
-
     SkDEBUGCODE(friend class UniformExpectationsValidator;)
 
     // Uniforms and textures are reset between draws but the PipelineDataGatherer is responsible
@@ -456,14 +427,6 @@
     UniformManager fUniformManager;
     skia_private::TArray<TextureDataBlock::SampledTexture> fTextures;
     int fPaintTextureCount = 0;
-
-    // NOTE: This storage aggregates all data required by all draws within a DrawPass so that its
-    // storage buffer can be bound once and accessed at random. It is not reset between draws like
-    // the regular uniform manager or texture list.
-    SkTDArray<float>  fGradientStorage;
-    // Storing the address of the shader as a proxy for comparing the colors and offsets arrays to
-    // keep lookup fast.
-    skia_private::THashMap<const SkGradientBaseShader*, int> fGradientOffsetCache;
 };
 
 #ifdef SK_DEBUG
@@ -490,6 +453,56 @@
 };
 #endif // SK_DEBUG
 
+/**
+ * Aggregates gradient color and stop information into a single buffer to be bound once for a
+ * DrawPass. It de-duplicates gradient data by caching based on the SkGradientBaseShader pointer.
+ */
+class FloatStorageManager {
+public:
+    FloatStorageManager() = default;
+
+    void reset() {
+        fGradientStorage.clear();
+        fGradientOffsetCache.reset();
+    }
+
+    // All accumulated gradient data.
+    SkSpan<const float> data() const { return fGradientStorage; }
+
+    // Checks if data already exists for the requested gradient shader. If so, it returns
+    // a nullptr and the existing offset. If not, it allocates space, caches the offset,
+    // and returns a pointer to the start of the new data and the calculated offset.
+    std::pair<float*, int> allocateGradientData(int numStops, const SkGradientBaseShader* shader) {
+        int* existingOffset = fGradientOffsetCache.find(shader);
+        if (existingOffset) {
+            return {nullptr, *existingOffset};
+        }
+
+        auto [ptr, offset] = this->allocateFloatData(numStops * 5); // 4 for color, 1 for offset
+        fGradientOffsetCache.set(shader, offset);
+
+        return {ptr, offset};
+    }
+
+private:
+    // Allocates space for a given number of floats and returns a pointer to the start
+    // of the new allocation and its offset from the beginning of the buffer.
+    std::pair<float*, int> allocateFloatData(int floatCount) {
+        int currentSize = fGradientStorage.size();
+        fGradientStorage.resize(currentSize + floatCount);
+        float* startPtr = fGradientStorage.begin() + currentSize;
+
+        return {startPtr, currentSize};
+    }
+
+    // NOTE: This storage aggregates all data required by all draws within a DrawPass so that its
+    // storage buffer can be bound once and accessed at random.
+    SkTDArray<float> fGradientStorage;
+
+    // We use the shader's address as a key to de-duplicate gradient data.
+    skia_private::THashMap<const SkGradientBaseShader*, int> fGradientOffsetCache;
+};
+
 } // namespace skgpu::graphite
 
 #endif // skgpu_graphite_PipelineData_DEFINED
diff --git a/src/gpu/graphite/PublicPrecompile.cpp b/src/gpu/graphite/PublicPrecompile.cpp
index da7656e..7cf033d 100644
--- a/src/gpu/graphite/PublicPrecompile.cpp
+++ b/src/gpu/graphite/PublicPrecompile.cpp
@@ -131,7 +131,15 @@
                                          caps->getDstReadStrategy());
 
             SkColorInfo ci(rpp.fDstCT, kPremul_SkAlphaType, rpp.fDstCS);
-            KeyContext keyContext(caps, dict, rtEffectDict.get(), ci);
+
+            // The PipelineDataGatherer and FloatStorageManager are only used to accumulate uniform
+            // data. In the pre-compile case we don't need to record the uniform data but the
+            // process of generating it is required to create the correct key.
+            FloatStorageManager floatStorageManager;
+            PipelineDataGatherer gatherer(Layout::kMetal);
+            PaintParamsKeyBuilder builder(dict);
+            KeyContext keyContext(caps, &floatStorageManager, &builder, &gatherer, dict,
+                                  rtEffectDict.get(), ci);
 
             for (Coverage coverage : { Coverage::kNone, Coverage::kSingleChannel }) {
                 PrecompileCombinations(
@@ -271,13 +279,8 @@
         return;
     }
 
-    // Since the precompilation path's uniforms aren't used and don't change the key,
-    // the exact layout doesn't matter
-    PipelineDataGatherer gatherer(Layout::kMetal);
-
     options.priv().buildCombinations(
         keyContext,
-        &gatherer,
         drawTypes,
         withPrimitiveBlender,
         coverage,
diff --git a/src/gpu/graphite/precompile/PaintOption.cpp b/src/gpu/graphite/precompile/PaintOption.cpp
index f735405..90379b6 100644
--- a/src/gpu/graphite/precompile/PaintOption.cpp
+++ b/src/gpu/graphite/precompile/PaintOption.cpp
@@ -55,11 +55,9 @@
     }
 }
 
-void PaintOption::toKey(const KeyContext& keyContext,
-                        PaintParamsKeyBuilder* keyBuilder,
-                        PipelineDataGatherer* gatherer) const {
+void PaintOption::toKey(const KeyContext& keyContext) const {
     // Root Node 0 is the source color, which is the output of all effects post dithering
-    this->handleDithering(keyContext, keyBuilder, gatherer);
+    this->handleDithering(keyContext);
 
     // Root Node 1 is the final blender
     std::optional<SkBlendMode> finalBlendMode =
@@ -67,103 +65,91 @@
                                  : SkBlendMode::kSrcOver;
     if (finalBlendMode) {
         if (!fDstReadRequired) {
-            AddFixedBlendMode(keyContext, keyBuilder, gatherer, *finalBlendMode);
+            AddFixedBlendMode(keyContext, *finalBlendMode);
         } else {
-            AddBlendMode(keyContext, keyBuilder, gatherer, *finalBlendMode);
+            AddBlendMode(keyContext, *finalBlendMode);
         }
     } else {
         SkASSERT(this->finalBlender());
-        fFinalBlender.first->priv().addToKey(keyContext, keyBuilder, gatherer,
-                                             fFinalBlender.second);
+        fFinalBlender.first->priv().addToKey(keyContext, fFinalBlender.second);
     }
 
     // Optional Root Node 2 is the clip
-    this->handleClipping(keyContext, keyBuilder, gatherer);
+    this->handleClipping(keyContext);
 }
 
-void PaintOption::addPaintColorToKey(const KeyContext& keyContext,
-                                     PaintParamsKeyBuilder* builder,
-                                     PipelineDataGatherer* gatherer) const {
+void PaintOption::addPaintColorToKey(const KeyContext& keyContext) const {
     if (fShader.first) {
-        fShader.first->priv().addToKey(keyContext, builder, gatherer, fShader.second);
+        fShader.first->priv().addToKey(keyContext, fShader.second);
     } else {
-        RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
+        RGBPaintColorBlock::AddBlock(keyContext);
     }
 }
 
-void PaintOption::handlePrimitiveColor(const KeyContext& keyContext,
-                                       PaintParamsKeyBuilder* keyBuilder,
-                                       PipelineDataGatherer* gatherer) const {
+void PaintOption::handlePrimitiveColor(const KeyContext& keyContext) const {
     if (!fHasPrimitiveBlender) {
-        this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
+        this->addPaintColorToKey(keyContext);
         return;
     }
 
     if (fSkipColorXform && fPrimitiveBlendMode == SkBlendMode::kDst) {
-        AddPrimitiveColor(keyContext, keyBuilder, gatherer, fSkipColorXform);
+        AddPrimitiveColor(keyContext, fSkipColorXform);
         return;
     }
 
-    Blend(keyContext, keyBuilder, gatherer,
+    Blend(keyContext,
             /* addBlendToKey= */ [&] () -> void {
                 /**
                  * TODO: Allow clients to provide precompile SkBlender options for primitive
                  * blending. For now we have a back door to internally specify an SkBlendMode.
                  */
                 AddToKey(keyContext,
-                         keyBuilder,
-                         gatherer,
                          SkBlender::Mode(fPrimitiveBlendMode).get());
             },
             /* addSrcToKey= */ [&]() -> void {
-                this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
+                this->addPaintColorToKey(keyContext);
             },
             /* addDstToKey= */ [&]() -> void {
-                AddPrimitiveColor(keyContext, keyBuilder, gatherer, fSkipColorXform);
+                AddPrimitiveColor(keyContext, fSkipColorXform);
             });
 }
 
-void PaintOption::handlePaintAlpha(const KeyContext& keyContext,
-                                   PaintParamsKeyBuilder* keyBuilder,
-                                   PipelineDataGatherer* gatherer) const {
+void PaintOption::handlePaintAlpha(const KeyContext& keyContext) const {
 
     if (!fShader.first && !fHasPrimitiveBlender) {
         // If there is no shader and no primitive blending the input to the colorFilter stage
         // is just the premultiplied paint color.
-        SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, SK_PMColor4fWHITE);
+        SolidColorShaderBlock::AddBlock(keyContext, SK_PMColor4fWHITE);
         return;
     }
 
     if (!fOpaquePaintColor) {
-        Blend(keyContext, keyBuilder, gatherer,
+        Blend(keyContext,
               /* addBlendToKey= */ [&] () -> void {
-                  AddFixedBlendMode(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
+                  AddFixedBlendMode(keyContext, SkBlendMode::kSrcIn);
               },
               /* addSrcToKey= */ [&]() -> void {
-                  this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
+                  this->handlePrimitiveColor(keyContext);
               },
               /* addDstToKey= */ [&]() -> void {
-                  AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
+                  AlphaOnlyPaintColorBlock::AddBlock(keyContext);
               });
     } else {
-        this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
+        this->handlePrimitiveColor(keyContext);
     }
 }
 
-void PaintOption::handleColorFilter(const KeyContext& keyContext,
-                                    PaintParamsKeyBuilder* builder,
-                                    PipelineDataGatherer* gatherer) const {
+void PaintOption::handleColorFilter(const KeyContext& keyContext) const {
     if (fColorFilter.first) {
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    this->handlePaintAlpha(keyContext, builder, gatherer);
+                    this->handlePaintAlpha(keyContext);
                 },
                 /* addOuterToKey= */ [&]() -> void {
-                    fColorFilter.first->priv().addToKey(keyContext, builder, gatherer,
-                                                        fColorFilter.second);
+                    fColorFilter.first->priv().addToKey(keyContext, fColorFilter.second);
                 });
     } else {
-        this->handlePaintAlpha(keyContext, builder, gatherer);
+        this->handlePaintAlpha(keyContext);
     }
 }
 
@@ -187,30 +173,26 @@
     return fShader.first && !fShader.first->priv().isConstant(fShader.second);
 }
 
-void PaintOption::handleDithering(const KeyContext& keyContext,
-                                  PaintParamsKeyBuilder* builder,
-                                  PipelineDataGatherer* gatherer) const {
+void PaintOption::handleDithering(const KeyContext& keyContext) const {
 
 #ifndef SK_IGNORE_GPU_DITHER
     SkColorType ct = keyContext.dstColorInfo().colorType();
     if (this->shouldDither(ct)) {
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    this->handleColorFilter(keyContext, builder, gatherer);
+                    this->handleColorFilter(keyContext);
                 },
                 /* addOuterToKey= */ [&]() -> void {
-                    AddDitherBlock(keyContext, builder, gatherer, ct);
+                    AddDitherBlock(keyContext, ct);
                 });
     } else
 #endif
     {
-        this->handleColorFilter(keyContext, builder, gatherer);
+        this->handleColorFilter(keyContext);
     }
 }
 
-void PaintOption::handleClipping(const KeyContext& keyContext,
-                                 PaintParamsKeyBuilder* builder,
-                                 PipelineDataGatherer* gatherer) const {
+void PaintOption::handleClipping(const KeyContext& keyContext) const {
     if (fAnalyticClip) {
         NonMSAAClipBlock::NonMSAAClipData data(
                 /* rect= */ {},
@@ -224,25 +206,23 @@
         if (fClipShader.first) {
             // For both an analytic clip and clip shader, we need to compose them together into
             // a single clipping root node.
-            Blend(keyContext, builder, gatherer,
+            Blend(keyContext,
                     /* addBlendToKey= */ [&]() -> void {
-                        AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kModulate);
+                        AddFixedBlendMode(keyContext, SkBlendMode::kModulate);
                     },
                     /* addSrcToKey= */ [&]() -> void {
-                        NonMSAAClipBlock::AddBlock(keyContext, builder, gatherer, data);
+                        NonMSAAClipBlock::AddBlock(keyContext, data);
                     },
                     /* addDstToKey= */ [&]() -> void {
-                        fClipShader.first->priv().addToKey(keyContext, builder, gatherer,
-                                                           fClipShader.second);
+                        fClipShader.first->priv().addToKey(keyContext, fClipShader.second);
                     });
         } else {
             // Without a clip shader, the analytic clip can be the clipping root node.
-            NonMSAAClipBlock::AddBlock(keyContext, builder, gatherer, data);
+            NonMSAAClipBlock::AddBlock(keyContext, data);
         }
     } else if (fClipShader.first) {
         // Since there's no analytic clip, the clipping root node can be fClipShader directly.
-        fClipShader.first->priv().addToKey(keyContext, builder, gatherer,
-                                           fClipShader.second);
+        fClipShader.first->priv().addToKey(keyContext, fClipShader.second);
     }
 }
 
diff --git a/src/gpu/graphite/precompile/PaintOption.h b/src/gpu/graphite/precompile/PaintOption.h
index a6da4d1..046ccc3 100644
--- a/src/gpu/graphite/precompile/PaintOption.h
+++ b/src/gpu/graphite/precompile/PaintOption.h
@@ -22,6 +22,7 @@
 class KeyContext;
 class PaintParamsKeyBuilder;
 class PipelineDataGatherer;
+class FloatStorageManager;
 
 class PaintOption {
 public:
@@ -39,18 +40,16 @@
 
     const PrecompileBlender* finalBlender() const { return fFinalBlender.first.get(); }
 
-    void toKey(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
+    void toKey(const KeyContext&) const;
 
 private:
-    void addPaintColorToKey(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handlePrimitiveColor(const KeyContext&,
-                              PaintParamsKeyBuilder*,
-                              PipelineDataGatherer*) const;
-    void handlePaintAlpha(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handleColorFilter(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
+    void addPaintColorToKey(const KeyContext&) const;
+    void handlePrimitiveColor(const KeyContext&) const;
+    void handlePaintAlpha(const KeyContext&) const;
+    void handleColorFilter(const KeyContext&) const;
     bool shouldDither(SkColorType dstCT) const;
-    void handleDithering(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
-    void handleClipping(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
+    void handleDithering(const KeyContext&) const;
+    void handleClipping(const KeyContext&) const;
 
     bool fOpaquePaintColor;
     std::pair<sk_sp<PrecompileBlender>, int> fFinalBlender;
diff --git a/src/gpu/graphite/precompile/PaintOptions.cpp b/src/gpu/graphite/precompile/PaintOptions.cpp
index b316e6d..f62f339 100644
--- a/src/gpu/graphite/precompile/PaintOptions.cpp
+++ b/src/gpu/graphite/precompile/PaintOptions.cpp
@@ -153,13 +153,11 @@
 
 void PaintOptions::createKey(const KeyContext& keyContext,
                              TextureFormat targetFormat,
-                             PaintParamsKeyBuilder* keyBuilder,
-                             PipelineDataGatherer* gatherer,
                              int desiredCombination,
                              bool addPrimitiveBlender,
                              bool addAnalyticClip,
                              Coverage coverage) const {
-    SkDEBUGCODE(keyBuilder->checkReset();)
+    SkDEBUGCODE(keyContext.paintParamsKeyBuilder()->checkReset();)
     SkASSERT(desiredCombination < this->numCombinations());
 
     const int numClipShaderCombos = this->numClipShaderCombinations();
@@ -213,13 +211,12 @@
                        fDither,
                        addAnalyticClip);
 
-    option.toKey(keyContext, keyBuilder, gatherer);
+    option.toKey(keyContext);
 }
 
 namespace {
 
 void create_image_drawing_pipelines(const KeyContext& keyContext,
-                                    PipelineDataGatherer* gatherer,
                                     const PaintOptions& orig,
                                     const RenderPassDesc& renderPassDesc,
                                     const PaintOptionsPriv::ProcessCombination& processCombination) {
@@ -236,7 +233,6 @@
     imagePaintOptions.priv().addColorFilter(nullptr);
 
     imagePaintOptions.priv().buildCombinations(keyContext,
-                                               gatherer,
                                                DrawTypeFlags::kSimpleShape,
                                                /* withPrimitiveBlender= */ false,
                                                Coverage::kSingleChannel,
@@ -248,15 +244,11 @@
 
 void PaintOptions::buildCombinations(
         const KeyContext& keyContext,
-        PipelineDataGatherer* gatherer,
         DrawTypeFlags drawTypes,
         bool withPrimitiveBlender,
         Coverage coverage,
         const RenderPassDesc& renderPassDesc,
         const ProcessCombination& processCombination) const {
-
-    PaintParamsKeyBuilder builder(keyContext.dict());
-
     if (!fImageFilterOptions.empty() || !fMaskFilterOptions.empty()) {
         // TODO: split this out into a create_restore_draw_pipelines method
         PaintOptions tmp = *this;
@@ -298,17 +290,16 @@
             tmp.setColorFilters(newCFs);
         }
 
-        tmp.buildCombinations(keyContext, gatherer, drawTypes, withPrimitiveBlender, coverage,
-                              renderPassDesc, processCombination);
+        tmp.buildCombinations(keyContext, drawTypes, withPrimitiveBlender, coverage, renderPassDesc,
+                              processCombination);
 
-        create_image_drawing_pipelines(keyContext, gatherer, *this,
-                                       renderPassDesc, processCombination);
+        create_image_drawing_pipelines(keyContext, *this, renderPassDesc, processCombination);
 
         for (const sk_sp<PrecompileImageFilter>& o : fImageFilterOptions) {
-            o->createPipelines(keyContext, gatherer, renderPassDesc, processCombination);
+            o->createPipelines(keyContext, renderPassDesc, processCombination);
         }
         for (const sk_sp<PrecompileMaskFilter>& o : fMaskFilterOptions) {
-            o->createPipelines(keyContext, gatherer, *this, renderPassDesc, processCombination);
+            o->createPipelines(keyContext, *this, renderPassDesc, processCombination);
         }
     } else {
         int numCombinations = this->numCombinations();
@@ -316,15 +307,16 @@
             // Since the precompilation path's uniforms aren't used and don't change the key,
             // the exact layout doesn't matter
 
-            gatherer->resetForDraw();
+            keyContext.pipelineDataGatherer()->resetForDraw();
 
             this->createKey(keyContext, renderPassDesc.fColorAttachment.fFormat,
-                            &builder, gatherer, i, withPrimitiveBlender,
+                            i, withPrimitiveBlender,
                             SkToBool(drawTypes & DrawTypeFlags::kAnalyticClip), coverage);
 
             // The 'findOrCreate' calls lockAsKey on builder and then destroys the returned
             // PaintParamsKey. This serves to reset the builder.
-            UniquePaintParamsID paintID = keyContext.dict()->findOrCreate(&builder);
+            UniquePaintParamsID paintID = keyContext.dict()->findOrCreate(
+                    keyContext.paintParamsKeyBuilder());
 
             processCombination(paintID, drawTypes, withPrimitiveBlender, coverage, renderPassDesc);
         }
diff --git a/src/gpu/graphite/precompile/PaintOptionsPriv.h b/src/gpu/graphite/precompile/PaintOptionsPriv.h
index 2a693de..cafc69c 100644
--- a/src/gpu/graphite/precompile/PaintOptionsPriv.h
+++ b/src/gpu/graphite/precompile/PaintOptionsPriv.h
@@ -41,15 +41,13 @@
 
     void buildCombinations(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             DrawTypeFlags drawTypes,
             bool withPrimitiveBlender,
             Coverage coverage,
             const RenderPassDesc& renderPassDesc,
             const ProcessCombination& processCombination) const {
-        fPaintOptions->buildCombinations(
-                keyContext, gatherer, drawTypes, withPrimitiveBlender, coverage,
-                renderPassDesc, processCombination);
+        fPaintOptions->buildCombinations(keyContext, drawTypes, withPrimitiveBlender, coverage,
+                                         renderPassDesc, processCombination);
     }
 
 private:
diff --git a/src/gpu/graphite/precompile/PrecompileBaseComplete.h b/src/gpu/graphite/precompile/PrecompileBaseComplete.h
index 9d0edaf..634590a 100644
--- a/src/gpu/graphite/precompile/PrecompileBaseComplete.h
+++ b/src/gpu/graphite/precompile/PrecompileBaseComplete.h
@@ -29,13 +29,11 @@
 
 template<typename T>
 void PrecompileBase::AddToKey(const KeyContext& keyContext,
-                              PaintParamsKeyBuilder* builder,
-                              PipelineDataGatherer* gatherer,
                               SkSpan<const sk_sp<T>> options,
                               int desiredOption) {
     auto [option, childOptions] = SelectOption(options, desiredOption);
     if (option) {
-        option->priv().addToKey(keyContext, builder, gatherer, childOptions);
+        option->priv().addToKey(keyContext, childOptions);
     }
 }
 
diff --git a/src/gpu/graphite/precompile/PrecompileBasePriv.h b/src/gpu/graphite/precompile/PrecompileBasePriv.h
index 350fcc0..b9c863e 100644
--- a/src/gpu/graphite/precompile/PrecompileBasePriv.h
+++ b/src/gpu/graphite/precompile/PrecompileBasePriv.h
@@ -25,11 +25,8 @@
         return fPrecompileBase->numCombinations();
     }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const {
-        fPrecompileBase->addToKey(keyContext, builder, gatherer, desiredCombination);
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const {
+        fPrecompileBase->addToKey(keyContext, desiredCombination);
     }
 
 private:
diff --git a/src/gpu/graphite/precompile/PrecompileBlender.cpp b/src/gpu/graphite/precompile/PrecompileBlender.cpp
index b493e79..3d2bcfa 100644
--- a/src/gpu/graphite/precompile/PrecompileBlender.cpp
+++ b/src/gpu/graphite/precompile/PrecompileBlender.cpp
@@ -27,13 +27,9 @@
 protected:
     std::optional<SkBlendMode> asBlendMode() const final { return fBlendMode; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const final {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const final {
         SkASSERT(desiredCombination == 0); // The blend mode blender only ever has one combination
-
-        AddBlendMode(keyContext, builder, gatherer, fBlendMode);
+        AddBlendMode(keyContext, fBlendMode);
     }
 
 private:
diff --git a/src/gpu/graphite/precompile/PrecompileBlenderPriv.h b/src/gpu/graphite/precompile/PrecompileBlenderPriv.h
index 71876c9..cd50bca1 100644
--- a/src/gpu/graphite/precompile/PrecompileBlenderPriv.h
+++ b/src/gpu/graphite/precompile/PrecompileBlenderPriv.h
@@ -26,11 +26,8 @@
 
     int numCombinations() const { return fPrecompileBlender->numCombinations(); }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const {
-        fPrecompileBlender->addToKey(keyContext, builder, gatherer, desiredCombination);
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const {
+        fPrecompileBlender->addToKey(keyContext, desiredCombination);
     }
 
 private:
diff --git a/src/gpu/graphite/precompile/PrecompileColorFilter.cpp b/src/gpu/graphite/precompile/PrecompileColorFilter.cpp
index 82e3e43..b857e7c 100644
--- a/src/gpu/graphite/precompile/PrecompileColorFilter.cpp
+++ b/src/gpu/graphite/precompile/PrecompileColorFilter.cpp
@@ -80,10 +80,7 @@
 private:
     int numChildCombinations() const override { return fNumOuterCombos * fNumInnerCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numCombinations());
 
         const int desiredOuterCombination = desiredCombination % fNumOuterCombos;
@@ -104,18 +101,18 @@
 
         if (!inner && !outer) {
             // A "passthrough" color filter returns the input color as-is.
-            builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+            keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
         } else if (!inner) {
-            outer->priv().addToKey(keyContext, builder, gatherer, outerChildOptions);
+            outer->priv().addToKey(keyContext, outerChildOptions);
         } else if (!outer) {
-            inner->priv().addToKey(keyContext, builder, gatherer, innerChildOptions);
+            inner->priv().addToKey(keyContext, innerChildOptions);
         } else {
-            Compose(keyContext, builder, gatherer,
+            Compose(keyContext,
                     /* addInnerToKey= */ [&]() -> void {
-                        inner->priv().addToKey(keyContext, builder, gatherer, innerChildOptions);
+                        inner->priv().addToKey(keyContext, innerChildOptions);
                     },
                     /* addOuterToKey= */ [&]() -> void {
-                        outer->priv().addToKey(keyContext, builder, gatherer, outerChildOptions);
+                        outer->priv().addToKey(keyContext, outerChildOptions);
                     });
         }
     }
@@ -148,18 +145,12 @@
         return fBlendOptions.numCombinations();
     }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         auto [blender, option ] = fBlendOptions.selectOption(desiredCombination);
         SkASSERT(option == 0 && blender->priv().asBlendMode().has_value());
-
         SkBlendMode representativeBlendMode = *blender->priv().asBlendMode();
-
         // Here the color is just a stand-in for a later value.
-        AddBlendModeColorFilter(keyContext, builder, gatherer,
-                                representativeBlendMode, SK_PMColor4fWHITE);
+        AddBlendModeColorFilter(keyContext, representativeBlendMode, SK_PMColor4fWHITE);
     }
 
     // NOTE: The BlendMode color filter can only be created with SkBlendModes, not arbitrary
@@ -200,21 +191,15 @@
     PrecompileMatrixColorFilter(bool inHSLA) : fInHSLA(inHSLA) {}
 
 private:
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination == 0);
-
         static constexpr float kIdentity[20] = { 1, 0, 0, 0, 0,
                                                  0, 1, 0, 0, 0,
                                                  0, 0, 1, 0, 0,
                                                  0, 0, 0, 1, 0 };
-
-        MatrixColorFilterBlock::MatrixColorFilterData matrixCFData(
-                kIdentity, fInHSLA, /* clamp= */ true);
-
-        MatrixColorFilterBlock::AddBlock(keyContext, builder, gatherer, matrixCFData);
+        MatrixColorFilterBlock::MatrixColorFilterData matrixCFData(kIdentity, fInHSLA,
+                                                                   /* clamp= */ true);
+        MatrixColorFilterBlock::AddBlock(keyContext, matrixCFData);
     }
 
     bool fInHSLA;
@@ -240,10 +225,7 @@
 private:
     int numIntrinsicCombinations() const override { return fNumCombinations; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         const int srcCombination = desiredCombination % fSrc.size();
         const int dstCombination = desiredCombination / fSrc.size();
         SkASSERT(dstCombination < static_cast<int>(fDst.size()));
@@ -256,7 +238,7 @@
                         fSrc[srcCombination].get(), kAlphaType,
                         fDst[dstCombination].get(), kAlphaType);
 
-        ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
+        ColorSpaceTransformBlock::AddBlock(keyContext, csData);
     }
 
     std::vector<sk_sp<SkColorSpace>> fSrc;
@@ -309,15 +291,10 @@
 
 //--------------------------------------------------------------------------------------------------
 class PrecompileTableColorFilter : public PrecompileColorFilter {
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination == 0);
-
         TableColorFilterBlock::TableColorFilterData data(/* proxy= */ nullptr);
-
-        TableColorFilterBlock::AddBlock(keyContext, builder, gatherer, data);
+        TableColorFilterBlock::AddBlock(keyContext, data);
     }
 };
 
@@ -367,13 +344,9 @@
 
 //--------------------------------------------------------------------------------------------------
 class PrecompileGaussianColorFilter : public PrecompileColorFilter {
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination == 0);
-
-        builder->addBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
     }
 };
 
@@ -399,10 +372,7 @@
 private:
     int numChildCombinations() const override { return fNumChildCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < fNumChildCombos);
 
         const SkColorInfo& dstInfo = keyContext.dstColorInfo();
@@ -417,28 +387,27 @@
 
         // Use two nested compose blocks to chain (dst->working), child, and (working->dst) together
         // while appearing as one block to the parent node.
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
                     // Inner compose
-                    Compose(keyContext, builder, gatherer,
+                    Compose(keyContext,
                             /* addInnerToKey= */ [&]() -> void {
                                 // Innermost (inner of inner compose)
                                 ColorSpaceTransformBlock::ColorSpaceTransformData data1(
                                         dstCS.get(), dstAT, workingCS.get(), workingAT);
-                                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
-                                                                   data1);
+                                ColorSpaceTransformBlock::AddBlock(keyContext, data1);
                             },
                             /* addOuterToKey= */ [&]() -> void {
                                 // Middle (outer of inner compose)
-                                AddToKey<PrecompileColorFilter>(workingContext, builder, gatherer,
-                                                                fChildOptions, desiredCombination);
+                                AddToKey<PrecompileColorFilter>(workingContext, fChildOptions,
+                                                                desiredCombination);
                             });
                 },
                 /* addOuterToKey= */ [&]() -> void {
                     // Outermost (outer of outer compose)
                     ColorSpaceTransformBlock::ColorSpaceTransformData data2(
                             workingCS.get(), workingAT, dstCS.get(), dstAT);
-                    ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data2);
+                    ColorSpaceTransformBlock::AddBlock(keyContext, data2);
                 });
     }
 
diff --git a/src/gpu/graphite/precompile/PrecompileImageFilter.cpp b/src/gpu/graphite/precompile/PrecompileImageFilter.cpp
index a282259..e7f9aed 100644
--- a/src/gpu/graphite/precompile/PrecompileImageFilter.cpp
+++ b/src/gpu/graphite/precompile/PrecompileImageFilter.cpp
@@ -49,17 +49,16 @@
 
 void PrecompileImageFilter::createPipelines(
         const KeyContext& keyContext,
-        PipelineDataGatherer* gatherer,
         const RenderPassDesc& renderPassDesc,
         const PaintOptions::ProcessCombination& processCombination) {
     // TODO: we will want to mark already visited nodes to prevent loops and track
     // already created Pipelines so we don't over-generate too much (e.g., if a DAG
     // has multiple blurs we don't want to keep trying to create all the blur pipelines).
-    this->onCreatePipelines(keyContext, gatherer, renderPassDesc, processCombination);
+    this->onCreatePipelines(keyContext, renderPassDesc, processCombination);
 
     for (const sk_sp<PrecompileImageFilter>& input : fInputs) {
         if (input) {
-            input->createPipelines(keyContext, gatherer, renderPassDesc, processCombination);
+            input->createPipelines(keyContext, renderPassDesc, processCombination);
         }
     }
 }
@@ -69,7 +68,6 @@
 
 void CreateBlurImageFilterPipelines(
         const KeyContext& keyContext,
-        PipelineDataGatherer* gatherer,
         const RenderPassDesc& renderPassDesc,
         const PaintOptionsPriv::ProcessCombination& processCombination) {
 
@@ -85,7 +83,6 @@
     blurPaintOptions.setBlendModes(kBlurBlendModes);
 
     blurPaintOptions.priv().buildCombinations(keyContext,
-                                              gatherer,
                                               DrawTypeFlags::kSimpleShape,
                                               /* withPrimitiveBlender= */ false,
                                               Coverage::kSingleChannel,
@@ -107,7 +104,6 @@
 private:
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
 
@@ -124,7 +120,6 @@
         paintOptions.setShaders({ std::move(blendShader) });
 
         paintOptions.priv().buildCombinations(keyContext,
-                                              gatherer,
                                               DrawTypeFlags::kSimpleShape,
                                               /* withPrimitiveBlender= */ false,
                                               Coverage::kSingleChannel,
@@ -181,11 +176,10 @@
 private:
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
 
-        PrecompileImageFiltersPriv::CreateBlurImageFilterPipelines(keyContext, gatherer,
+        PrecompileImageFiltersPriv::CreateBlurImageFilterPipelines(keyContext,
                                                                    renderPassDesc,
                                                                    processCombination);
     }
@@ -212,7 +206,6 @@
 
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
         PaintOptions paintOptions;
@@ -226,7 +219,6 @@
         paintOptions.setBlendModes(kBlendModes);
 
         paintOptions.priv().buildCombinations(keyContext,
-                                              gatherer,
                                               DrawTypeFlags::kSimpleShape,
                                               /* withPrimitiveBlender= */ false,
                                               Coverage::kSingleChannel,
@@ -266,7 +258,6 @@
 private:
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
 
@@ -280,7 +271,6 @@
         displacement.setShaders({ PrecompileShadersPriv::Displacement(imageShader, imageShader) });
 
         displacement.priv().buildCombinations(keyContext,
-                                              gatherer,
                                               DrawTypeFlags::kSimpleShape,
                                               /* withPrimitiveBlender= */ false,
                                               Coverage::kSingleChannel,
@@ -304,7 +294,6 @@
 private:
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
 
@@ -315,7 +304,6 @@
         lighting.setShaders({ PrecompileShadersPriv::Lighting(std::move(imageShader)) });
 
         lighting.priv().buildCombinations(keyContext,
-                                          gatherer,
                                           DrawTypeFlags::kSimpleShape,
                                           /* withPrimitiveBlender= */ false,
                                           Coverage::kSingleChannel,
@@ -339,7 +327,6 @@
 private:
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
 
@@ -353,7 +340,6 @@
         matrixConv.setShaders({ PrecompileShadersPriv::MatrixConvolution(imageShader) });
 
         matrixConv.priv().buildCombinations(keyContext,
-                                            gatherer,
                                             DrawTypeFlags::kSimpleShape,
                                             /* withPrimitiveBlender= */ false,
                                             Coverage::kSingleChannel,
@@ -377,7 +363,6 @@
 private:
     void onCreatePipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const RenderPassDesc& renderPassDesc,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
 
@@ -394,7 +379,6 @@
             sparse.setBlendModes(kBlendModes);
 
             sparse.priv().buildCombinations(keyContext,
-                                            gatherer,
                                             DrawTypeFlags::kSimpleShape,
                                             /* withPrimitiveBlender= */ false,
                                             Coverage::kSingleChannel,
@@ -410,7 +394,6 @@
             linear.setBlendModes(kBlendModes);
 
             linear.priv().buildCombinations(keyContext,
-                                            gatherer,
                                             DrawTypeFlags::kSimpleShape,
                                             /* withPrimitiveBlender= */ false,
                                             Coverage::kSingleChannel,
diff --git a/src/gpu/graphite/precompile/PrecompileImageFiltersPriv.h b/src/gpu/graphite/precompile/PrecompileImageFiltersPriv.h
index 2192c9b..9e5abd1 100644
--- a/src/gpu/graphite/precompile/PrecompileImageFiltersPriv.h
+++ b/src/gpu/graphite/precompile/PrecompileImageFiltersPriv.h
@@ -19,7 +19,6 @@
 
     // Used by both the BlurMaskFilter and the BlurImageFilter
     void CreateBlurImageFilterPipelines(const KeyContext&,
-                                        PipelineDataGatherer*,
                                         const RenderPassDesc&,
                                         const PaintOptionsPriv::ProcessCombination&);
 
diff --git a/src/gpu/graphite/precompile/PrecompileImageShader.h b/src/gpu/graphite/precompile/PrecompileImageShader.h
index e390f0f..56d125c 100644
--- a/src/gpu/graphite/precompile/PrecompileImageShader.h
+++ b/src/gpu/graphite/precompile/PrecompileImageShader.h
@@ -87,10 +87,7 @@
 
     int numIntrinsicCombinations() const override;
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override;
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override;
 };
 
 } // namespace skgpu::graphite
diff --git a/src/gpu/graphite/precompile/PrecompileMaskFilter.cpp b/src/gpu/graphite/precompile/PrecompileMaskFilter.cpp
index 13b73ae..c5f536e 100644
--- a/src/gpu/graphite/precompile/PrecompileMaskFilter.cpp
+++ b/src/gpu/graphite/precompile/PrecompileMaskFilter.cpp
@@ -25,10 +25,7 @@
 // The PrecompileMaskFilter-derived classes do not use the PrecompileBase::addToKey virtual since
 // they, in general, do not themselves contribute to a given SkPaint/Pipeline but, rather,
 // create separate SkPaints/Pipelines from whole cloth (in createPipelines).
-void PrecompileMaskFilter::addToKey(const KeyContext& keyContext,
-                                    PaintParamsKeyBuilder* builder,
-                                    PipelineDataGatherer* gatherer,
-                                    int desiredCombination) const {
+void PrecompileMaskFilter::addToKey(const KeyContext& keyContext, int desiredCombination) const {
     SkASSERT(false);
 }
 
@@ -42,7 +39,6 @@
 private:
     void createPipelines(
             const KeyContext& keyContext,
-            PipelineDataGatherer* gatherer,
             const PaintOptions& paintOptions,
             const RenderPassDesc& renderPassDescIn,
             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
@@ -64,7 +60,7 @@
                 skgpu::Swizzle("a000"),
                 caps->getDstReadStrategy());
 
-        PrecompileImageFiltersPriv::CreateBlurImageFilterPipelines(keyContext, gatherer,
+        PrecompileImageFiltersPriv::CreateBlurImageFilterPipelines(keyContext,
                                                                    coverageRenderPassDesc,
                                                                    processCombination);
 
@@ -78,7 +74,6 @@
             restoreOptions.setMaskFilters({});
             restoreOptions.priv().buildCombinations(
                     keyContext,
-                    gatherer,
                     static_cast<DrawTypeFlags>(InternalDrawTypeFlags::kCoverageMask),
                     /* withPrimitiveBlender= */ false,
                     Coverage::kSingleChannel,
@@ -97,7 +92,6 @@
 
             coverageOptions.priv().buildCombinations(
                     keyContext,
-                    gatherer,
                     DrawTypeFlags::kAnalyticRRect,
                     /* withPrimitiveBlender= */ false,
                     Coverage::kSingleChannel,
diff --git a/src/gpu/graphite/precompile/PrecompileRuntimeEffect.cpp b/src/gpu/graphite/precompile/PrecompileRuntimeEffect.cpp
index 06c5432..86714c2 100644
--- a/src/gpu/graphite/precompile/PrecompileRuntimeEffect.cpp
+++ b/src/gpu/graphite/precompile/PrecompileRuntimeEffect.cpp
@@ -113,17 +113,14 @@
 private:
     int numChildCombinations() const override { return fNumChildCombinations; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
 
         SkASSERT(desiredCombination < this->numCombinations());
 
         SkSpan<const SkRuntimeEffect::Child> childInfo = fEffect->children();
 
-        if (!RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { fEffect })) {
-            RuntimeEffectBlock::AddNoOpEffect(keyContext, builder, gatherer, fEffect.get());
+        if (!RuntimeEffectBlock::BeginBlock(keyContext, { fEffect })) {
+            RuntimeEffectBlock::AddNoOpEffect(keyContext, fEffect.get());
             return;
         }
 
@@ -144,7 +141,7 @@
 
             SkASSERT(precompilebase_is_valid_as_child(option.get()));
             if (option) {
-                option->priv().addToKey(childContext, builder, gatherer, childOptions);
+                option->priv().addToKey(childContext, childOptions);
             } else {
                 SkASSERT(childOptions == 0);
 
@@ -152,26 +149,26 @@
                 switch (childInfo[rowIndex].type) {
                     case SkRuntimeEffect::ChildType::kShader:
                         // A missing shader returns transparent black
-                        SolidColorShaderBlock::AddBlock(childContext, builder, gatherer,
-                                                        SK_PMColor4fTRANSPARENT);
+                        SolidColorShaderBlock::AddBlock(childContext, SK_PMColor4fTRANSPARENT);
                         break;
 
                     case SkRuntimeEffect::ChildType::kColorFilter:
                         // A "passthrough" shader returns the input color as-is.
-                        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+                        keyContext.paintParamsKeyBuilder()->addBlock(
+                                BuiltInCodeSnippetID::kPriorOutput);
                         break;
 
                     case SkRuntimeEffect::ChildType::kBlender:
                         // A "passthrough" blender performs `blend_src_over(src, dest)`.
-                        AddFixedBlendMode(childContext, builder, gatherer, SkBlendMode::kSrcOver);
+                        AddFixedBlendMode(childContext, SkBlendMode::kSrcOver);
                         break;
                 }
             }
         }
 
-        RuntimeEffectBlock::HandleIntrinsics(keyContext, builder, gatherer, fEffect.get());
+        RuntimeEffectBlock::HandleIntrinsics(keyContext, fEffect.get());
 
-        builder->endBlock();
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     sk_sp<SkRuntimeEffect> fEffect;
diff --git a/src/gpu/graphite/precompile/PrecompileShader.cpp b/src/gpu/graphite/precompile/PrecompileShader.cpp
index 59d0022..a854c22 100644
--- a/src/gpu/graphite/precompile/PrecompileShader.cpp
+++ b/src/gpu/graphite/precompile/PrecompileShader.cpp
@@ -66,14 +66,9 @@
 //--------------------------------------------------------------------------------------------------
 class PrecompileEmptyShader final : public PrecompileShader {
 private:
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
-
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination == 0); // The empty shader only ever has one combination
-
-        builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
+        keyContext.paintParamsKeyBuilder()->addBlock(BuiltInCodeSnippetID::kPriorOutput);
     }
 };
 
@@ -89,15 +84,10 @@
         return true;
     }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
-
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
-
         // The white PMColor is just a placeholder for the actual paint params color
-        SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, SK_PMColor4fWHITE);
+        SolidColorShaderBlock::AddBlock(keyContext, SK_PMColor4fWHITE);
     }
 };
 
@@ -136,10 +126,7 @@
         return fBlenderOptions.numCombinations() * fNumDstCombos * fNumSrcCombos;
     }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numCombinations());
 
         const int desiredDstCombination = desiredCombination % fNumDstCombos;
@@ -155,30 +142,27 @@
         if (blender->priv().asBlendMode()) {
             // Coefficient and HSLC blends, and other fixed SkBlendMode blenders use the
             // BlendCompose block to organize the children.
-            BlendComposeBlock::BeginBlock(keyContext, builder, gatherer);
+            BlendComposeBlock::BeginBlock(keyContext);
         } else {
             // Runtime blenders are wrapped in the kBlend runtime shader, although functionally
             // it is identical to the BlendCompose snippet.
             const SkRuntimeEffect* blendEffect =
                     GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kBlend);
 
-            RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
-                                           { sk_ref_sp(blendEffect) });
+            RuntimeEffectBlock::BeginBlock(keyContext, { sk_ref_sp(blendEffect) });
         }
 
-        AddToKey<PrecompileShader>(keyContext, builder, gatherer, fSrcOptions,
-                                   desiredSrcCombination);
-        AddToKey<PrecompileShader>(keyContext, builder, gatherer, fDstOptions,
-                                   desiredDstCombination);
+        AddToKey<PrecompileShader>(keyContext, fSrcOptions, desiredSrcCombination);
+        AddToKey<PrecompileShader>(keyContext, fDstOptions, desiredDstCombination);
 
         if (blender->priv().asBlendMode()) {
             SkASSERT(blenderCombination == 0);
-            AddBlendMode(keyContext, builder, gatherer, *blender->priv().asBlendMode());
+            AddBlendMode(keyContext, *blender->priv().asBlendMode());
         } else {
-            blender->priv().addToKey(keyContext, builder, gatherer, blenderCombination);
+            blender->priv().addToKey(keyContext, blenderCombination);
         }
 
-        builder->endBlock();  // BlendComposeBlock or RuntimeEffectBlock
+        keyContext.paintParamsKeyBuilder()->endBlock();  // BlendComposeBlock or RuntimeEffectBlock
     }
 
     PrecompileBlenderList fBlenderOptions;
@@ -219,10 +203,7 @@
         return fNumShaderCombos;
     }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < fNumShaderCombos);
 
         constexpr SkRect kIgnored { 0, 0, 256, 256 }; // ignored bc we're precompiling
@@ -230,9 +211,9 @@
         // TODO: update CoordClampShaderBlock so this is optional
         CoordClampShaderBlock::CoordClampData data(kIgnored);
 
-        CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
-            AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders, desiredCombination);
-        builder->endBlock();
+        CoordClampShaderBlock::BeginBlock(keyContext, data);
+            AddToKey<PrecompileShader>(keyContext, fShaders, desiredCombination);
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     std::vector<sk_sp<PrecompileShader>> fShaders;
@@ -273,10 +254,7 @@
     return fColorInfos.size() * (fTileModes.size() + fNumExtraSamplingTilingCombos);
 }
 
-void PrecompileImageShader::addToKey(const KeyContext& keyContext,
-                                     PaintParamsKeyBuilder* builder,
-                                     PipelineDataGatherer* gatherer,
-                                     int desiredCombination) const {
+void PrecompileImageShader::addToKey(const KeyContext& keyContext, int desiredCombination) const {
     SkASSERT(this->numChildCombinations() == 1);
     SkASSERT(desiredCombination < this->numIntrinsicCombinations());
 
@@ -342,35 +320,32 @@
                 dstColorSpace, dstAT);
 
         if (alphaOnly) {
-            Blend(keyContext, builder, gatherer,
+            Blend(keyContext,
                   /* addBlendToKey= */ [&] () -> void {
-                      AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kDstIn);
+                      AddFixedBlendMode(keyContext, SkBlendMode::kDstIn);
                   },
                   /* addSrcToKey= */ [&] () -> void {
-                      Compose(keyContext, builder, gatherer,
+                      Compose(keyContext,
                               /* addInnerToKey= */ [&]() -> void {
-                                  ImageShaderBlock::AddBlock(keyContext, builder, gatherer,
-                                                             imgData);
+                                  ImageShaderBlock::AddBlock(keyContext, imgData);
                               },
                               /* addOuterToKey= */ [&]() -> void {
-                                  ColorSpaceTransformBlock::AddBlock(keyContext, builder,
-                                                                     gatherer, colorXformData);
+                                  ColorSpaceTransformBlock::AddBlock(keyContext, colorXformData);
                               });
                   },
                   /* addDstToKey= */ [&]() -> void {
-                      RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
+                      RGBPaintColorBlock::AddBlock(keyContext);
                   });
             return;
         }
     }
 
-    Compose(keyContext, builder, gatherer,
+    Compose(keyContext,
             /* addInnerToKey= */ [&]() -> void {
-                ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
+                ImageShaderBlock::AddBlock(keyContext, imgData);
             },
             /* addOuterToKey= */ [&]() -> void {
-                ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
-                                                   colorXformData);
+                ColorSpaceTransformBlock::AddBlock(keyContext, colorXformData);
             });
 }
 
@@ -447,10 +422,7 @@
         return fNumTilingModes * fColorInfos.size();
     }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numIntrinsicCombinations());
 
         int desiredTiling = desiredCombination % fNumTilingModes;
@@ -505,13 +477,12 @@
                 colorInfo.colorSpace(), colorInfo.alphaType(),
                 dstColorSpace, colorInfo.alphaType());
 
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
+                    YUVImageShaderBlock::AddBlock(keyContext, imgData);
                 },
                 /* addOuterToKey= */ [&]() -> void {
-                    ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
-                                                       colorXformData);
+                    ColorSpaceTransformBlock::AddBlock(keyContext, colorXformData);
                 });
     }
 
@@ -538,10 +509,7 @@
     PrecompilePerlinNoiseShader() {}
 
 private:
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
 
         SkASSERT(desiredCombination == 0); // The Perlin noise shader only ever has one combination
 
@@ -549,7 +517,7 @@
         static const PerlinNoiseShaderBlock::PerlinNoiseData kIgnoredNoiseData(
                 PerlinNoiseShaderBlock::Type::kFractalNoise, { 0.0f, 0.0f }, 2, {1, 1});
 
-        PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, kIgnoredNoiseData);
+        PerlinNoiseShaderBlock::AddBlock(keyContext, kIgnoredNoiseData);
     }
 
 };
@@ -615,10 +583,7 @@
 
     int numIntrinsicCombinations() const override { return fNumStopVariants; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(this->numChildCombinations() == 1);
         SkASSERT(desiredCombination < fNumStopVariants);
 
@@ -640,12 +605,12 @@
                 intermediateCS.get(), kPremul_SkAlphaType,
                 dstCS, kPremul_SkAlphaType);
 
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
+                    GradientShaderBlocks::AddBlock(keyContext, gradData);
                 },
                 /* addOuterToKey= */  [&]() -> void {
-                    ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
+                    ColorSpaceTransformBlock::AddBlock(keyContext, csData);
                 });
     }
 
@@ -773,10 +738,7 @@
 
     int numChildCombinations() const override { return fNumWrappedCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numCombinations());
 
         int desiredLMCombination, desiredWrappedCombination;
@@ -797,14 +759,13 @@
             }
             LocalMatrixShaderBlock::LMShaderData lmShaderData(matrix);
 
-            LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, matrix);
+            LocalMatrixShaderBlock::BeginBlock(keyContext, matrix);
         }
 
-        AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped,
-                                   desiredWrappedCombination);
+        AddToKey<PrecompileShader>(keyContext, fWrapped, desiredWrappedCombination);
 
         if (desiredLMCombination == kWithLocalMatrix) {
-            builder->endBlock();
+            keyContext.paintParamsKeyBuilder()->endBlock();
         }
     }
 
@@ -867,23 +828,19 @@
 private:
     int numChildCombinations() const override { return fNumShaderCombos * fNumColorFilterCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numCombinations());
 
         int desiredShaderCombination = desiredCombination % fNumShaderCombos;
         int desiredColorFilterCombination = desiredCombination / fNumShaderCombos;
         SkASSERT(desiredColorFilterCombination < fNumColorFilterCombos);
 
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
-                                               desiredShaderCombination);
+                    AddToKey<PrecompileShader>(keyContext, fShaders, desiredShaderCombination);
                 },
                 /* addOuterToKey= */ [&]() -> void {
-                    AddToKey<PrecompileColorFilter>(keyContext, builder, gatherer, fColorFilters,
+                    AddToKey<PrecompileColorFilter>(keyContext, fColorFilters,
                                                     desiredColorFilterCombination);
                 });
     }
@@ -916,10 +873,7 @@
 private:
     int numChildCombinations() const override { return fNumShaderCombos * fColorSpaces.size(); }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numCombinations());
 
         int desiredShaderCombination = desiredCombination % fNumShaderCombos;
@@ -937,15 +891,14 @@
         SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
         KeyContextWithColorInfo workingContext(keyContext, workingInfo);
 
-        Compose(keyContext, builder, gatherer,
+        Compose(keyContext,
                 /* addInnerToKey= */ [&]() -> void {
-                    AddToKey<PrecompileShader>(workingContext, builder, gatherer, fShaders,
-                                               desiredShaderCombination);
+                    AddToKey<PrecompileShader>(workingContext, fShaders, desiredShaderCombination);
                 },
                 /* addOuterToKey= */ [&]() -> void {
                     ColorSpaceTransformBlock::ColorSpaceTransformData data(
                             workingCS.get(), dstAT, dstCS.get(), dstAT);
-                    ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
+                    ColorSpaceTransformBlock::AddBlock(keyContext, data);
                 });
     }
 
@@ -988,19 +941,16 @@
 private:
     int numChildCombinations() const override { return fNumWrappedCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < fNumWrappedCombos);
 
         LocalMatrixShaderBlock::LMShaderData kIgnoredLMShaderData(SkMatrix::I());
 
-        LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, kIgnoredLMShaderData);
+        LocalMatrixShaderBlock::BeginBlock(keyContext, kIgnoredLMShaderData);
 
-            AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped, desiredCombination);
+        AddToKey<PrecompileShader>(keyContext, fWrapped, desiredCombination);
 
-        builder->endBlock();
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     std::vector<sk_sp<PrecompileShader>> fWrapped;
@@ -1027,10 +977,7 @@
 
     int numChildCombinations() const override { return fNumWrappedCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numCombinations());
 
         using namespace SkKnownRuntimeEffects;
@@ -1052,9 +999,9 @@
 
         KeyContextForRuntimeEffect childContext(keyContext, effect, /*child=*/0);
 
-        RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
-            fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
-        builder->endBlock();
+        RuntimeEffectBlock::BeginBlock(keyContext, { sk_ref_sp(effect) });
+            fWrapped->priv().addToKey(childContext, desiredWrappedCombination);
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     sk_sp<PrecompileShader> fWrapped;
@@ -1090,10 +1037,7 @@
 
     int numChildCombinations() const override { return fNumWrappedCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
 
         int desiredTextureCombination = 0;
 
@@ -1119,17 +1063,16 @@
 
         KeyContextForRuntimeEffect childContext(keyContext, effect, /*child=*/0);
 
-        RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
-            fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
+        RuntimeEffectBlock::BeginBlock(keyContext, { sk_ref_sp(effect) });
+            fWrapped->priv().addToKey(childContext, desiredWrappedCombination);
             if (stableKey != SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms) {
                 SkASSERT(effect->children().size() == 2);
                 KeyContextForRuntimeEffect kernelContext(keyContext, effect, /*child=*/1);
-                fRawImageShader->priv().addToKey(kernelContext, builder, gatherer,
-                                                 desiredTextureCombination);
+                fRawImageShader->priv().addToKey(kernelContext, desiredTextureCombination);
             } else {
                 SkASSERT(effect->children().size() == 1);
             }
-        builder->endBlock();
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     sk_sp<PrecompileShader> fWrapped;
@@ -1158,10 +1101,7 @@
 private:
     int numChildCombinations() const override { return fNumWrappedCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < fNumWrappedCombos);
 
         const SkRuntimeEffect* effect = GetKnownRuntimeEffect(fStableKey);
@@ -1169,9 +1109,9 @@
 
         KeyContextForRuntimeEffect childContext(keyContext, effect, /*child=*/0);
 
-        RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
-            fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
-        builder->endBlock();
+        RuntimeEffectBlock::BeginBlock(keyContext, { sk_ref_sp(effect) });
+            fWrapped->priv().addToKey(childContext, desiredCombination);
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     sk_sp<PrecompileShader> fWrapped;
@@ -1205,10 +1145,7 @@
 private:
     int numChildCombinations() const override { return fNumDisplacementCombos * fNumColorCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < this->numChildCombinations());
 
         const int desiredDisplacementCombination = desiredCombination % fNumDisplacementCombos;
@@ -1222,12 +1159,10 @@
         KeyContextForRuntimeEffect displContext(keyContext, effect, /*child=*/0);
         KeyContextForRuntimeEffect colorContext(keyContext, effect, /*child=*/1);
 
-        RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
-            fDisplacement->priv().addToKey(displContext, builder, gatherer,
-                                           desiredDisplacementCombination);
-            fColor->priv().addToKey(colorContext, builder, gatherer,
-                                    desiredColorCombination);
-        builder->endBlock();
+        RuntimeEffectBlock::BeginBlock(keyContext, { sk_ref_sp(effect) });
+            fDisplacement->priv().addToKey(displContext, desiredDisplacementCombination);
+            fColor->priv().addToKey(colorContext, desiredColorCombination);
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     sk_sp<PrecompileShader> fDisplacement;
@@ -1253,10 +1188,7 @@
 private:
     int numChildCombinations() const override { return fNumWrappedCombos; }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const override {
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const override {
         SkASSERT(desiredCombination < fNumWrappedCombos);
 
         const SkRuntimeEffect* normalEffect =
@@ -1269,13 +1201,11 @@
         KeyContextForRuntimeEffect lightingContext(keyContext, lightingEffect, /*child=*/0);
         KeyContextForRuntimeEffect normalContext(lightingContext, normalEffect, /*child=*/0);
 
-        RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
-                                       { sk_ref_sp(lightingEffect) });
-            RuntimeEffectBlock::BeginBlock(lightingContext, builder, gatherer,
-                                           { sk_ref_sp(normalEffect) });
-                fWrapped->priv().addToKey(normalContext, builder, gatherer, desiredCombination);
-            builder->endBlock();
-        builder->endBlock();
+        RuntimeEffectBlock::BeginBlock(keyContext, { sk_ref_sp(lightingEffect) });
+            RuntimeEffectBlock::BeginBlock(lightingContext, { sk_ref_sp(normalEffect) });
+                fWrapped->priv().addToKey(normalContext, desiredCombination);
+            keyContext.paintParamsKeyBuilder()->endBlock();
+        keyContext.paintParamsKeyBuilder()->endBlock();
     }
 
     sk_sp<PrecompileShader> fWrapped;
diff --git a/src/gpu/graphite/precompile/PrecompileShaderPriv.h b/src/gpu/graphite/precompile/PrecompileShaderPriv.h
index 109bbd3..802698b 100644
--- a/src/gpu/graphite/precompile/PrecompileShaderPriv.h
+++ b/src/gpu/graphite/precompile/PrecompileShaderPriv.h
@@ -30,11 +30,8 @@
 
     int numCombinations() const { return fPrecompileShader->numCombinations(); }
 
-    void addToKey(const KeyContext& keyContext,
-                  PaintParamsKeyBuilder* builder,
-                  PipelineDataGatherer* gatherer,
-                  int desiredCombination) const {
-        fPrecompileShader->addToKey(keyContext, builder, gatherer, desiredCombination);
+    void addToKey(const KeyContext& keyContext, int desiredCombination) const {
+        fPrecompileShader->addToKey(keyContext, desiredCombination);
     }
 
 private:
diff --git a/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp b/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp
index d105ee89..45b67ee 100644
--- a/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp
+++ b/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp
@@ -22,10 +22,10 @@
         return nullptr;
     }
 
-    sk_sp<PrecompileImageShader> shader(new PrecompileImageShader(shaderFlags,
+    sk_sp<PrecompileImageShader> shader = sk_make_sp<PrecompileImageShader>(shaderFlags,
                                                                   colorInfos,
                                                                   tileModes,
-                                                                  /* raw= */false));
+                                                                  /* raw= */false);
 
     shader->setImmutableSamplerInfo(
             VulkanYcbcrConversion::ToImmutableSamplerInfo(YCbCrConversionInfo));
diff --git a/tests/graphite/precompile/CombinationBuilderTest.cpp b/tests/graphite/precompile/CombinationBuilderTest.cpp
index 71b2d4e..aa0f02d 100644
--- a/tests/graphite/precompile/CombinationBuilderTest.cpp
+++ b/tests/graphite/precompile/CombinationBuilderTest.cpp
@@ -48,10 +48,8 @@
 static constexpr int kExpectedRawImageCombos = 10;
 static constexpr int kExpectedSolidColorCombos = 1;
 
-
 // A default kSrcOver blend mode will be supplied if no other blend options are added
 void no_blend_mode_option_test(const KeyContext& keyContext,
-                               PipelineDataGatherer* gatherer,
                                const RenderPassDesc& renderPassDesc,
                                skiatest::Reporter* reporter) {
     PaintOptions paintOptions;
@@ -61,7 +59,6 @@
 
     std::vector<UniquePaintParamsID> precompileIDs;
     paintOptions.priv().buildCombinations(keyContext,
-                                          gatherer,
                                           DrawTypeFlags::kNone,
                                           /* withPrimitiveBlender= */ false,
                                           Coverage::kNone,
@@ -80,7 +77,6 @@
 // This test checks that the 'PaintOptions::numCombinations' method and the number actually
 // generated by 'buildCombinations' agree with the expected number of combinations.
 void run_test(const KeyContext& keyContext,
-              PipelineDataGatherer* gatherer,
               const RenderPassDesc& renderPassDesc,
               skiatest::Reporter* reporter,
               const PaintOptions& paintOptions,
@@ -91,7 +87,6 @@
 
     std::vector<UniquePaintParamsID> precompileIDs;
     paintOptions.priv().buildCombinations(keyContext,
-                                          gatherer,
                                           DrawTypeFlags::kNone,
                                           /* withPrimitiveBlender= */ false,
                                           Coverage::kNone,
@@ -108,7 +103,6 @@
 }
 
 void big_test(const KeyContext& keyContext,
-              PipelineDataGatherer* gatherer,
               const RenderPassDesc& renderPassDesc,
               skiatest::Reporter* reporter) {
 
@@ -174,7 +168,6 @@
 
     std::vector<UniquePaintParamsID> precompileIDs;
     paintOptions.priv().buildCombinations(keyContext,
-                                          gatherer,
                                           DrawTypeFlags::kNone,
                                           /* withPrimitiveBlender= */ false,
                                           Coverage::kNone,
@@ -226,7 +219,6 @@
 }
 
 void runtime_effect_test(const KeyContext& keyContext,
-                         PipelineDataGatherer* gatherer,
                          const RenderPassDesc& renderPassDesc,
                          skiatest::Reporter* reporter) {
     // paintOptions (64 = 4*4*4)
@@ -341,7 +333,6 @@
 
     std::vector<UniquePaintParamsID> precompileIDs;
     paintOptions.priv().buildCombinations(keyContext,
-                                          gatherer,
                                           DrawTypeFlags::kNone,
                                           /* withPrimitiveBlender= */ false,
                                           Coverage::kNone,
@@ -359,7 +350,6 @@
 
 // Exercise all the PrecompileBlenders factories
 void blend_subtest(const KeyContext& keyContext,
-                   PipelineDataGatherer* gatherer,
                    const RenderPassDesc& renderPassDesc,
                    skiatest::Reporter* reporter) {
     // The BlendMode PrecompileBlender only ever has 1 combination
@@ -367,8 +357,7 @@
         PaintOptions paintOptions;
         paintOptions.setBlenders({ PrecompileBlenders::Mode(SkBlendMode::kColorDodge) });
 
-        run_test(keyContext, gatherer, renderPassDesc,
-                 reporter, paintOptions, /* expectedNumOptions= */ 1);
+        run_test(keyContext, renderPassDesc, reporter, paintOptions, /* expectedNumOptions= */ 1);
     }
 
     // Specifying the BlendMode PrecompileBlender by SkBlendMode should also only ever
@@ -377,8 +366,7 @@
         PaintOptions paintOptions;
         paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
 
-        run_test(keyContext, gatherer, renderPassDesc,
-                 reporter, paintOptions, /* expectedNumOptions= */ 1);
+        run_test(keyContext, renderPassDesc, reporter, paintOptions, /* expectedNumOptions= */ 1);
     }
 
     // The Arithmetic PrecompileBlender only ever has 1 combination
@@ -386,22 +374,19 @@
         PaintOptions paintOptions;
         paintOptions.setBlenders({ PrecompileBlenders::Arithmetic() });
 
-        run_test(keyContext, gatherer, renderPassDesc,
-                 reporter, paintOptions, /* expectedNumOptions= */ 1);
+        run_test(keyContext, renderPassDesc, reporter, paintOptions, /* expectedNumOptions= */ 1);
     }
 }
 
 // Exercise all the PrecompileShaders factories
 void shader_subtest(const KeyContext& keyContext,
-                    PipelineDataGatherer* gatherer,
                     const RenderPassDesc& renderPassDesc,
                     skiatest::Reporter* reporter) {
     {
         PaintOptions paintOptions;
         paintOptions.setShaders({ PrecompileShaders::Empty() });
 
-        run_test(keyContext, gatherer, renderPassDesc,
-                 reporter, paintOptions, /* expectedNumOptions= */ 1);
+        run_test(keyContext, renderPassDesc, reporter, paintOptions, /* expectedNumOptions= */ 1);
     }
 
     // The solid color shader only ever generates one combination. Because it is constant
@@ -411,7 +396,7 @@
         PaintOptions paintOptions;
         paintOptions.setShaders({ PrecompileShaders::Color() });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedSolidColorCombos);
     }
 
@@ -435,7 +420,7 @@
                                            { PrecompileShaders::Color() },
                                            { PrecompileShaders::MakeFractalNoise() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ 4 *  // Porter-Duff, HSLC, Screen, Darken
                                            kExpectedSolidColorCombos *
                                            kExpectedPerlinNoiseCombos);
@@ -448,7 +433,7 @@
         PaintOptions paintOptions;
         paintOptions.setShaders({ PrecompileShaders::CoordClamp({ PrecompileShaders::Image() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedImageCombos);
     }
 
@@ -458,7 +443,7 @@
         PaintOptions paintOptions;
         paintOptions.setShaders({ PrecompileShaders::RawImage() });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedRawImageCombos);
     }
 
@@ -468,7 +453,7 @@
         paintOptions.setShaders({ PrecompileShaders::MakeFractalNoise(),
                                   PrecompileShaders::MakeTurbulence() });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedPerlinNoiseCombos + kExpectedPerlinNoiseCombos);
     }
 
@@ -480,7 +465,7 @@
                                   PrecompileShaders::TwoPointConicalGradient(),
                                   PrecompileShaders::SweepGradient() });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedGradientCombos + kExpectedGradientCombos +
                                            kExpectedGradientCombos + kExpectedGradientCombos);
     }
@@ -491,7 +476,7 @@
         PaintOptions paintOptions;
         paintOptions.setShaders({ PrecompileShaders::Picture() });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedPictureCombos);
     }
 
@@ -502,7 +487,7 @@
         paintOptions.setShaders(
                 { PrecompileShaders::LocalMatrix({ PrecompileShaders::LinearGradient() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedGradientCombos);
     }
 
@@ -513,7 +498,7 @@
                 { PrecompileShaders::ColorFilter({ PrecompileShaders::LinearGradient() },
                                                  { PrecompileColorFilters::Blend() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedGradientCombos * kExpectedBlendCFCombos);
     }
 
@@ -523,7 +508,7 @@
                 { PrecompileShaders::WorkingColorSpace({ PrecompileShaders::LinearGradient() },
                                                        { SkColorSpace::MakeSRGBLinear() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ kExpectedGradientCombos *
                                            1 /* only one colorSpace */);
     }
@@ -534,7 +519,6 @@
 // color filters only ever have one combination. The Compose and Lerp color filters also just
 // simply generate the cross product of their children.
 void colorfilter_subtest(const KeyContext& keyContext,
-                         PipelineDataGatherer* gatherer,
                          const RenderPassDesc& renderPassDesc,
                          skiatest::Reporter* reporter) {
 
@@ -551,14 +535,14 @@
                     { PrecompileColorFilters::Table(), PrecompileColorFilters::Lighting() },
                     { PrecompileColorFilters::HighContrast(), PrecompileColorFilters::Luma() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
+        run_test(keyContext, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
     }
 
     {
         PaintOptions paintOptions;
         paintOptions.setColorFilters({ PrecompileColorFilters::Blend() });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  kExpectedBlendCFCombos);
     }
 
@@ -568,7 +552,7 @@
                                        PrecompileColorFilters::HSLAMatrix() });
 
         // HSLAMatrix and Matrix map to the same color filter
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  kExpectedMatrixCFCombos + kExpectedMatrixCFCombos);
     }
 
@@ -578,7 +562,7 @@
                                        PrecompileColorFilters::SRGBToLinearGamma() });
 
         // LinearToSRGB and SRGBToLinear both map to the colorspace colorfilter
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
+        run_test(keyContext, renderPassDesc, reporter, paintOptions,
                  kExpectedColorSpaceCFCombos + kExpectedColorSpaceCFCombos);
     }
 
@@ -594,7 +578,7 @@
                     { PrecompileColorFilters::Matrix(), PrecompileColorFilters::Luma() },
                     { PrecompileColorFilters::Blend(), PrecompileColorFilters::Overdraw() }) });
 
-        run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
+        run_test(keyContext, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
     }
 }
 
@@ -607,9 +591,11 @@
     auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
 
     SkColorInfo ci(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
-    KeyContext keyContext(context->priv().caps(), dict, rtEffectDict.get(), ci);
-
+    FloatStorageManager floatStorageManager;
+    PaintParamsKeyBuilder builder(dict);
     PipelineDataGatherer gatherer(Layout::kMetal);
+    KeyContext keyContext(context->priv().caps(), &floatStorageManager, &builder, &gatherer, dict,
+                          rtEffectDict.get(), ci);
 
     RenderPassDesc unusedRenderPassDesc;
 
@@ -618,17 +604,17 @@
     {
         PaintOptions paintOptions;
 
-        run_test(keyContext, &gatherer, unusedRenderPassDesc, reporter, paintOptions,
+        run_test(keyContext, unusedRenderPassDesc, reporter, paintOptions,
                  /* expectedNumOptions= */ 1);
     }
 
-    blend_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
-    shader_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
-    colorfilter_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
+    blend_subtest(keyContext, unusedRenderPassDesc, reporter);
+    shader_subtest(keyContext, unusedRenderPassDesc, reporter);
+    colorfilter_subtest(keyContext, unusedRenderPassDesc, reporter);
 
-    no_blend_mode_option_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
-    big_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
-    runtime_effect_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
+    no_blend_mode_option_test(keyContext, unusedRenderPassDesc, reporter);
+    big_test(keyContext, unusedRenderPassDesc, reporter);
+    runtime_effect_test(keyContext, unusedRenderPassDesc, reporter);
 }
 
 #endif // SK_GRAPHITE
diff --git a/tests/graphite/precompile/PaintParamsKeyTest.cpp b/tests/graphite/precompile/PaintParamsKeyTest.cpp
index 22b3c16..58fe237 100644
--- a/tests/graphite/precompile/PaintParamsKeyTest.cpp
+++ b/tests/graphite/precompile/PaintParamsKeyTest.cpp
@@ -341,8 +341,14 @@
              "ClipType clipType = %s;\n"
              "DrawTypeFlags drawTypeFlags = %s;\n"
              "//-----------------------\n",
-             label, seed,
-             to_str(s), to_str(bm), to_str(cf), to_str(mf), to_str(imageFilter), to_str(clipType),
+             label,
+             seed,
+             to_str(s),
+             to_str(bm),
+             to_str(cf),
+             to_str(mf),
+             to_str(imageFilter),
+             to_str(clipType),
              to_str(drawTypeFlags));
 }
 
@@ -1027,10 +1033,10 @@
 }
 
 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_arithmetic_blender() {
-    sk_sp<SkBlender> b = SkBlenders::Arithmetic(/* k1= */ 0.5,
-                                                /* k2= */ 0.5,
-                                                /* k3= */ 0.5,
-                                                /* k4= */ 0.5,
+    sk_sp<SkBlender> b = SkBlenders::Arithmetic(/* k1= */ 0.5f,
+                                                /* k2= */ 0.5f,
+                                                /* k3= */ 0.5f,
+                                                /* k4= */ 0.5f,
                                                 /* enforcePremul= */ true);
     sk_sp<PrecompileBlender> o = PrecompileBlenders::Arithmetic();
 
@@ -1914,17 +1920,6 @@
 
 }
 
-KeyContext create_key_context(Context* context, RuntimeEffectDictionary* rtDict) {
-    ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
-
-    SkColorInfo destColorInfo = SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType,
-                                            SkColorSpace::MakeSRGB());
-    return KeyContext(context->priv().caps(),
-                      dict,
-                      rtDict,
-                      destColorInfo);
-}
-
 // This subtest compares the output of ExtractPaintData (applied to an SkPaint) and
 // PaintOptions::buildCombinations (applied to a matching PaintOptions). The actual check
 // performed is that the UniquePaintParamsID created by ExtractPaintData is contained in the
@@ -1948,12 +1943,7 @@
                               uint32_t seed,
                               SkRandom* rand,
                               bool verbose) {
-
-    ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
-
-    PaintParamsKeyBuilder builder(dict);
     PipelineDataGatherer paramsGatherer(Layout::kMetal);
-    PipelineDataGatherer precompileGatherer(Layout::kMetal);
 
     for (bool withPrimitiveBlender: {false, true}) {
 
@@ -2001,8 +1991,9 @@
         SkDEBUGCODE(paramsGatherer.resetForDraw());
         UniquePaintParamsID paintID =
                 ExtractPaintData(recorder,
+                                 precompileKeyContext.floatStorageManager(),
                                  &paramsGatherer,
-                                 &builder,
+                                 precompileKeyContext.paintParamsKeyBuilder(),
                                  Layout::kMetal,
                                  {},
                                  PaintParams(paint,
@@ -2018,7 +2009,6 @@
 
         std::vector<UniquePaintParamsID> precompileIDs;
         paintOptions.priv().buildCombinations(precompileKeyContext,
-                                              &precompileGatherer,
                                               hasAnalyticClip ? DrawTypeFlags::kAnalyticClip
                                                               : DrawTypeFlags::kNone,
                                               withPrimitiveBlender,
@@ -2054,11 +2044,11 @@
 #ifdef SK_DEBUG
         if (result == precompileIDs.end()) {
             SkDebugf("From paint: ");
-            dict->dump(paintID);
+            precompileKeyContext.dict()->dump(paintID);
 
             SkDebugf("From combination builder [%d]:", static_cast<int>(precompileIDs.size()));
             for (auto iter: precompileIDs) {
-                dict->dump(iter);
+                precompileKeyContext.dict()->dump(iter);
             }
         }
 #endif
@@ -2185,9 +2175,9 @@
     // a SkCanvas::clipShader call).
     paintOptions.priv().setClipShaders({clipShaderOption});
 
-    extract_vs_build_subtest(reporter, context, testContext, precompileKeyContext, recorder.get(),
-                             paint, paintOptions, s, bm, cf, mf, imageFilter, clipType,
-                             clipShader, dt, seed, &rand, verbose);
+    extract_vs_build_subtest(reporter, context, testContext, precompileKeyContext,
+                             recorder.get(), paint, paintOptions, s, bm, cf, mf, imageFilter,
+                             clipType, clipShader, dt, seed, &rand, verbose);
     precompile_vs_real_draws_subtest(reporter, context, precompileContext,
                                      testContext, recorder.get(),
                                      paint, paintOptions, clipType, clipShader, dt, verbose);
@@ -2204,6 +2194,20 @@
     std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
     std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
 
+    FloatStorageManager floatStorageManager;
+    ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
+    PaintParamsKeyBuilder builder(dict);
+    PipelineDataGatherer gatherer(Layout::kMetal);
+    KeyContext keyContext(context->priv().caps(),
+                          &floatStorageManager,
+                          &builder,
+                          &gatherer,
+                          dict,
+                          rtDict.get(),
+                          SkColorInfo(kRGBA_8888_SkColorType,
+                                      kPremul_SkAlphaType,
+                                      SkColorSpace::MakeSRGB()));
+
 #if 1
     //----------------------
     uint32_t seed = std::time(nullptr) % std::numeric_limits<uint32_t>::max();
@@ -2239,7 +2243,7 @@
              context,
              precompileContext.get(),
              testContext,
-             create_key_context(context, rtDict.get()),
+             keyContext,
              shaderType,
              blenderType,
              colorFilterType,
@@ -2267,7 +2271,19 @@
     std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
     std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
 
-    KeyContext precompileKeyContext(create_key_context(context, rtDict.get()));
+    FloatStorageManager floatStorageManager;
+    ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
+    PaintParamsKeyBuilder builder(dict);
+    PipelineDataGatherer gatherer(Layout::kMetal);
+    KeyContext precompileKeyContext(context->priv().caps(),
+                                    &floatStorageManager,
+                                    &builder,
+                                    &gatherer,
+                                    dict,
+                                    rtDict.get(),
+                                    SkColorInfo(kRGBA_8888_SkColorType,
+                                                kPremul_SkAlphaType,
+                                                SkColorSpace::MakeSRGB()));
 
     ShaderType shaders[] = {
             ShaderType::kImage,