1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2024 Google LLC
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/gpu/graphite/precompile/PrecompileRuntimeEffect.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/PrecompileBase.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/PrecompileBlender.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/PrecompileShader.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyHelpers.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParams.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParamsKey.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileBaseComplete.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker namespace {
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
28*c8dee2aaSAndroid Build Coastguard Worker
precompilebase_is_valid_as_child(const PrecompileBase * child)29*c8dee2aaSAndroid Build Coastguard Worker bool precompilebase_is_valid_as_child(const PrecompileBase *child) {
30*c8dee2aaSAndroid Build Coastguard Worker if (!child) {
31*c8dee2aaSAndroid Build Coastguard Worker return true;
32*c8dee2aaSAndroid Build Coastguard Worker }
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker switch (child->type()) {
35*c8dee2aaSAndroid Build Coastguard Worker case PrecompileBase::Type::kShader:
36*c8dee2aaSAndroid Build Coastguard Worker case PrecompileBase::Type::kColorFilter:
37*c8dee2aaSAndroid Build Coastguard Worker case PrecompileBase::Type::kBlender:
38*c8dee2aaSAndroid Build Coastguard Worker return true;
39*c8dee2aaSAndroid Build Coastguard Worker default:
40*c8dee2aaSAndroid Build Coastguard Worker return false;
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_DEBUG
45*c8dee2aaSAndroid Build Coastguard Worker
num_options_in_set(const SkSpan<const sk_sp<PrecompileBase>> & optionSet)46*c8dee2aaSAndroid Build Coastguard Worker int num_options_in_set(const SkSpan<const sk_sp<PrecompileBase>>& optionSet) {
47*c8dee2aaSAndroid Build Coastguard Worker int numOptions = 0;
48*c8dee2aaSAndroid Build Coastguard Worker for (const sk_sp<PrecompileBase>& childOption : optionSet) {
49*c8dee2aaSAndroid Build Coastguard Worker // A missing child will fall back to a passthrough object
50*c8dee2aaSAndroid Build Coastguard Worker if (childOption) {
51*c8dee2aaSAndroid Build Coastguard Worker numOptions += childOption->priv().numCombinations();
52*c8dee2aaSAndroid Build Coastguard Worker } else {
53*c8dee2aaSAndroid Build Coastguard Worker ++numOptions;
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker return numOptions;
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker // Convert from runtime effect type to precompile type
to_precompile_type(SkRuntimeEffect::ChildType childType)61*c8dee2aaSAndroid Build Coastguard Worker PrecompileBase::Type to_precompile_type(SkRuntimeEffect::ChildType childType) {
62*c8dee2aaSAndroid Build Coastguard Worker switch(childType) {
63*c8dee2aaSAndroid Build Coastguard Worker case SkRuntimeEffect::ChildType::kShader: return PrecompileBase::Type::kShader;
64*c8dee2aaSAndroid Build Coastguard Worker case SkRuntimeEffect::ChildType::kColorFilter: return PrecompileBase::Type::kColorFilter;
65*c8dee2aaSAndroid Build Coastguard Worker case SkRuntimeEffect::ChildType::kBlender: return PrecompileBase::Type::kBlender;
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker
children_are_valid(SkRuntimeEffect * effect,SkSpan<const PrecompileChildOptions> childOptions)70*c8dee2aaSAndroid Build Coastguard Worker bool children_are_valid(SkRuntimeEffect* effect,
71*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const PrecompileChildOptions> childOptions) {
72*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkRuntimeEffect::Child> childInfo = effect->children();
73*c8dee2aaSAndroid Build Coastguard Worker if (childOptions.size() != childInfo.size()) {
74*c8dee2aaSAndroid Build Coastguard Worker return false;
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < childInfo.size(); ++i) {
78*c8dee2aaSAndroid Build Coastguard Worker const PrecompileBase::Type expectedType = to_precompile_type(childInfo[i].type);
79*c8dee2aaSAndroid Build Coastguard Worker for (const sk_sp<PrecompileBase>& childOption : childOptions[i]) {
80*c8dee2aaSAndroid Build Coastguard Worker if (childOption && expectedType != childOption->type()) {
81*c8dee2aaSAndroid Build Coastguard Worker return false;
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker return true;
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker template<typename T>
92*c8dee2aaSAndroid Build Coastguard Worker class PrecompileRTEffect : public T {
93*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileRTEffect(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)94*c8dee2aaSAndroid Build Coastguard Worker PrecompileRTEffect(sk_sp<SkRuntimeEffect> effect,
95*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const PrecompileChildOptions> childOptions)
96*c8dee2aaSAndroid Build Coastguard Worker : fEffect(std::move(effect)) {
97*c8dee2aaSAndroid Build Coastguard Worker fChildOptions.reserve(childOptions.size());
98*c8dee2aaSAndroid Build Coastguard Worker for (PrecompileChildOptions c : childOptions) {
99*c8dee2aaSAndroid Build Coastguard Worker fChildOptions.push_back({ c.begin(), c.end() });
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker fNumSlotCombinations.reserve(childOptions.size());
103*c8dee2aaSAndroid Build Coastguard Worker fNumChildCombinations = 1;
104*c8dee2aaSAndroid Build Coastguard Worker for (const std::vector<sk_sp<PrecompileBase>>& optionSet : fChildOptions) {
105*c8dee2aaSAndroid Build Coastguard Worker fNumSlotCombinations.push_back(num_options_in_set(optionSet));
106*c8dee2aaSAndroid Build Coastguard Worker fNumChildCombinations *= fNumSlotCombinations.back();
107*c8dee2aaSAndroid Build Coastguard Worker }
108*c8dee2aaSAndroid Build Coastguard Worker
109*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fChildOptions.size() == fEffect->children().size());
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const113*c8dee2aaSAndroid Build Coastguard Worker int numChildCombinations() const override { return fNumChildCombinations; }
114*c8dee2aaSAndroid Build Coastguard Worker
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const115*c8dee2aaSAndroid Build Coastguard Worker void addToKey(const KeyContext& keyContext,
116*c8dee2aaSAndroid Build Coastguard Worker PaintParamsKeyBuilder* builder,
117*c8dee2aaSAndroid Build Coastguard Worker PipelineDataGatherer* gatherer,
118*c8dee2aaSAndroid Build Coastguard Worker int desiredCombination) const override {
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(desiredCombination < this->numCombinations());
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkRuntimeEffect::Child> childInfo = fEffect->children();
123*c8dee2aaSAndroid Build Coastguard Worker
124*c8dee2aaSAndroid Build Coastguard Worker RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { fEffect });
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker int remainingCombinations = desiredCombination;
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker for (size_t rowIndex = 0; rowIndex < fChildOptions.size(); ++rowIndex) {
131*c8dee2aaSAndroid Build Coastguard Worker const std::vector<sk_sp<PrecompileBase>>& slotOptions = fChildOptions[rowIndex];
132*c8dee2aaSAndroid Build Coastguard Worker int numSlotCombinations = fNumSlotCombinations[rowIndex];
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker const int slotOption = remainingCombinations % numSlotCombinations;
135*c8dee2aaSAndroid Build Coastguard Worker remainingCombinations /= numSlotCombinations;
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker auto [option, childOptions] = PrecompileBase::SelectOption(
138*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const sk_sp<PrecompileBase>>(slotOptions),
139*c8dee2aaSAndroid Build Coastguard Worker slotOption);
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(precompilebase_is_valid_as_child(option.get()));
142*c8dee2aaSAndroid Build Coastguard Worker if (option) {
143*c8dee2aaSAndroid Build Coastguard Worker option->priv().addToKey(keyContext, builder, gatherer, childOptions);
144*c8dee2aaSAndroid Build Coastguard Worker } else {
145*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(childOptions == 0);
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker // We don't have a child effect. Substitute in a no-op effect.
148*c8dee2aaSAndroid Build Coastguard Worker switch (childInfo[rowIndex].type) {
149*c8dee2aaSAndroid Build Coastguard Worker case SkRuntimeEffect::ChildType::kShader:
150*c8dee2aaSAndroid Build Coastguard Worker // A missing shader returns transparent black
151*c8dee2aaSAndroid Build Coastguard Worker SolidColorShaderBlock::AddBlock(childContext, builder, gatherer,
152*c8dee2aaSAndroid Build Coastguard Worker SK_PMColor4fTRANSPARENT);
153*c8dee2aaSAndroid Build Coastguard Worker break;
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker case SkRuntimeEffect::ChildType::kColorFilter:
156*c8dee2aaSAndroid Build Coastguard Worker // A "passthrough" shader returns the input color as-is.
157*c8dee2aaSAndroid Build Coastguard Worker builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
158*c8dee2aaSAndroid Build Coastguard Worker break;
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker case SkRuntimeEffect::ChildType::kBlender:
161*c8dee2aaSAndroid Build Coastguard Worker // A "passthrough" blender performs `blend_src_over(src, dest)`.
162*c8dee2aaSAndroid Build Coastguard Worker AddFixedBlendMode(childContext, builder, gatherer, SkBlendMode::kSrcOver);
163*c8dee2aaSAndroid Build Coastguard Worker break;
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Worker builder->endBlock();
169*c8dee2aaSAndroid Build Coastguard Worker }
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> fEffect;
172*c8dee2aaSAndroid Build Coastguard Worker std::vector<std::vector<sk_sp<PrecompileBase>>> fChildOptions;
173*c8dee2aaSAndroid Build Coastguard Worker skia_private::TArray<int> fNumSlotCombinations;
174*c8dee2aaSAndroid Build Coastguard Worker int fNumChildCombinations;
175*c8dee2aaSAndroid Build Coastguard Worker };
176*c8dee2aaSAndroid Build Coastguard Worker
MakePrecompileShader(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)177*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileRuntimeEffects::MakePrecompileShader(
178*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> effect,
179*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const PrecompileChildOptions> childOptions) {
180*c8dee2aaSAndroid Build Coastguard Worker if (!effect || !effect->allowShader()) {
181*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker if (!children_are_valid(effect.get(), childOptions)) {
185*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
186*c8dee2aaSAndroid Build Coastguard Worker }
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker return sk_make_sp<PrecompileRTEffect<PrecompileShader>>(std::move(effect), childOptions);
189*c8dee2aaSAndroid Build Coastguard Worker }
190*c8dee2aaSAndroid Build Coastguard Worker
MakePrecompileColorFilter(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)191*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileColorFilter> PrecompileRuntimeEffects::MakePrecompileColorFilter(
192*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> effect,
193*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const PrecompileChildOptions> childOptions) {
194*c8dee2aaSAndroid Build Coastguard Worker if (!effect || !effect->allowColorFilter()) {
195*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker if (!children_are_valid(effect.get(), childOptions)) {
199*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker
202*c8dee2aaSAndroid Build Coastguard Worker return sk_make_sp<PrecompileRTEffect<PrecompileColorFilter>>(std::move(effect), childOptions);
203*c8dee2aaSAndroid Build Coastguard Worker }
204*c8dee2aaSAndroid Build Coastguard Worker
MakePrecompileBlender(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)205*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileBlender> PrecompileRuntimeEffects::MakePrecompileBlender(
206*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> effect,
207*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const PrecompileChildOptions> childOptions) {
208*c8dee2aaSAndroid Build Coastguard Worker if (!effect || !effect->allowBlender()) {
209*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
210*c8dee2aaSAndroid Build Coastguard Worker }
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker if (!children_are_valid(effect.get(), childOptions)) {
213*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
214*c8dee2aaSAndroid Build Coastguard Worker }
215*c8dee2aaSAndroid Build Coastguard Worker
216*c8dee2aaSAndroid Build Coastguard Worker return sk_make_sp<PrecompileRTEffect<PrecompileBlender>>(std::move(effect), childOptions);
217*c8dee2aaSAndroid Build Coastguard Worker }
218*c8dee2aaSAndroid Build Coastguard Worker
219*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
220