Flutter Engine
The Flutter Engine
SkSLEffect.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
10#include "include/core/SkData.h"
12#include "include/core/SkRect.h"
29#include "src/utils/SkJSON.h"
30
31#include <cstdint>
32#include <cstring>
33#include <memory>
34#include <tuple>
35#include <utility>
36#include <vector>
37
38class SkMatrix;
39struct SkPoint;
40
41namespace sksg {
42class InvalidationController;
43}
44
45namespace skottie::internal {
46
47// https://g-issues.chromium.org/issues/40064011
48#if defined(SK_ENABLE_SKOTTIE_SKSLEFFECT)
49
50namespace {
51class SkSLShaderNode final : public sksg::CustomRenderNode {
52public:
53 explicit SkSLShaderNode(sk_sp<RenderNode> child) : INHERITED({std::move(child)}) {}
54
55 SG_ATTRIBUTE(Shader, sk_sp<SkShader>, fEffectShader)
56private:
57 SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
58 const auto& child = this->children()[0];
59 return child->revalidate(ic, ctm);
60 }
61
62 void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
63 const auto& bounds = this->bounds();
64 const auto local_ctx = ScopedRenderContext(canvas, ctx)
65 .setIsolation(bounds, canvas->getTotalMatrix(), true);
66
67 canvas->saveLayer(&bounds, nullptr);
68 this->children()[0]->render(canvas, local_ctx);
69
70 SkPaint effect_paint;
71 effect_paint.setShader(fEffectShader);
73
74 canvas->drawPaint(effect_paint);
75 }
76
77 const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
78
79 sk_sp<SkShader> fEffectShader;
80
82};
83
84class SkSLEffectBase {
85public:
86 SkSLEffectBase(const skjson::ArrayValue& jprops,
87 const AnimationBuilder& abuilder)
88 {
89 if (jprops.size() < 1) {
90 return;
91 }
92 const skjson::ObjectValue* jSkSL = jprops[kSkSL_index];
93 if (!jSkSL) {
94 return;
95 }
96 const skjson::StringValue* jShader = (*jSkSL)["sh"];
97 if (!jShader) {
98 return;
99 }
100 SkString shader = SkString(jShader->begin(), jShader->size());
101 auto result = SkRuntimeEffect::MakeForShader(shader, {});
102 if (!result.effect) {
103 abuilder.log(Logger::Level::kError, nullptr, "Failed to parse SkSL shader: %s",
104 result.errorText.c_str());
105 return;
106 }
107 fEffect = std::move(result.effect);
108 }
109protected:
110 enum : size_t {
111 kSkSL_index = 0,
112 kFirstUniform_index = 1,
113 };
114
115 void bindUniforms(const skjson::ArrayValue& jprops,
116 const AnimationBuilder& abuilder,
117 AnimatablePropertyContainer * const &container) {
118 // construct dynamic uniform list from jprops, skip SkSL property
119 for (size_t i = kFirstUniform_index; i < jprops.size(); i++) {
120 const skjson::ObjectValue* jprop = jprops[i];
121 if (!jprop) { continue; }
122 const skjson::StringValue* uniformName = (*jprop)["nm"];
123 if (!uniformName) { continue; }
124 auto uniformTuple = std::make_tuple(SkString(uniformName->begin(),
125 uniformName->size()),
126 std::make_unique<VectorValue>());
127 fUniforms.push_back(std::move(uniformTuple));
128 container->bind(abuilder, (*jprop)["v"], std::get<1>(fUniforms.back()).get());
129 }
130 }
131
132 sk_sp<SkData> buildUniformData() const {
133 auto uniformData = SkData::MakeUninitialized(fEffect->uniformSize());
134 SkASSERT(uniformData);
135 sk_bzero(uniformData->writable_data(), uniformData->size());
136 for (const auto& uniform : fUniforms) {
137 const auto& name = std::get<0>(uniform);
138 const auto& data = std::get<1>(uniform);
139 auto metadata = fEffect->findUniform(name.c_str());
140 if (metadata && metadata->count == static_cast<int>(data->size())) {
141 auto dst = reinterpret_cast<uint8_t*>(uniformData->writable_data()) + metadata->offset;
142 memcpy(reinterpret_cast<void*>(dst), data->data(), data->size() * sizeof(float));
143 } else {
144 SkDebugf("cannot set malformed uniform: %s", name.c_str());
145 }
146 }
147 return uniformData;
148 }
150 std::vector<std::tuple<SkString, std::unique_ptr<VectorValue>>> fUniforms;
151};
152
153class SkSLShaderAdapter final : public DiscardableAdapterBase<SkSLShaderAdapter,
154 SkSLShaderNode>,
155 public SkSLEffectBase {
156public:
157 SkSLShaderAdapter(const skjson::ArrayValue& jprops,
158 const AnimationBuilder& abuilder,
160 : DiscardableAdapterBase<SkSLShaderAdapter, SkSLShaderNode>(std::move(node))
161 , SkSLEffectBase(jprops, abuilder)
162 {
163 this->bindUniforms(jprops, abuilder, this);
164 }
165
166private:
167 void onSync() override {
168 if (!fEffect) {
169 return;
170 }
171 sk_sp<SkShader> shader =
172 fEffect->makeShader(buildUniformData(), {/* TODO: child support */});
173 this->node()->setShader(std::move(shader));
174 }
175};
176
177class SkSLColorFilterAdapter final : public DiscardableAdapterBase<SkSLColorFilterAdapter,
178 sksg::ExternalColorFilter>
179 , public SkSLEffectBase {
180public:
181 SkSLColorFilterAdapter(const skjson::ArrayValue& jprops,
182 const AnimationBuilder& abuilder,
184 : DiscardableAdapterBase<SkSLColorFilterAdapter, sksg::ExternalColorFilter>(std::move(node))
185 , SkSLEffectBase(jprops, abuilder)
186 {
187 this->bindUniforms(jprops, abuilder, this);
188 }
189
190private:
191 void onSync() override {
192 if (!fEffect) {
193 return;
194 }
195 auto cf = fEffect->makeColorFilter(buildUniformData());
196 this->node()->setColorFilter(std::move(cf));
197 }
198};
199
200} // namespace
201
202#endif // SK_ENABLE_SKOTTIE_SKSLEFFECT
203
204sk_sp<sksg::RenderNode> EffectBuilder::attachSkSLShader(const skjson::ArrayValue& jprops,
205 sk_sp<sksg::RenderNode> layer) const {
206#if defined(SK_ENABLE_SKOTTIE_SKSLEFFECT)
207 auto shaderNode = sk_make_sp<SkSLShaderNode>(std::move(layer));
208 return fBuilder->attachDiscardableAdapter<SkSLShaderAdapter>(jprops, *fBuilder,
209 std::move(shaderNode));
210#else
211 return layer;
212#endif
213}
214
215sk_sp<sksg::RenderNode> EffectBuilder::attachSkSLColorFilter(const skjson::ArrayValue& jprops,
216 sk_sp<sksg::RenderNode> layer) const {
217#if defined(SK_ENABLE_SKOTTIE_SKSLEFFECT)
218 auto cfNode = sksg::ExternalColorFilter::Make(std::move(layer));
219 return fBuilder->attachDiscardableAdapter<SkSLColorFilterAdapter>(jprops, *fBuilder,
220 std::move(cfNode));
221#else
222 return layer;
223#endif
224}
225
226} // namespace skottie::internal
sk_bzero(glyphs, sizeof(glyphs))
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kSrcIn
r = s * da
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
#define SG_ATTRIBUTE(attr_name, attr_type, attr_container)
Definition: SkSGNode.h:100
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition: SkCanvas.cpp:496
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
void setShader(sk_sp< SkShader > shader)
void setBlendMode(SkBlendMode mode)
Definition: SkPaint.cpp:151
size_t uniformSize() const
sk_sp< SkShader > makeShader(sk_sp< const SkData > uniforms, sk_sp< SkShader > children[], size_t childCount, const SkMatrix *localMatrix=nullptr) const
static Result MakeForShader(SkString sksl, const Options &)
sk_sp< SkColorFilter > makeColorFilter(sk_sp< const SkData > uniforms) const
const Uniform * findUniform(std::string_view name) const
const char * begin() const
Definition: SkJSON.h:315
size_t size() const
Definition: SkJSON.h:300
size_t size() const
Definition: SkJSON.h:262
void attachDiscardableAdapter(sk_sp< T > adapter) const
Definition: SkottiePriv.h:139
static sk_sp< ExternalColorFilter > Make(sk_sp< RenderNode > child)
GAsyncResult * result
Optional< SkRect > bounds
Definition: SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
dst
Definition: cp.py:12
const myers::Point & get< 1 >(const myers::Segment &s)
Definition: Myers.h:81
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
Definition: Skottie.h:32
Definition: ref_ptr.h:256
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63