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