Add GrRuntimeFPBuilder

Like SkRuntimeShaderBuilder but for internal use for creating FPs.

Currently it requires that the code be a static string so it can
easily make a static SkRuntimeEffect instance for each effect.

Bug: skia:11771

Change-Id: I18148eb33e7d28c804e4a13bcef88c89c06b2c9b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386889
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 409d7eb..a8a0560 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -342,8 +342,6 @@
   "$_src/gpu/effects/generated/GrClampFragmentProcessor.h",
   "$_src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp",
   "$_src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h",
-  "$_src/gpu/effects/generated/GrComposeLerpEffect.cpp",
-  "$_src/gpu/effects/generated/GrComposeLerpEffect.h",
   "$_src/gpu/effects/generated/GrConfigConversionEffect.cpp",
   "$_src/gpu/effects/generated/GrConfigConversionEffect.h",
   "$_src/gpu/effects/generated/GrConstColorProcessor.cpp",
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 58d7f68..2c5bc51 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -187,7 +187,6 @@
   "$_src/gpu/effects/GrCircleEffect.fp",
   "$_src/gpu/effects/GrClampFragmentProcessor.fp",
   "$_src/gpu/effects/GrColorMatrixFragmentProcessor.fp",
-  "$_src/gpu/effects/GrComposeLerpEffect.fp",
   "$_src/gpu/effects/GrConfigConversionEffect.fp",
   "$_src/gpu/effects/GrConstColorProcessor.fp",
   "$_src/gpu/effects/GrDeviceSpaceEffect.fp",
diff --git a/include/effects/SkRuntimeEffect.h b/include/effects/SkRuntimeEffect.h
index 819a794..4248a13 100644
--- a/include/effects/SkRuntimeEffect.h
+++ b/include/effects/SkRuntimeEffect.h
@@ -17,6 +17,7 @@
 
 #include <vector>
 
+class GrFragmentProcessor;
 class GrRecordingContext;
 class SkColorFilter;
 class SkImage;
@@ -96,7 +97,7 @@
                                sk_sp<SkShader> children[],
                                size_t childCount,
                                const SkMatrix* localMatrix,
-                               bool isOpaque);
+                               bool isOpaque) const;
 
     sk_sp<SkImage> makeImage(GrRecordingContext*,
                              sk_sp<SkData> uniforms,
@@ -104,12 +105,12 @@
                              size_t childCount,
                              const SkMatrix* localMatrix,
                              SkImageInfo resultInfo,
-                             bool mipmapped);
+                             bool mipmapped) const;
 
-    sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms);
+    sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms) const;
     sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
                                          sk_sp<SkColorFilter> children[],
-                                         size_t childCount);
+                                         size_t childCount) const;
 
     const SkString& source() const { return fSkSL; }
 
@@ -145,6 +146,14 @@
     static void RegisterFlattenables();
     ~SkRuntimeEffect() override;
 
+#if SK_SUPPORT_GPU
+    // For internal use.
+    std::unique_ptr<GrFragmentProcessor> makeFP(GrRecordingContext*,
+                                                sk_sp<SkData> uniforms,
+                                                std::unique_ptr<GrFragmentProcessor> children[],
+                                                size_t childCount) const;
+#endif
+
 private:
     SkRuntimeEffect(SkString sksl,
                     std::unique_ptr<SkSL::Program> baseProgram,
@@ -184,31 +193,9 @@
     bool   fAllowColorFilter;
 };
 
-/**
- * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
- *
- * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
- *
- * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
- * provides named access to the 'uniform' variables in that block, as well as named access
- * to a list of child shader slots. Usage:
- *
- *   sk_sp<SkRuntimeEffect> effect = ...;
- *   SkRuntimeShaderBuilder builder(effect);
- *   builder.uniform("some_uniform_float")  = 3.14f;
- *   builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
- *   builder.child("some_child_effect")     = mySkImage->makeShader(...);
- *   ...
- *   sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
- *
- * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
- * so can be used as-is or serve as inspiration for other interfaces or binding techniques.
- */
-class SkRuntimeShaderBuilder {
+/** Base class for SkRuntimeShaderBuilder, defined below. */
+template <typename Child> class SkRuntimeEffectBuilder {
 public:
-    SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
-    ~SkRuntimeShaderBuilder();
-
     struct BuilderUniform {
         // Copy 'val' to this variable. No type conversion is performed - 'val' must be same
         // size as expected by the effect. Information about the variable can be queried by
@@ -259,14 +246,21 @@
             return true;
         }
 
-        SkRuntimeShaderBuilder*         fOwner;
+        SkRuntimeEffectBuilder*         fOwner;
         const SkRuntimeEffect::Uniform* fVar;    // nullptr if the variable was not found
     };
 
     struct BuilderChild {
-        BuilderChild& operator=(const sk_sp<SkShader>& val);
+        template <typename C> BuilderChild& operator=(C&& val) {
+            if (fIndex < 0) {
+                SkDEBUGFAIL("Assigning to missing child");
+            } else {
+                fOwner->fChildren[fIndex] = std::forward<C>(val);
+            }
+            return *this;
+        }
 
-        SkRuntimeShaderBuilder* fOwner;
+        SkRuntimeEffectBuilder* fOwner;
         int                     fIndex;  // -1 if the child was not found
     };
 
@@ -275,6 +269,60 @@
     BuilderUniform uniform(const char* name) { return { this, fEffect->findUniform(name) }; }
     BuilderChild child(const char* name) { return { this, fEffect->findChild(name) }; }
 
+protected:
+    explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)
+            : fEffect(std::move(effect))
+            , fUniforms(SkData::MakeUninitialized(fEffect->uniformSize()))
+            , fChildren(fEffect->children().count()) {}
+
+    SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default;
+    SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = delete;
+
+    SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = default;
+    SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete;
+
+    sk_sp<SkData> uniforms() { return fUniforms; }
+    Child* children() { return fChildren.data(); }
+    size_t numChildren() { return fChildren.size(); }
+
+private:
+    void* writableUniformData() {
+        if (!fUniforms->unique()) {
+            fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
+        }
+        return fUniforms->writable_data();
+    }
+
+    sk_sp<SkRuntimeEffect> fEffect;
+    sk_sp<SkData>          fUniforms;
+    std::vector<Child>     fChildren;
+};
+
+/**
+ * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
+ *
+ * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
+ *
+ * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
+ * provides named access to the 'uniform' variables in that block, as well as named access
+ * to a list of child shader slots. Usage:
+ *
+ *   sk_sp<SkRuntimeEffect> effect = ...;
+ *   SkRuntimeShaderBuilder builder(effect);
+ *   builder.uniform("some_uniform_float")  = 3.14f;
+ *   builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
+ *   builder.child("some_child_effect")     = mySkImage->makeShader(...);
+ *   ...
+ *   sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
+ *
+ * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
+ * so can be used as-is or serve as inspiration for other interfaces or binding techniques.
+ */
+class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder<sk_sp<SkShader>> {
+public:
+    explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
+    ~SkRuntimeShaderBuilder();
+
     sk_sp<SkShader> makeShader(const SkMatrix* localMatrix, bool isOpaque);
     sk_sp<SkImage> makeImage(GrRecordingContext*,
                              const SkMatrix* localMatrix,
@@ -282,11 +330,7 @@
                              bool mipmapped);
 
 private:
-    void* writableUniformData();
-
-    sk_sp<SkRuntimeEffect>       fEffect;
-    sk_sp<SkData>                fUniforms;
-    std::vector<sk_sp<SkShader>> fChildren;
+    using INHERITED = SkRuntimeEffectBuilder<sk_sp<SkShader>>;
 };
 
 #endif
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index 6b9362d..0d2e302 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -799,9 +799,28 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+#if SK_SUPPORT_GPU
+std::unique_ptr<GrFragmentProcessor> SkRuntimeEffect::makeFP(
+        GrRecordingContext* recordingContext,
+        sk_sp<SkData> uniforms,
+        std::unique_ptr<GrFragmentProcessor> children[],
+        size_t childCount) const {
+    if (!uniforms) {
+        uniforms = SkData::MakeEmpty();
+    }
+    auto fp = GrSkSLFP::Make(recordingContext, sk_ref_sp(this), "make_fp", std::move(uniforms));
+    for (size_t i = 0; i < childCount; ++i) {
+        fp->addChild(std::move(children[i]));
+    }
+    return std::move(fp);
+}
+#endif
+
 sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<SkData> uniforms,
-                                            sk_sp<SkShader> children[], size_t childCount,
-                                            const SkMatrix* localMatrix, bool isOpaque) {
+                                            sk_sp<SkShader> children[],
+                                            size_t childCount,
+                                            const SkMatrix* localMatrix,
+                                            bool isOpaque) const {
     if (!uniforms) {
         uniforms = SkData::MakeEmpty();
     }
@@ -817,7 +836,7 @@
                                           size_t childCount,
                                           const SkMatrix* localMatrix,
                                           SkImageInfo resultInfo,
-                                          bool mipmapped) {
+                                          bool mipmapped) const {
     if (recordingContext) {
 #if SK_SUPPORT_GPU
         if (!recordingContext->priv().caps()->mipmapSupport()) {
@@ -897,7 +916,7 @@
 
 sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms,
                                                       sk_sp<SkColorFilter> children[],
-                                                      size_t childCount) {
+                                                      size_t childCount) const {
     if (!fAllowColorFilter) {
         return nullptr;
     }
@@ -910,7 +929,7 @@
         : nullptr;
 }
 
-sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms) {
+sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms) const {
     return this->makeColorFilter(std::move(uniforms), nullptr, 0);
 }
 
@@ -922,42 +941,27 @@
 }
 
 SkRuntimeShaderBuilder::SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect)
-    : fEffect(std::move(effect))
-    , fUniforms(SkData::MakeUninitialized(fEffect->uniformSize()))
-    , fChildren(fEffect->children().count()) {}
+        : INHERITED(std::move(effect)) {}
 
 SkRuntimeShaderBuilder::~SkRuntimeShaderBuilder() = default;
 
-void* SkRuntimeShaderBuilder::writableUniformData() {
-    if (!fUniforms->unique()) {
-        fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
-    }
-    return fUniforms->writable_data();
-}
-
-sk_sp<SkShader> SkRuntimeShaderBuilder::makeShader(const SkMatrix* localMatrix, bool isOpaque) {
-    return fEffect->makeShader(fUniforms, fChildren.data(), fChildren.size(), localMatrix, isOpaque);
-}
-
 sk_sp<SkImage> SkRuntimeShaderBuilder::makeImage(GrRecordingContext* recordingContext,
                                                  const SkMatrix* localMatrix,
                                                  SkImageInfo resultInfo,
                                                  bool mipmapped) {
-    return fEffect->makeImage(recordingContext,
-                              fUniforms,
-                              fChildren.data(),
-                              fChildren.size(),
-                              localMatrix,
-                              resultInfo,
-                              mipmapped);
+    return this->effect()->makeImage(recordingContext,
+                                     this->uniforms(),
+                                     this->children(),
+                                     this->numChildren(),
+                                     localMatrix,
+                                     resultInfo,
+                                     mipmapped);
 }
 
-SkRuntimeShaderBuilder::BuilderChild&
-SkRuntimeShaderBuilder::BuilderChild::operator=(const sk_sp<SkShader>& val) {
-    if (fIndex < 0) {
-        SkDEBUGFAIL("Assigning to missing child");
-    } else {
-        fOwner->fChildren[fIndex] = val;
-    }
-    return *this;
+sk_sp<SkShader> SkRuntimeShaderBuilder::makeShader(const SkMatrix* localMatrix, bool isOpaque) {
+    return this->effect()->makeShader(this->uniforms(),
+                                      this->children(),
+                                      this->numChildren(),
+                                      localMatrix,
+                                      isOpaque);
 }
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 507646c..e14278b 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -67,7 +67,6 @@
         kGrClampFragmentProcessor_ClassID,
         kGrColorMatrixFragmentProcessor_ClassID,
         kGrColorSpaceXformEffect_ClassID,
-        kGrComposeLerpEffect_ClassID,
         kGrConfigConversionEffect_ClassID,
         kGrConicEffect_ClassID,
         kGrConstColorProcessor_ClassID,
diff --git a/src/gpu/effects/GrComposeLerpEffect.fp b/src/gpu/effects/GrComposeLerpEffect.fp
deleted file mode 100644
index 7449541..0000000
--- a/src/gpu/effects/GrComposeLerpEffect.fp
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 2019 Google LLC.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-in fragmentProcessor child1;
-in fragmentProcessor child2;
-in uniform float weight;
-
-half4 main() {
-    return mix(sample(child1), sample(child2), half(weight));
-}
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index 9d4e472..f984cdb 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -254,3 +254,18 @@
 }
 
 #endif
+
+/**************************************************************************************************/
+
+GrRuntimeFPBuilder::GrRuntimeFPBuilder(sk_sp<SkRuntimeEffect> effect)
+        : INHERITED(std::move(effect)) {}
+
+GrRuntimeFPBuilder::~GrRuntimeFPBuilder() = default;
+
+std::unique_ptr<GrFragmentProcessor> GrRuntimeFPBuilder::makeFP(
+        GrRecordingContext* recordingContext) {
+    return this->effect()->makeFP(recordingContext,
+                                  this->uniforms(),
+                                  this->children(),
+                                  this->numChildren());
+}
diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h
index 5b4dd54..7566898 100644
--- a/src/gpu/effects/GrSkSLFP.h
+++ b/src/gpu/effects/GrSkSLFP.h
@@ -9,6 +9,7 @@
 #define GrSkSLFP_DEFINED
 
 #include "include/core/SkRefCnt.h"
+#include "include/effects/SkRuntimeEffect.h"
 #include "include/gpu/GrContextOptions.h"
 #include "src/gpu/GrFragmentProcessor.h"
 #include <atomic>
@@ -65,4 +66,27 @@
     friend class GrSkSLFPFactory;
 };
 
+class GrRuntimeFPBuilder : public SkRuntimeEffectBuilder<std::unique_ptr<GrFragmentProcessor>> {
+public:
+    ~GrRuntimeFPBuilder();
+
+    template <const char* CODE> static GrRuntimeFPBuilder Make() {
+        static const SkRuntimeEffect::Result gResult = SkRuntimeEffect::Make(SkString(CODE));
+#ifdef SK_DEBUG
+        if (!gResult.effect) {
+            SK_ABORT("Code failed: %s", gResult.errorText.c_str());
+        }
+#endif
+        return GrRuntimeFPBuilder(gResult.effect);
+    }
+
+    std::unique_ptr<GrFragmentProcessor> makeFP(GrRecordingContext*);
+
+private:
+    explicit GrRuntimeFPBuilder(sk_sp<SkRuntimeEffect>);
+    GrRuntimeFPBuilder(GrRuntimeFPBuilder&& that) = default;
+
+    using INHERITED = SkRuntimeEffectBuilder<std::unique_ptr<GrFragmentProcessor>>;
+};
+
 #endif
diff --git a/src/gpu/effects/generated/GrComposeLerpEffect.cpp b/src/gpu/effects/generated/GrComposeLerpEffect.cpp
deleted file mode 100644
index 155cc78..0000000
--- a/src/gpu/effects/generated/GrComposeLerpEffect.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2019 Google LLC.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrComposeLerpEffect.fp; do not modify.
- **************************************************************************************************/
-#include "GrComposeLerpEffect.h"
-
-#include "src/core/SkUtils.h"
-#include "src/gpu/GrTexture.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
-#include "src/sksl/SkSLCPP.h"
-#include "src/sksl/SkSLUtil.h"
-class GrGLSLComposeLerpEffect : public GrGLSLFragmentProcessor {
-public:
-    GrGLSLComposeLerpEffect() {}
-    void emitCode(EmitArgs& args) override {
-        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
-        const GrComposeLerpEffect& _outer = args.fFp.cast<GrComposeLerpEffect>();
-        (void)_outer;
-        auto weight = _outer.weight;
-        (void)weight;
-        weightVar = args.fUniformHandler->addUniform(
-                &_outer, kFragment_GrShaderFlag, kFloat_GrSLType, "weight");
-        SkString _sample0 = this->invokeChild(0, args);
-        SkString _sample1 = this->invokeChild(1, args);
-        fragBuilder->codeAppendf(
-                R"SkSL(return mix(%s, %s, half(%s));
-)SkSL",
-                _sample0.c_str(),
-                _sample1.c_str(),
-                args.fUniformHandler->getUniformCStr(weightVar));
-    }
-
-private:
-    void onSetData(const GrGLSLProgramDataManager& pdman,
-                   const GrFragmentProcessor& _proc) override {
-        const GrComposeLerpEffect& _outer = _proc.cast<GrComposeLerpEffect>();
-        { pdman.set1f(weightVar, (_outer.weight)); }
-    }
-    UniformHandle weightVar;
-};
-std::unique_ptr<GrGLSLFragmentProcessor> GrComposeLerpEffect::onMakeProgramImpl() const {
-    return std::make_unique<GrGLSLComposeLerpEffect>();
-}
-void GrComposeLerpEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
-                                                GrProcessorKeyBuilder* b) const {}
-bool GrComposeLerpEffect::onIsEqual(const GrFragmentProcessor& other) const {
-    const GrComposeLerpEffect& that = other.cast<GrComposeLerpEffect>();
-    (void)that;
-    if (weight != that.weight) return false;
-    return true;
-}
-GrComposeLerpEffect::GrComposeLerpEffect(const GrComposeLerpEffect& src)
-        : INHERITED(kGrComposeLerpEffect_ClassID, src.optimizationFlags()), weight(src.weight) {
-    this->cloneAndRegisterAllChildProcessors(src);
-}
-std::unique_ptr<GrFragmentProcessor> GrComposeLerpEffect::clone() const {
-    return std::make_unique<GrComposeLerpEffect>(*this);
-}
-#if GR_TEST_UTILS
-SkString GrComposeLerpEffect::onDumpInfo() const { return SkStringPrintf("(weight=%f)", weight); }
-#endif
diff --git a/src/gpu/effects/generated/GrComposeLerpEffect.h b/src/gpu/effects/generated/GrComposeLerpEffect.h
deleted file mode 100644
index 5e44e1a..0000000
--- a/src/gpu/effects/generated/GrComposeLerpEffect.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2019 Google LLC.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrComposeLerpEffect.fp; do not modify.
- **************************************************************************************************/
-#ifndef GrComposeLerpEffect_DEFINED
-#define GrComposeLerpEffect_DEFINED
-
-#include "include/core/SkM44.h"
-#include "include/core/SkTypes.h"
-
-#include "src/gpu/GrFragmentProcessor.h"
-
-class GrComposeLerpEffect : public GrFragmentProcessor {
-public:
-    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child1,
-                                                     std::unique_ptr<GrFragmentProcessor> child2,
-                                                     float weight) {
-        return std::unique_ptr<GrFragmentProcessor>(
-                new GrComposeLerpEffect(std::move(child1), std::move(child2), weight));
-    }
-    GrComposeLerpEffect(const GrComposeLerpEffect& src);
-    std::unique_ptr<GrFragmentProcessor> clone() const override;
-    const char* name() const override { return "ComposeLerpEffect"; }
-    float weight;
-
-private:
-    GrComposeLerpEffect(std::unique_ptr<GrFragmentProcessor> child1,
-                        std::unique_ptr<GrFragmentProcessor> child2,
-                        float weight)
-            : INHERITED(kGrComposeLerpEffect_ClassID, kNone_OptimizationFlags), weight(weight) {
-        this->registerChild(std::move(child1), SkSL::SampleUsage::PassThrough());
-        this->registerChild(std::move(child2), SkSL::SampleUsage::PassThrough());
-    }
-    std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
-    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-    bool onIsEqual(const GrFragmentProcessor&) const override;
-#if GR_TEST_UTILS
-    SkString onDumpInfo() const override;
-#endif
-    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
-    using INHERITED = GrFragmentProcessor;
-};
-#endif
diff --git a/src/shaders/SkComposeShader.cpp b/src/shaders/SkComposeShader.cpp
index 19d7334..0bc012d 100644
--- a/src/shaders/SkComposeShader.cpp
+++ b/src/shaders/SkComposeShader.cpp
@@ -201,7 +201,7 @@
 
 #include "include/gpu/GrRecordingContext.h"
 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
-#include "src/gpu/effects/generated/GrComposeLerpEffect.h"
+#include "src/gpu/effects/GrSkSLFP.h"
 #include "src/gpu/effects/generated/GrConstColorProcessor.h"
 
 static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) {
@@ -221,6 +221,19 @@
     const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix());
     auto fpA = as_fp(args, fDst.get());
     auto fpB = as_fp(args, fSrc.get());
-    return GrComposeLerpEffect::Make(std::move(fpA), std::move(fpB), fWeight);
+
+    static constexpr char kCode[] = R"(
+        uniform shader a;
+        uniform shader b;
+        uniform half w;
+
+        half4 main() { return mix(sample(a), sample(b), w); }
+    )";
+
+    auto builder = GrRuntimeFPBuilder::Make<kCode>();
+    builder.uniform("w") = fWeight;
+    builder.child("a") = std::move(fpA);
+    builder.child("b") = std::move(fpB);
+    return builder.makeFP(args.fContext);
 }
 #endif