xref: /aosp_15_r20/external/skia/modules/skottie/src/effects/SkSLEffect.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkSpan_impl.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/Skottie.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/Adapter.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieJson.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottiePriv.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieValue.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/animator/Animator.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/effects/Effects.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skresources/include/SkResources.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGColorFilter.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGNode.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGRenderNode.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkJSON.h"
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
41*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
42*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
43*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
44*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
45*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker struct SkPoint;
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker namespace sksg {
50*c8dee2aaSAndroid Build Coastguard Worker class InvalidationController;
51*c8dee2aaSAndroid Build Coastguard Worker }
52*c8dee2aaSAndroid Build Coastguard Worker 
53*c8dee2aaSAndroid Build Coastguard Worker namespace skottie::internal {
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker // https://g-issues.chromium.org/issues/40064011
56*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_ENABLE_SKOTTIE_SKSLEFFECT)
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker class SkSLShaderNode final : public sksg::CustomRenderNode {
59*c8dee2aaSAndroid Build Coastguard Worker public:
SkSLShaderNode(sk_sp<RenderNode> child,const SkSize & content_size)60*c8dee2aaSAndroid Build Coastguard Worker     explicit SkSLShaderNode(sk_sp<RenderNode> child, const SkSize& content_size)
61*c8dee2aaSAndroid Build Coastguard Worker         : INHERITED({std::move(child)})
62*c8dee2aaSAndroid Build Coastguard Worker         , fContentSize(content_size) {}
63*c8dee2aaSAndroid Build Coastguard Worker 
contentShader()64*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> contentShader() {
65*c8dee2aaSAndroid Build Coastguard Worker         if (!fContentShader || this->hasChildrenInval()) {
66*c8dee2aaSAndroid Build Coastguard Worker             const auto& child = this->children()[0];
67*c8dee2aaSAndroid Build Coastguard Worker             child->revalidate(nullptr, SkMatrix::I());
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker             SkPictureRecorder recorder;
70*c8dee2aaSAndroid Build Coastguard Worker             child->render(recorder.beginRecording(SkRect::MakeSize(fContentSize)));
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker             fContentShader = recorder.finishRecordingAsPicture()
73*c8dee2aaSAndroid Build Coastguard Worker                     ->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkFilterMode::kLinear,
74*c8dee2aaSAndroid Build Coastguard Worker                                  nullptr, nullptr);
75*c8dee2aaSAndroid Build Coastguard Worker         }
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker         return fContentShader;
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     SG_ATTRIBUTE(Shader, sk_sp<SkShader>, fEffectShader)
81*c8dee2aaSAndroid Build Coastguard Worker private:
onRevalidate(sksg::InvalidationController * ic,const SkMatrix & ctm)82*c8dee2aaSAndroid Build Coastguard Worker     SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
83*c8dee2aaSAndroid Build Coastguard Worker         const auto& child = this->children()[0];
84*c8dee2aaSAndroid Build Coastguard Worker         return child->revalidate(ic, ctm);
85*c8dee2aaSAndroid Build Coastguard Worker     }
86*c8dee2aaSAndroid Build Coastguard Worker 
onRender(SkCanvas * canvas,const RenderContext * ctx) const87*c8dee2aaSAndroid Build Coastguard Worker     void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
88*c8dee2aaSAndroid Build Coastguard Worker         const auto& bounds = this->bounds();
89*c8dee2aaSAndroid Build Coastguard Worker         const auto local_ctx = ScopedRenderContext(canvas, ctx)
90*c8dee2aaSAndroid Build Coastguard Worker                 .setIsolation(bounds, canvas->getTotalMatrix(), true);
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker         canvas->saveLayer(&bounds, nullptr);
93*c8dee2aaSAndroid Build Coastguard Worker         this->children()[0]->render(canvas, local_ctx);
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         SkPaint effect_paint;
96*c8dee2aaSAndroid Build Coastguard Worker         effect_paint.setShader(fEffectShader);
97*c8dee2aaSAndroid Build Coastguard Worker         effect_paint.setBlendMode(SkBlendMode::kSrcIn);
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPaint(effect_paint);
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker 
onNodeAt(const SkPoint &) const102*c8dee2aaSAndroid Build Coastguard Worker     const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fEffectShader;
105*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fContentShader;
106*c8dee2aaSAndroid Build Coastguard Worker     const SkSize fContentSize;
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = sksg::CustomRenderNode;
109*c8dee2aaSAndroid Build Coastguard Worker };
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker class SkSLEffectBase {
112*c8dee2aaSAndroid Build Coastguard Worker public:
SkSLEffectBase(const skjson::ArrayValue & jprops,const AnimationBuilder & abuilder)113*c8dee2aaSAndroid Build Coastguard Worker     SkSLEffectBase(const skjson::ArrayValue& jprops,
114*c8dee2aaSAndroid Build Coastguard Worker                    const AnimationBuilder& abuilder)
115*c8dee2aaSAndroid Build Coastguard Worker     {
116*c8dee2aaSAndroid Build Coastguard Worker         if (jprops.size() < 1) {
117*c8dee2aaSAndroid Build Coastguard Worker             return;
118*c8dee2aaSAndroid Build Coastguard Worker         }
119*c8dee2aaSAndroid Build Coastguard Worker         const skjson::ObjectValue* jSkSL = jprops[kSkSL_index];
120*c8dee2aaSAndroid Build Coastguard Worker         if (!jSkSL) {
121*c8dee2aaSAndroid Build Coastguard Worker             return;
122*c8dee2aaSAndroid Build Coastguard Worker         }
123*c8dee2aaSAndroid Build Coastguard Worker         const skjson::StringValue* jShader = (*jSkSL)["sh"];
124*c8dee2aaSAndroid Build Coastguard Worker         if (!jShader) {
125*c8dee2aaSAndroid Build Coastguard Worker             return;
126*c8dee2aaSAndroid Build Coastguard Worker         }
127*c8dee2aaSAndroid Build Coastguard Worker         SkString shader = SkString(jShader->begin(), jShader->size());
128*c8dee2aaSAndroid Build Coastguard Worker         auto result = SkRuntimeEffect::MakeForShader(shader, {});
129*c8dee2aaSAndroid Build Coastguard Worker         if (!result.effect) {
130*c8dee2aaSAndroid Build Coastguard Worker             abuilder.log(Logger::Level::kError, nullptr, "Failed to parse SkSL shader: %s",
131*c8dee2aaSAndroid Build Coastguard Worker                result.errorText.c_str());
132*c8dee2aaSAndroid Build Coastguard Worker             return;
133*c8dee2aaSAndroid Build Coastguard Worker         }
134*c8dee2aaSAndroid Build Coastguard Worker         fEffect = std::move(result.effect);
135*c8dee2aaSAndroid Build Coastguard Worker     }
136*c8dee2aaSAndroid Build Coastguard Worker protected:
137*c8dee2aaSAndroid Build Coastguard Worker     enum : size_t {
138*c8dee2aaSAndroid Build Coastguard Worker         kSkSL_index = 0,
139*c8dee2aaSAndroid Build Coastguard Worker         kFirstUniform_index = 1,
140*c8dee2aaSAndroid Build Coastguard Worker     };
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker     enum : size_t {
143*c8dee2aaSAndroid Build Coastguard Worker         kSkSLProp_uniform = 0,   // Maps to the integer value 1
144*c8dee2aaSAndroid Build Coastguard Worker         kSkSLProp_image = 98, // Maps to the integer value 98
145*c8dee2aaSAndroid Build Coastguard Worker         kSkSLProp_layer = 99  // Maps to the integer value 99
146*c8dee2aaSAndroid Build Coastguard Worker     };
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker     struct ChildData {
149*c8dee2aaSAndroid Build Coastguard Worker         int type;
150*c8dee2aaSAndroid Build Coastguard Worker         SkString name;
151*c8dee2aaSAndroid Build Coastguard Worker         SkRuntimeEffect::ChildPtr child;
152*c8dee2aaSAndroid Build Coastguard Worker     };
153*c8dee2aaSAndroid Build Coastguard Worker 
bindUniforms(const skjson::ArrayValue & jprops,const AnimationBuilder & abuilder,AnimatablePropertyContainer * const & container)154*c8dee2aaSAndroid Build Coastguard Worker     void bindUniforms(const skjson::ArrayValue& jprops,
155*c8dee2aaSAndroid Build Coastguard Worker                       const AnimationBuilder& abuilder,
156*c8dee2aaSAndroid Build Coastguard Worker                       AnimatablePropertyContainer * const &container) {
157*c8dee2aaSAndroid Build Coastguard Worker         // construct dynamic uniform list from jprops, skip SkSL property
158*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = kFirstUniform_index; i < jprops.size(); i++) {
159*c8dee2aaSAndroid Build Coastguard Worker             const skjson::ObjectValue* jprop = jprops[i];
160*c8dee2aaSAndroid Build Coastguard Worker             if (!jprop) { continue; }
161*c8dee2aaSAndroid Build Coastguard Worker             const skjson::StringValue* uniformName = (*jprop)["nm"];
162*c8dee2aaSAndroid Build Coastguard Worker             if (!uniformName) { continue; }
163*c8dee2aaSAndroid Build Coastguard Worker             int type = ParseDefault<int>((*jprop)["ty"], kSkSLProp_uniform);
164*c8dee2aaSAndroid Build Coastguard Worker             if (type == kSkSLProp_uniform) {
165*c8dee2aaSAndroid Build Coastguard Worker                 auto uniformTuple = std::make_tuple(SkString(uniformName->begin(),
166*c8dee2aaSAndroid Build Coastguard Worker                                                             uniformName->size()),
167*c8dee2aaSAndroid Build Coastguard Worker                                                     std::make_unique<VectorValue>());
168*c8dee2aaSAndroid Build Coastguard Worker                 fUniforms.push_back(std::move(uniformTuple));
169*c8dee2aaSAndroid Build Coastguard Worker                 container->bind(abuilder, (*jprop)["v"], std::get<1>(fUniforms.back()).get());
170*c8dee2aaSAndroid Build Coastguard Worker             } else if (type == kSkSLProp_image) {
171*c8dee2aaSAndroid Build Coastguard Worker                 const skjson::ObjectValue* jimageRef = (*jprop)["v"];
172*c8dee2aaSAndroid Build Coastguard Worker                 const AnimationBuilder::ScopedAssetRef footageAsset(&abuilder, *jimageRef);
173*c8dee2aaSAndroid Build Coastguard Worker                 const auto* asset_info = abuilder.loadFootageAsset(*footageAsset);
174*c8dee2aaSAndroid Build Coastguard Worker                 if (asset_info && asset_info->fAsset) {
175*c8dee2aaSAndroid Build Coastguard Worker                     // TODO: instead of resolving shaders here, save a collection of footage assets
176*c8dee2aaSAndroid Build Coastguard Worker                     // onSync, grab the correct frameData and create a shader then
177*c8dee2aaSAndroid Build Coastguard Worker                     auto frameData = asset_info->fAsset->getFrameData(0);
178*c8dee2aaSAndroid Build Coastguard Worker                     SkSamplingOptions sampling(SkFilterMode::kLinear);
179*c8dee2aaSAndroid Build Coastguard Worker                     fChildren.push_back({type, SkString(uniformName->begin(), uniformName->size()),
180*c8dee2aaSAndroid Build Coastguard Worker                                             frameData.image->makeShader(sampling)});
181*c8dee2aaSAndroid Build Coastguard Worker                 } else {
182*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("cannot find asset for custom shader effect");
183*c8dee2aaSAndroid Build Coastguard Worker                 }
184*c8dee2aaSAndroid Build Coastguard Worker             } else if (type == kSkSLProp_layer) { /* layer content */
185*c8dee2aaSAndroid Build Coastguard Worker                 fChildren.push_back({type, SkString(uniformName->begin(), uniformName->size()),
186*c8dee2aaSAndroid Build Coastguard Worker                     SkRuntimeEffect::ChildPtr()});
187*c8dee2aaSAndroid Build Coastguard Worker             }
188*c8dee2aaSAndroid Build Coastguard Worker         }
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
buildUniformData() const191*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> buildUniformData() const {
192*c8dee2aaSAndroid Build Coastguard Worker         auto uniformData = SkData::MakeZeroInitialized(fEffect->uniformSize());
193*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(uniformData);
194*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& uniform : fUniforms) {
195*c8dee2aaSAndroid Build Coastguard Worker             const auto& name = std::get<0>(uniform);
196*c8dee2aaSAndroid Build Coastguard Worker             const auto& data = std::get<1>(uniform);
197*c8dee2aaSAndroid Build Coastguard Worker             auto metadata = fEffect->findUniform(name.c_str());
198*c8dee2aaSAndroid Build Coastguard Worker             if (metadata && metadata->count == static_cast<int>(data->size())) {
199*c8dee2aaSAndroid Build Coastguard Worker                 auto dst = reinterpret_cast<uint8_t*>(uniformData->writable_data())
200*c8dee2aaSAndroid Build Coastguard Worker                     + metadata->offset;
201*c8dee2aaSAndroid Build Coastguard Worker                 memcpy(reinterpret_cast<void*>(dst), data->data(), data->size() * sizeof(float));
202*c8dee2aaSAndroid Build Coastguard Worker             } else {
203*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("cannot set malformed uniform: %s\n", name.c_str());
204*c8dee2aaSAndroid Build Coastguard Worker             }
205*c8dee2aaSAndroid Build Coastguard Worker         }
206*c8dee2aaSAndroid Build Coastguard Worker         return uniformData;
207*c8dee2aaSAndroid Build Coastguard Worker     }
208*c8dee2aaSAndroid Build Coastguard Worker 
buildChildrenData(sk_sp<SkSLShaderNode> node) const209*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkRuntimeEffect::ChildPtr> buildChildrenData(sk_sp<SkSLShaderNode> node) const {
210*c8dee2aaSAndroid Build Coastguard Worker         std::vector<SkRuntimeEffect::ChildPtr> childrenData(fEffect->children().size());
211*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& childData : fChildren) {
212*c8dee2aaSAndroid Build Coastguard Worker             auto metadata = fEffect->findChild(childData.name.c_str());
213*c8dee2aaSAndroid Build Coastguard Worker             if (childData.type == kSkSLProp_layer) {
214*c8dee2aaSAndroid Build Coastguard Worker                 childrenData[metadata->index] = (node->contentShader());
215*c8dee2aaSAndroid Build Coastguard Worker             } else if (childData.type == kSkSLProp_image) {
216*c8dee2aaSAndroid Build Coastguard Worker                 childrenData[metadata->index] = childData.child;
217*c8dee2aaSAndroid Build Coastguard Worker             }
218*c8dee2aaSAndroid Build Coastguard Worker         }
219*c8dee2aaSAndroid Build Coastguard Worker         return childrenData;
220*c8dee2aaSAndroid Build Coastguard Worker     }
221*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkRuntimeEffect> fEffect;
222*c8dee2aaSAndroid Build Coastguard Worker     std::vector<std::tuple<SkString, std::unique_ptr<VectorValue>>> fUniforms;
223*c8dee2aaSAndroid Build Coastguard Worker     std::vector<ChildData> fChildren;
224*c8dee2aaSAndroid Build Coastguard Worker };
225*c8dee2aaSAndroid Build Coastguard Worker 
226*c8dee2aaSAndroid Build Coastguard Worker class SkSLShaderAdapter final : public DiscardableAdapterBase<SkSLShaderAdapter,
227*c8dee2aaSAndroid Build Coastguard Worker                                                               SkSLShaderNode>,
228*c8dee2aaSAndroid Build Coastguard Worker                                 public SkSLEffectBase {
229*c8dee2aaSAndroid Build Coastguard Worker public:
SkSLShaderAdapter(const skjson::ArrayValue & jprops,const AnimationBuilder & abuilder,sk_sp<SkSLShaderNode> node)230*c8dee2aaSAndroid Build Coastguard Worker     SkSLShaderAdapter(const skjson::ArrayValue& jprops,
231*c8dee2aaSAndroid Build Coastguard Worker                       const AnimationBuilder& abuilder,
232*c8dee2aaSAndroid Build Coastguard Worker                       sk_sp<SkSLShaderNode> node)
233*c8dee2aaSAndroid Build Coastguard Worker         : DiscardableAdapterBase<SkSLShaderAdapter, SkSLShaderNode>(std::move(node))
234*c8dee2aaSAndroid Build Coastguard Worker         , SkSLEffectBase(jprops, abuilder)
235*c8dee2aaSAndroid Build Coastguard Worker     {
236*c8dee2aaSAndroid Build Coastguard Worker         this->bindUniforms(jprops, abuilder, this);
237*c8dee2aaSAndroid Build Coastguard Worker     }
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker private:
onSync()240*c8dee2aaSAndroid Build Coastguard Worker     void onSync() override {
241*c8dee2aaSAndroid Build Coastguard Worker         if (!fEffect) {
242*c8dee2aaSAndroid Build Coastguard Worker             return;
243*c8dee2aaSAndroid Build Coastguard Worker         }
244*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkShader> shader =
245*c8dee2aaSAndroid Build Coastguard Worker                 fEffect->makeShader(buildUniformData(), SkSpan(buildChildrenData(this->node())));
246*c8dee2aaSAndroid Build Coastguard Worker         this->node()->setShader(std::move(shader));
247*c8dee2aaSAndroid Build Coastguard Worker     }
248*c8dee2aaSAndroid Build Coastguard Worker };
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker class SkSLColorFilterAdapter final : public DiscardableAdapterBase<SkSLColorFilterAdapter,
251*c8dee2aaSAndroid Build Coastguard Worker                                                              sksg::ExternalColorFilter>
252*c8dee2aaSAndroid Build Coastguard Worker                                    , public SkSLEffectBase {
253*c8dee2aaSAndroid Build Coastguard Worker public:
SkSLColorFilterAdapter(const skjson::ArrayValue & jprops,const AnimationBuilder & abuilder,sk_sp<sksg::ExternalColorFilter> node)254*c8dee2aaSAndroid Build Coastguard Worker     SkSLColorFilterAdapter(const skjson::ArrayValue& jprops,
255*c8dee2aaSAndroid Build Coastguard Worker                       const AnimationBuilder& abuilder,
256*c8dee2aaSAndroid Build Coastguard Worker                       sk_sp<sksg::ExternalColorFilter> node)
257*c8dee2aaSAndroid Build Coastguard Worker         : DiscardableAdapterBase<SkSLColorFilterAdapter, sksg::ExternalColorFilter>(std::move(node))
258*c8dee2aaSAndroid Build Coastguard Worker         , SkSLEffectBase(jprops, abuilder)
259*c8dee2aaSAndroid Build Coastguard Worker     {
260*c8dee2aaSAndroid Build Coastguard Worker         this->bindUniforms(jprops, abuilder, this);
261*c8dee2aaSAndroid Build Coastguard Worker     }
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker private:
onSync()264*c8dee2aaSAndroid Build Coastguard Worker     void onSync() override {
265*c8dee2aaSAndroid Build Coastguard Worker         if (!fEffect) {
266*c8dee2aaSAndroid Build Coastguard Worker             return;
267*c8dee2aaSAndroid Build Coastguard Worker         }
268*c8dee2aaSAndroid Build Coastguard Worker         auto cf = fEffect->makeColorFilter(buildUniformData());
269*c8dee2aaSAndroid Build Coastguard Worker         this->node()->setColorFilter(std::move(cf));
270*c8dee2aaSAndroid Build Coastguard Worker     }
271*c8dee2aaSAndroid Build Coastguard Worker };
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker #endif  // SK_ENABLE_SKOTTIE_SKSLEFFECT
274*c8dee2aaSAndroid Build Coastguard Worker 
attachSkSLShader(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const275*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> EffectBuilder::attachSkSLShader(const skjson::ArrayValue& jprops,
276*c8dee2aaSAndroid Build Coastguard Worker                                                         sk_sp<sksg::RenderNode> layer) const {
277*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_ENABLE_SKOTTIE_SKSLEFFECT)
278*c8dee2aaSAndroid Build Coastguard Worker     auto shaderNode = sk_make_sp<SkSLShaderNode>(std::move(layer), fLayerSize);
279*c8dee2aaSAndroid Build Coastguard Worker     return fBuilder->attachDiscardableAdapter<SkSLShaderAdapter>(jprops, *fBuilder,
280*c8dee2aaSAndroid Build Coastguard Worker                                                                  std::move(shaderNode));
281*c8dee2aaSAndroid Build Coastguard Worker #else
282*c8dee2aaSAndroid Build Coastguard Worker     return layer;
283*c8dee2aaSAndroid Build Coastguard Worker #endif
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker 
attachSkSLColorFilter(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const286*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> EffectBuilder::attachSkSLColorFilter(const skjson::ArrayValue& jprops,
287*c8dee2aaSAndroid Build Coastguard Worker                                                              sk_sp<sksg::RenderNode> layer) const {
288*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_ENABLE_SKOTTIE_SKSLEFFECT)
289*c8dee2aaSAndroid Build Coastguard Worker     auto cfNode = sksg::ExternalColorFilter::Make(std::move(layer));
290*c8dee2aaSAndroid Build Coastguard Worker     return fBuilder->attachDiscardableAdapter<SkSLColorFilterAdapter>(jprops, *fBuilder,
291*c8dee2aaSAndroid Build Coastguard Worker                                                                       std::move(cfNode));
292*c8dee2aaSAndroid Build Coastguard Worker #else
293*c8dee2aaSAndroid Build Coastguard Worker     return layer;
294*c8dee2aaSAndroid Build Coastguard Worker #endif
295*c8dee2aaSAndroid Build Coastguard Worker }
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker } // namespace skottie::internal
298