Revert "Move runtime shader/colorfilter into SkRuntimeEffect.cpp"

This reverts commit 8980acd6239b4c7c9aa3bf36aee1cb5c208738ae.

Reason for revert: Win-Shared

Original change's description:
> Move runtime shader/colorfilter into SkRuntimeEffect.cpp
> 
> Better organization that lets us share a bunch of code between these
> (very similar) objects.
> 
> Change-Id: Ie559d6e144d8588b98a95d4170e2e6c19d9623bd
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/270736
> Reviewed-by: Mike Reed <reed@google.com>
> Commit-Queue: Brian Osman <brianosman@google.com>

TBR=brianosman@google.com,ethannicholas@google.com,reed@google.com

Change-Id: Ic13d85b7c4f2d593a6c15dde067f118ea5753eb6
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/271600
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/gn/core.gni b/gn/core.gni
index 7d59209..dff7111 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -445,6 +445,7 @@
   "$_src/shaders/SkLights.h",
   "$_src/shaders/SkLocalMatrixShader.cpp",
   "$_src/shaders/SkLocalMatrixShader.h",
+  "$_src/shaders/SkRTShader.cpp",
   "$_src/shaders/SkShader.cpp",
   "$_src/shaders/SkShaderBase.h",
 
diff --git a/include/effects/SkRuntimeEffect.h b/include/effects/SkRuntimeEffect.h
index 44f55b1..921b42e 100644
--- a/include/effects/SkRuntimeEffect.h
+++ b/include/effects/SkRuntimeEffect.h
@@ -127,8 +127,6 @@
 
     ByteCodeResult toByteCode(const void* inputs);
 
-    static void RegisterFlattenables();
-
 private:
     SkRuntimeEffect(SkString sksl, std::unique_ptr<SkSL::Compiler> compiler,
                     std::unique_ptr<SkSL::Program> baseProgram,
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index 9a86a2f..edd5869 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -9,6 +9,7 @@
 #include "include/core/SkRefCnt.h"
 #include "include/core/SkString.h"
 #include "include/core/SkUnPreMultiply.h"
+#include "include/effects/SkRuntimeEffect.h"
 #include "include/private/SkNx.h"
 #include "include/private/SkTDArray.h"
 #include "src/core/SkArenaAlloc.h"
@@ -18,6 +19,7 @@
 #include "src/core/SkReadBuffer.h"
 #include "src/core/SkVM.h"
 #include "src/core/SkWriteBuffer.h"
+#include "src/sksl/SkSLInterpreter.h"
 
 #if SK_SUPPORT_GPU
 #include "src/gpu/GrFragmentProcessor.h"
@@ -389,6 +391,129 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+#include "include/private/SkMutex.h"
+#include "src/sksl/SkSLByteCode.h"
+
+#if SK_SUPPORT_GPU
+#include "include/private/GrRecordingContext.h"
+#include "src/gpu/effects/GrSkSLFP.h"
+#endif
+
+class SkRuntimeColorFilter : public SkColorFilter {
+public:
+    SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs,
+                         sk_sp<SkColorFilter> children[], size_t childCount)
+            : fEffect(std::move(effect))
+            , fInputs(std::move(inputs))
+            , fChildren(children, children + childCount) {}
+
+#if SK_SUPPORT_GPU
+    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
+            GrRecordingContext* context, const GrColorInfo& colorInfo) const override {
+        auto fp = GrSkSLFP::Make(context, fEffect, "Runtime Color Filter", fInputs);
+        for (const auto& child : fChildren) {
+            auto childFP = child ? child->asFragmentProcessor(context, colorInfo) : nullptr;
+            if (!childFP) {
+                // TODO: This is the case that should eventually mean "the original input color"
+                return nullptr;
+            }
+            fp->addChild(std::move(childFP));
+        }
+        return fp;
+    }
+#endif
+
+    bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
+        auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
+        // don't need to set ctx->paintColor
+        ctx->inputs = fInputs->data();
+        ctx->ninputs = fEffect->uniformSize() / 4;
+        ctx->shaderConvention = false;
+
+        SkAutoMutexExclusive ama(fInterpreterMutex);
+        if (!fInterpreter) {
+            auto [byteCode, errorText] = fEffect->toByteCode(fInputs->data());
+            if (!byteCode) {
+                SkDebugf("%s\n", errorText.c_str());
+                return false;
+            }
+            fMain = byteCode->getFunction("main");
+            fInterpreter.reset(
+                           new SkSL::Interpreter<SkRasterPipeline_InterpreterCtx::VECTOR_WIDTH>(
+                                                                          std::move(byteCode)));
+        }
+        ctx->fn = fMain;
+        ctx->interpreter = fInterpreter.get();
+        rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
+        return true;
+    }
+
+protected:
+    void flatten(SkWriteBuffer& buffer) const override {
+        buffer.writeString(fEffect->source().c_str());
+        if (fInputs) {
+            buffer.writeDataAsByteArray(fInputs.get());
+        } else {
+            buffer.writeByteArray(nullptr, 0);
+        }
+        buffer.write32(fChildren.size());
+        for (const auto& child : fChildren) {
+            buffer.writeFlattenable(child.get());
+        }
+    }
+
+private:
+    SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
+
+    sk_sp<SkRuntimeEffect> fEffect;
+    sk_sp<SkData> fInputs;
+    std::vector<sk_sp<SkColorFilter>> fChildren;
+
+    mutable SkMutex fInterpreterMutex;
+    mutable std::unique_ptr<SkSL::Interpreter<SkRasterPipeline_InterpreterCtx::VECTOR_WIDTH>>
+                                                                                       fInterpreter;
+    mutable const SkSL::ByteCodeFunction* fMain;
+
+    friend class SkColorFilter;
+
+    typedef SkColorFilter INHERITED;
+};
+
+sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
+    SkString sksl;
+    buffer.readString(&sksl);
+    sk_sp<SkData> inputs = buffer.readByteArrayAsData();
+
+    auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
+    if (!effect) {
+        buffer.validate(false);
+        return nullptr;
+    }
+
+    size_t childCount = buffer.read32();
+    if (childCount != effect->children().count()) {
+        buffer.validate(false);
+        return nullptr;
+    }
+
+    std::vector<sk_sp<SkColorFilter>> children;
+    children.resize(childCount);
+    for (size_t i = 0; i < children.size(); ++i) {
+        children[i] = buffer.readColorFilter();
+    }
+
+    return effect->makeColorFilter(std::move(inputs), children.data(), children.size());
+}
+
+// Private helper method so SkRuntimeEffect can access SkRuntimeColorFilter
+sk_sp<SkColorFilter> SkMakeRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs,
+                                              sk_sp<SkColorFilter> children[], size_t childCount) {
+    return sk_sp<SkColorFilter>(
+            new SkRuntimeColorFilter(std::move(effect), std::move(inputs), children, childCount));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 #include "src/core/SkModeColorFilter.h"
 
 void SkColorFilter::RegisterFlattenables() {
@@ -396,4 +521,5 @@
     SK_REGISTER_FLATTENABLE(SkModeColorFilter);
     SK_REGISTER_FLATTENABLE(SkSRGBGammaColorFilter);
     SK_REGISTER_FLATTENABLE(SkMixerColorFilter);
+    SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
 }
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index d4d6fae..926b1f4 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -9,22 +9,11 @@
 #include "include/core/SkData.h"
 #include "include/effects/SkRuntimeEffect.h"
 #include "include/private/SkChecksum.h"
-#include "include/private/SkMutex.h"
-#include "src/core/SkRasterPipeline.h"
-#include "src/core/SkReadBuffer.h"
-#include "src/core/SkWriteBuffer.h"
+#include "src/shaders/SkRTShader.h"
 #include "src/sksl/SkSLByteCode.h"
 #include "src/sksl/SkSLCompiler.h"
-#include "src/sksl/SkSLInterpreter.h"
 #include "src/sksl/ir/SkSLVarDeclarations.h"
 
-#if SK_SUPPORT_GPU
-#include "include/private/GrRecordingContext.h"
-#include "src/gpu/GrColorInfo.h"
-#include "src/gpu/GrFPArgs.h"
-#include "src/gpu/effects/GrSkSLFP.h"
-#endif
-
 SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
     auto compiler = std::make_unique<SkSL::Compiler>();
     auto program = compiler->convertProgram(SkSL::Program::kPipelineStage_Kind,
@@ -304,257 +293,6 @@
     return ByteCodeResult(std::move(byteCode), SkString(fCompiler->errorText().c_str()));
 }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static constexpr int kVectorWidth = SkRasterPipeline_InterpreterCtx::VECTOR_WIDTH;
-
-class SkRuntimeColorFilter : public SkColorFilter {
-public:
-    SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs,
-                         sk_sp<SkColorFilter> children[], size_t childCount)
-            : fEffect(std::move(effect))
-            , fInputs(std::move(inputs))
-            , fChildren(children, children + childCount) {}
-
-#if SK_SUPPORT_GPU
-    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
-            GrRecordingContext* context, const GrColorInfo& colorInfo) const override {
-        auto fp = GrSkSLFP::Make(context, fEffect, "Runtime Color Filter", fInputs);
-        for (const auto& child : fChildren) {
-            auto childFP = child ? child->asFragmentProcessor(context, colorInfo) : nullptr;
-            if (!childFP) {
-                // TODO: This is the case that should eventually mean "the original input color"
-                return nullptr;
-            }
-            fp->addChild(std::move(childFP));
-        }
-        return fp;
-    }
-#endif
-
-    bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
-        auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
-        // don't need to set ctx->paintColor
-        ctx->inputs = fInputs->data();
-        ctx->ninputs = fEffect->uniformSize() / 4;
-        ctx->shaderConvention = false;
-
-        SkAutoMutexExclusive ama(fInterpreterMutex);
-        if (!fInterpreter) {
-            auto [byteCode, errorText] = fEffect->toByteCode(fInputs->data());
-            if (!byteCode) {
-                SkDebugf("%s\n", errorText.c_str());
-                return false;
-            }
-            fMain = byteCode->getFunction("main");
-            fInterpreter.reset(new SkSL::Interpreter<kVectorWidth>(std::move(byteCode)));
-        }
-        ctx->fn = fMain;
-        ctx->interpreter = fInterpreter.get();
-        rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
-        return true;
-    }
-
-    void flatten(SkWriteBuffer& buffer) const override {
-        buffer.writeString(fEffect->source().c_str());
-        if (fInputs) {
-            buffer.writeDataAsByteArray(fInputs.get());
-        } else {
-            buffer.writeByteArray(nullptr, 0);
-        }
-        buffer.write32(fChildren.size());
-        for (const auto& child : fChildren) {
-            buffer.writeFlattenable(child.get());
-        }
-    }
-
-    SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
-
-private:
-    sk_sp<SkRuntimeEffect> fEffect;
-    sk_sp<SkData> fInputs;
-    std::vector<sk_sp<SkColorFilter>> fChildren;
-
-    mutable SkMutex fInterpreterMutex;
-    mutable std::unique_ptr<SkSL::Interpreter<kVectorWidth>> fInterpreter;
-    mutable const SkSL::ByteCodeFunction* fMain;
-};
-
-sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
-    SkString sksl;
-    buffer.readString(&sksl);
-    sk_sp<SkData> inputs = buffer.readByteArrayAsData();
-
-    auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
-    if (!effect) {
-        buffer.validate(false);
-        return nullptr;
-    }
-
-    size_t childCount = buffer.read32();
-    if (childCount != effect->children().count()) {
-        buffer.validate(false);
-        return nullptr;
-    }
-
-    std::vector<sk_sp<SkColorFilter>> children;
-    children.resize(childCount);
-    for (size_t i = 0; i < children.size(); ++i) {
-        children[i] = buffer.readColorFilter();
-    }
-
-    return effect->makeColorFilter(std::move(inputs), children.data(), children.size());
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class SkRTShader : public SkShaderBase {
-public:
-    SkRTShader(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs, const SkMatrix* localMatrix,
-               sk_sp<SkShader>* children, size_t childCount, bool isOpaque)
-            : SkShaderBase(localMatrix)
-            , fEffect(std::move(effect))
-            , fIsOpaque(isOpaque)
-            , fInputs(std::move(inputs))
-            , fChildren(children, children + childCount) {}
-
-    bool isOpaque() const override { return fIsOpaque; }
-
-#if SK_SUPPORT_GPU
-    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override {
-        SkMatrix matrix;
-        if (!this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
-            return nullptr;
-        }
-        auto fp = GrSkSLFP::Make(args.fContext, fEffect, "runtime-shader", fInputs, &matrix);
-        for (const auto& child : fChildren) {
-            auto childFP = child ? as_SB(child)->asFragmentProcessor(args) : nullptr;
-            if (!childFP) {
-                // TODO: This is the case that should eventually mean "the original input color"
-                return nullptr;
-            }
-            fp->addChild(std::move(childFP));
-        }
-        if (GrColorTypeClampType(args.fDstColorInfo->colorType()) != GrClampType::kNone) {
-            return GrFragmentProcessor::ClampPremulOutput(std::move(fp));
-        } else {
-            return fp;
-        }
-    }
-#endif
-
-    bool onAppendStages(const SkStageRec& rec) const override {
-        SkMatrix inverse;
-        if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &inverse)) {
-            return false;
-        }
-
-        auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
-        ctx->paintColor = rec.fPaint.getColor4f();
-        ctx->inputs = fInputs->data();
-        ctx->ninputs = fEffect->uniformSize() / 4;
-        ctx->shaderConvention = true;
-
-        SkAutoMutexExclusive ama(fInterpreterMutex);
-        if (!fInterpreter) {
-            auto[byteCode, errorText] = fEffect->toByteCode(fInputs->data());
-            if (!byteCode) {
-                SkDebugf("%s\n", errorText.c_str());
-                return false;
-            }
-            fMain = byteCode->getFunction("main");
-            fInterpreter.reset(new SkSL::Interpreter<kVectorWidth>(std::move(byteCode)));
-        }
-        ctx->fn = fMain;
-        ctx->interpreter = fInterpreter.get();
-
-        rec.fPipeline->append(SkRasterPipeline::seed_shader);
-        rec.fPipeline->append_matrix(rec.fAlloc, inverse);
-        rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
-        return true;
-    }
-
-    void flatten(SkWriteBuffer& buffer) const override {
-        uint32_t flags = 0;
-        if (fIsOpaque) {
-            flags |= kIsOpaque_Flag;
-        }
-        if (!this->getLocalMatrix().isIdentity()) {
-            flags |= kHasLocalMatrix_Flag;
-        }
-
-        buffer.writeString(fEffect->source().c_str());
-        if (fInputs) {
-            buffer.writeDataAsByteArray(fInputs.get());
-        } else {
-            buffer.writeByteArray(nullptr, 0);
-        }
-        buffer.write32(flags);
-        if (flags & kHasLocalMatrix_Flag) {
-            buffer.writeMatrix(this->getLocalMatrix());
-        }
-        buffer.write32(fChildren.size());
-        for (const auto& child : fChildren) {
-            buffer.writeFlattenable(child.get());
-        }
-    }
-
-    SK_FLATTENABLE_HOOKS(SkRTShader)
-
-private:
-    enum Flags {
-        kIsOpaque_Flag          = 1 << 0,
-        kHasLocalMatrix_Flag    = 1 << 1,
-    };
-
-    sk_sp<SkRuntimeEffect> fEffect;
-    bool fIsOpaque;
-
-    sk_sp<SkData> fInputs;
-    std::vector<sk_sp<SkShader>> fChildren;
-
-    mutable SkMutex fInterpreterMutex;
-    mutable std::unique_ptr<SkSL::Interpreter<kVectorWidth>> fInterpreter;
-    mutable const SkSL::ByteCodeFunction* fMain;
-};
-
-sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
-    SkString sksl;
-    buffer.readString(&sksl);
-    sk_sp<SkData> inputs = buffer.readByteArrayAsData();
-    uint32_t flags = buffer.read32();
-
-    bool isOpaque = SkToBool(flags & kIsOpaque_Flag);
-    SkMatrix localM, *localMPtr = nullptr;
-    if (flags & kHasLocalMatrix_Flag) {
-        buffer.readMatrix(&localM);
-        localMPtr = &localM;
-    }
-
-    auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
-    if (!effect) {
-        buffer.validate(false);
-        return nullptr;
-    }
-
-    size_t childCount = buffer.read32();
-    if (childCount != effect->children().count()) {
-        buffer.validate(false);
-        return nullptr;
-    }
-
-    std::vector<sk_sp<SkShader>> children;
-    children.resize(childCount);
-    for (size_t i = 0; i < children.size(); ++i) {
-        children[i] = buffer.readShader();
-    }
-
-    return effect->makeShader(std::move(inputs), children.data(), children.size(), localMPtr,
-                              isOpaque);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
 sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<SkData> inputs,
                                             sk_sp<SkShader> children[], size_t childCount,
                                             const SkMatrix* localMatrix, bool isOpaque) {
@@ -567,19 +305,14 @@
 sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs,
                                                       sk_sp<SkColorFilter> children[],
                                                       size_t childCount) {
+    extern sk_sp<SkColorFilter> SkMakeRuntimeColorFilter(sk_sp<SkRuntimeEffect>, sk_sp<SkData>,
+                                                         sk_sp<SkColorFilter>[], size_t);
+
     return inputs && inputs->size() == this->inputSize() && childCount == fChildren.size()
-        ? sk_sp<SkColorFilter>(new SkRuntimeColorFilter(sk_ref_sp(this), std::move(inputs),
-                                                        children, childCount))
+        ? SkMakeRuntimeColorFilter(sk_ref_sp(this), std::move(inputs), children, childCount)
         : nullptr;
 }
 
 sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs) {
     return this->makeColorFilter(std::move(inputs), nullptr, 0);
 }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void SkRuntimeEffect::RegisterFlattenables() {
-    SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
-    SK_REGISTER_FLATTENABLE(SkRTShader);
-}
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 7ef7c31..30d41da 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -27,7 +27,6 @@
     #include "include/effects/SkLumaColorFilter.h"
     #include "include/effects/SkOverdrawColorFilter.h"
     #include "include/effects/SkPerlinNoiseShader.h"
-    #include "include/effects/SkRuntimeEffect.h"
     #include "include/effects/SkShaderMaskFilter.h"
     #include "include/effects/SkTableColorFilter.h"
     #include "src/core/SkColorFilter_Matrix.h"
@@ -46,6 +45,7 @@
     #include "src/shaders/SkLightingShader.h"
     #include "src/shaders/SkLocalMatrixShader.h"
     #include "src/shaders/SkPictureShader.h"
+    #include "src/shaders/SkRTShader.h"
     #include "src/shaders/SkShaderBase.h"
 
     #include "include/effects/SkImageFilters.h"
@@ -70,6 +70,7 @@
         SK_REGISTER_FLATTENABLE(SkEmptyShader);
         SK_REGISTER_FLATTENABLE(SkLocalMatrixShader);
         SK_REGISTER_FLATTENABLE(SkPictureShader);
+        SK_REGISTER_FLATTENABLE(SkRTShader);
         SkGradientShader::RegisterFlattenables();
         SkLightingShader::RegisterFlattenables();
         SkPerlinNoiseShader::RegisterFlattenables();
@@ -83,9 +84,6 @@
         SkOverdrawColorFilter::RegisterFlattenables();
         SkTableColorFilter::RegisterFlattenables();
 
-        // Shader & color filter.
-        SkRuntimeEffect::RegisterFlattenables();
-
         // Mask filters.
         SK_REGISTER_FLATTENABLE(SkEmbossMaskFilter);
         SkMaskFilter::RegisterFlattenables();
diff --git a/src/shaders/SkRTShader.cpp b/src/shaders/SkRTShader.cpp
new file mode 100644
index 0000000..3e961e0
--- /dev/null
+++ b/src/shaders/SkRTShader.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkData.h"
+#include "include/effects/SkRuntimeEffect.h"
+#include "src/core/SkArenaAlloc.h"
+#include "src/core/SkRasterPipeline.h"
+#include "src/core/SkReadBuffer.h"
+#include "src/core/SkWriteBuffer.h"
+#include "src/shaders/SkRTShader.h"
+
+#include "src/sksl/SkSLByteCode.h"
+#include "src/sksl/SkSLCompiler.h"
+#include "src/sksl/SkSLInterpreter.h"
+
+#if SK_SUPPORT_GPU
+#include "src/gpu/GrColorInfo.h"
+#include "src/gpu/GrFPArgs.h"
+#include "src/gpu/effects/GrSkSLFP.h"
+#endif
+
+SkRTShader::SkRTShader(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs,
+                       const SkMatrix* localMatrix, sk_sp<SkShader>* children, size_t childCount,
+                       bool isOpaque)
+        : SkShaderBase(localMatrix)
+        , fEffect(std::move(effect))
+        , fIsOpaque(isOpaque)
+        , fInputs(std::move(inputs))
+        , fChildren(children, children + childCount) {
+}
+
+SkRTShader::~SkRTShader() = default;
+
+bool SkRTShader::onAppendStages(const SkStageRec& rec) const {
+    SkMatrix inverse;
+    if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &inverse)) {
+        return false;
+    }
+
+    auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
+    ctx->paintColor = rec.fPaint.getColor4f();
+    ctx->inputs = fInputs->data();
+    ctx->ninputs = fEffect->uniformSize() / 4;
+    ctx->shaderConvention = true;
+
+    SkAutoMutexExclusive ama(fInterpreterMutex);
+    if (!fInterpreter) {
+        auto [byteCode, errorText] = fEffect->toByteCode(fInputs->data());
+        if (!byteCode) {
+            SkDebugf("%s\n", errorText.c_str());
+            return false;
+        }
+        fMain = byteCode->getFunction("main");
+        fInterpreter.reset(new SkSL::Interpreter<SkRasterPipeline_InterpreterCtx::VECTOR_WIDTH>(
+                                                                      std::move(byteCode)));
+    }
+    ctx->fn = fMain;
+    ctx->interpreter = fInterpreter.get();
+
+    rec.fPipeline->append(SkRasterPipeline::seed_shader);
+    rec.fPipeline->append_matrix(rec.fAlloc, inverse);
+    rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
+    return true;
+}
+
+enum Flags {
+    kIsOpaque_Flag          = 1 << 0,
+    kHasLocalMatrix_Flag    = 1 << 1,
+};
+
+void SkRTShader::flatten(SkWriteBuffer& buffer) const {
+    uint32_t flags = 0;
+    if (fIsOpaque) {
+        flags |= kIsOpaque_Flag;
+    }
+    if (!this->getLocalMatrix().isIdentity()) {
+        flags |= kHasLocalMatrix_Flag;
+    }
+
+    buffer.writeString(fEffect->source().c_str());
+    if (fInputs) {
+        buffer.writeDataAsByteArray(fInputs.get());
+    } else {
+        buffer.writeByteArray(nullptr, 0);
+    }
+    buffer.write32(flags);
+    if (flags & kHasLocalMatrix_Flag) {
+        buffer.writeMatrix(this->getLocalMatrix());
+    }
+    buffer.write32(fChildren.size());
+    for (const auto& child : fChildren) {
+        buffer.writeFlattenable(child.get());
+    }
+}
+
+sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
+    SkString sksl;
+    buffer.readString(&sksl);
+    sk_sp<SkData> inputs = buffer.readByteArrayAsData();
+    uint32_t flags = buffer.read32();
+
+    bool isOpaque = SkToBool(flags & kIsOpaque_Flag);
+    SkMatrix localM, *localMPtr = nullptr;
+    if (flags & kHasLocalMatrix_Flag) {
+        buffer.readMatrix(&localM);
+        localMPtr = &localM;
+    }
+
+    auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
+    if (!effect) {
+        buffer.validate(false);
+        return nullptr;
+    }
+
+    size_t childCount = buffer.read32();
+    if (childCount != effect->children().count()) {
+        buffer.validate(false);
+        return nullptr;
+    }
+
+    std::vector<sk_sp<SkShader>> children;
+    children.resize(childCount);
+    for (size_t i = 0; i < children.size(); ++i) {
+        children[i] = buffer.readShader();
+    }
+
+    return effect->makeShader(std::move(inputs), children.data(), children.size(), localMPtr,
+                              isOpaque);
+}
+
+#if SK_SUPPORT_GPU
+std::unique_ptr<GrFragmentProcessor> SkRTShader::asFragmentProcessor(const GrFPArgs& args) const {
+    SkMatrix matrix;
+    if (!this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
+        return nullptr;
+    }
+    auto fp = GrSkSLFP::Make(args.fContext, fEffect, "runtime-shader", fInputs, &matrix);
+    for (const auto& child : fChildren) {
+        auto childFP = child ? as_SB(child)->asFragmentProcessor(args) : nullptr;
+        if (!childFP) {
+            // TODO: This is the case that should eventually mean "the original input color"
+            return nullptr;
+        }
+        fp->addChild(std::move(childFP));
+    }
+    if (GrColorTypeClampType(args.fDstColorInfo->colorType()) != GrClampType::kNone) {
+        return GrFragmentProcessor::ClampPremulOutput(std::move(fp));
+    } else {
+        return fp;
+    }
+}
+#endif
diff --git a/src/shaders/SkRTShader.h b/src/shaders/SkRTShader.h
new file mode 100644
index 0000000..1ac56ec
--- /dev/null
+++ b/src/shaders/SkRTShader.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRTShader_DEFINED
+#define SkRTShader_DEFINED
+
+#include "include/core/SkString.h"
+#include "include/private/SkMutex.h"
+#include "src/shaders/SkShaderBase.h"
+
+struct GrFPArgs;
+class GrFragmentProcessor;
+class SkData;
+class SkMatrix;
+class SkRuntimeEffect;
+
+namespace SkSL {
+    class ByteCodeFunction;
+
+    template<int width>
+    class Interpreter;
+}
+
+class SkRTShader : public SkShaderBase {
+public:
+    SkRTShader(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs, const SkMatrix* localMatrix,
+               sk_sp<SkShader>* children, size_t childCount, bool isOpaque);
+    ~SkRTShader() override;
+
+    bool isOpaque() const override { return fIsOpaque; }
+
+#if SK_SUPPORT_GPU
+    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
+#endif
+
+protected:
+    void flatten(SkWriteBuffer&) const override;
+    bool onAppendStages(const SkStageRec& rec) const override;
+
+private:
+    static constexpr int VECTOR_WIDTH = 8;
+
+    SK_FLATTENABLE_HOOKS(SkRTShader)
+
+    sk_sp<SkRuntimeEffect> fEffect;
+    bool fIsOpaque;
+
+    sk_sp<SkData> fInputs;
+    std::vector<sk_sp<SkShader>> fChildren;
+
+    mutable SkMutex fInterpreterMutex;
+    mutable std::unique_ptr<SkSL::Interpreter<VECTOR_WIDTH>> fInterpreter;
+    mutable const SkSL::ByteCodeFunction* fMain;
+
+    typedef SkShaderBase INHERITED;
+};
+
+#endif