xref: /aosp_15_r20/external/skia/src/gpu/graphite/precompile/PrecompileShader.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/PrecompileShader.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.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 "src/core/SkColorSpacePriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkKnownRuntimeEffects.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/Blend.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/BuiltInCodeSnippetID.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyContext.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyHelpers.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParams.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParamsKey.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PrecompileInternal.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ReadSwizzle.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileBaseComplete.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileShaderPriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/precompile/PrecompileShadersPriv.h"
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker PrecompileShader::~PrecompileShader() = default;
33*c8dee2aaSAndroid Build Coastguard Worker 
makeWithColorFilter(sk_sp<PrecompileColorFilter> cf) const34*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShader::makeWithColorFilter(
35*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<PrecompileColorFilter> cf) const {
36*c8dee2aaSAndroid Build Coastguard Worker     if (!cf) {
37*c8dee2aaSAndroid Build Coastguard Worker         return sk_ref_sp(this);
38*c8dee2aaSAndroid Build Coastguard Worker     }
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::ColorFilter({ sk_ref_sp(this) }, { std::move(cf) });
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker 
makeWithWorkingColorSpace(sk_sp<SkColorSpace> cs) const43*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShader::makeWithWorkingColorSpace(sk_sp<SkColorSpace> cs) const {
44*c8dee2aaSAndroid Build Coastguard Worker     if (!cs) {
45*c8dee2aaSAndroid Build Coastguard Worker         return sk_ref_sp(this);
46*c8dee2aaSAndroid Build Coastguard Worker     }
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::WorkingColorSpace({ sk_ref_sp(this) }, { std::move(cs) });
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
52*c8dee2aaSAndroid Build Coastguard Worker class PrecompileEmptyShader final : public PrecompileShader {
53*c8dee2aaSAndroid Build Coastguard Worker private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const54*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
55*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
56*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
57*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination == 0); // The empty shader only ever has one combination
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker         builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
62*c8dee2aaSAndroid Build Coastguard Worker     }
63*c8dee2aaSAndroid Build Coastguard Worker };
64*c8dee2aaSAndroid Build Coastguard Worker 
Empty()65*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Empty() {
66*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileEmptyShader>();
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
70*c8dee2aaSAndroid Build Coastguard Worker class PrecompileColorShader final : public PrecompileShader {
71*c8dee2aaSAndroid Build Coastguard Worker private:
isConstant(int desiredCombination) const72*c8dee2aaSAndroid Build Coastguard Worker     bool isConstant(int desiredCombination) const override {
73*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
74*c8dee2aaSAndroid Build Coastguard Worker         return true;
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const77*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
78*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
79*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
80*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker         // The white PMColor is just a placeholder for the actual paint params color
85*c8dee2aaSAndroid Build Coastguard Worker         SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, SK_PMColor4fWHITE);
86*c8dee2aaSAndroid Build Coastguard Worker     }
87*c8dee2aaSAndroid Build Coastguard Worker };
88*c8dee2aaSAndroid Build Coastguard Worker 
Color()89*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Color() {
90*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileColorShader>();
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker // The colorSpace is safe to ignore - it is just applied to the color and doesn't modify the
94*c8dee2aaSAndroid Build Coastguard Worker // generated program.
Color(sk_sp<SkColorSpace>)95*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Color(sk_sp<SkColorSpace>) {
96*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileColorShader>();
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
100*c8dee2aaSAndroid Build Coastguard Worker class PrecompileBlendShader final : public PrecompileShader {
101*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileBlendShader(PrecompileBlenderList && blenders,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)102*c8dee2aaSAndroid Build Coastguard Worker     PrecompileBlendShader(PrecompileBlenderList&& blenders,
103*c8dee2aaSAndroid Build Coastguard Worker                           SkSpan<const sk_sp<PrecompileShader>> dsts,
104*c8dee2aaSAndroid Build Coastguard Worker                           SkSpan<const sk_sp<PrecompileShader>> srcs)
105*c8dee2aaSAndroid Build Coastguard Worker             : fBlenderOptions(std::move(blenders))
106*c8dee2aaSAndroid Build Coastguard Worker             , fDstOptions(dsts.begin(), dsts.end())
107*c8dee2aaSAndroid Build Coastguard Worker             , fSrcOptions(srcs.begin(), srcs.end()) {
108*c8dee2aaSAndroid Build Coastguard Worker         fNumDstCombos = 0;
109*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& d : fDstOptions) {
110*c8dee2aaSAndroid Build Coastguard Worker             fNumDstCombos += d->priv().numCombinations();
111*c8dee2aaSAndroid Build Coastguard Worker         }
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker         fNumSrcCombos = 0;
114*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& s : fSrcOptions) {
115*c8dee2aaSAndroid Build Coastguard Worker             fNumSrcCombos += s->priv().numCombinations();
116*c8dee2aaSAndroid Build Coastguard Worker         }
117*c8dee2aaSAndroid Build Coastguard Worker     }
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const120*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override {
121*c8dee2aaSAndroid Build Coastguard Worker         return fBlenderOptions.numCombinations() * fNumDstCombos * fNumSrcCombos;
122*c8dee2aaSAndroid Build Coastguard Worker     }
123*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const124*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
125*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
126*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
127*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
128*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numCombinations());
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker         const int desiredDstCombination = desiredCombination % fNumDstCombos;
131*c8dee2aaSAndroid Build Coastguard Worker         int remainingCombinations = desiredCombination / fNumDstCombos;
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker         const int desiredSrcCombination = remainingCombinations % fNumSrcCombos;
134*c8dee2aaSAndroid Build Coastguard Worker         remainingCombinations /= fNumSrcCombos;
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker         int desiredBlendCombination = remainingCombinations;
137*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredBlendCombination < fBlenderOptions.numCombinations());
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker         auto [blender, blenderCombination] = fBlenderOptions.selectOption(desiredBlendCombination);
140*c8dee2aaSAndroid Build Coastguard Worker         if (blender->priv().asBlendMode()) {
141*c8dee2aaSAndroid Build Coastguard Worker             // Coefficient and HSLC blends, and other fixed SkBlendMode blenders use the
142*c8dee2aaSAndroid Build Coastguard Worker             // BlendCompose block to organize the children.
143*c8dee2aaSAndroid Build Coastguard Worker             BlendComposeBlock::BeginBlock(keyContext, builder, gatherer);
144*c8dee2aaSAndroid Build Coastguard Worker         } else {
145*c8dee2aaSAndroid Build Coastguard Worker             // Runtime blenders are wrapped in the kBlend runtime shader, although functionally
146*c8dee2aaSAndroid Build Coastguard Worker             // it is identical to the BlendCompose snippet.
147*c8dee2aaSAndroid Build Coastguard Worker             const SkRuntimeEffect* blendEffect =
148*c8dee2aaSAndroid Build Coastguard Worker                     GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kBlend);
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker             RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
151*c8dee2aaSAndroid Build Coastguard Worker                                            { sk_ref_sp(blendEffect) });
152*c8dee2aaSAndroid Build Coastguard Worker         }
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker         AddToKey<PrecompileShader>(keyContext, builder, gatherer, fSrcOptions,
155*c8dee2aaSAndroid Build Coastguard Worker                                    desiredSrcCombination);
156*c8dee2aaSAndroid Build Coastguard Worker         AddToKey<PrecompileShader>(keyContext, builder, gatherer, fDstOptions,
157*c8dee2aaSAndroid Build Coastguard Worker                                    desiredDstCombination);
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker         if (blender->priv().asBlendMode()) {
160*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(blenderCombination == 0);
161*c8dee2aaSAndroid Build Coastguard Worker             AddBlendMode(keyContext, builder, gatherer, *blender->priv().asBlendMode());
162*c8dee2aaSAndroid Build Coastguard Worker         } else {
163*c8dee2aaSAndroid Build Coastguard Worker             blender->priv().addToKey(keyContext, builder, gatherer, blenderCombination);
164*c8dee2aaSAndroid Build Coastguard Worker         }
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();  // BlendComposeBlock or RuntimeEffectBlock
167*c8dee2aaSAndroid Build Coastguard Worker     }
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker     PrecompileBlenderList fBlenderOptions;
170*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>> fDstOptions;
171*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>> fSrcOptions;
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker     int fNumDstCombos;
174*c8dee2aaSAndroid Build Coastguard Worker     int fNumSrcCombos;
175*c8dee2aaSAndroid Build Coastguard Worker };
176*c8dee2aaSAndroid Build Coastguard Worker 
Blend(SkSpan<const sk_sp<PrecompileBlender>> blenders,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)177*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Blend(
178*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileBlender>> blenders,
179*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> dsts,
180*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> srcs) {
181*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileBlendShader>(PrecompileBlenderList(blenders), dsts, srcs);
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker 
Blend(SkSpan<const SkBlendMode> blendModes,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)184*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Blend(
185*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const SkBlendMode> blendModes,
186*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> dsts,
187*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> srcs) {
188*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileBlendShader>(PrecompileBlenderList(blendModes), dsts, srcs);
189*c8dee2aaSAndroid Build Coastguard Worker }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
192*c8dee2aaSAndroid Build Coastguard Worker class PrecompileCoordClampShader final : public PrecompileShader {
193*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileCoordClampShader(SkSpan<const sk_sp<PrecompileShader>> shaders)194*c8dee2aaSAndroid Build Coastguard Worker     PrecompileCoordClampShader(SkSpan<const sk_sp<PrecompileShader>> shaders)
195*c8dee2aaSAndroid Build Coastguard Worker             : fShaders(shaders.begin(), shaders.end()) {
196*c8dee2aaSAndroid Build Coastguard Worker         fNumShaderCombos = 0;
197*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& s : fShaders) {
198*c8dee2aaSAndroid Build Coastguard Worker             fNumShaderCombos += s->priv().numCombinations();
199*c8dee2aaSAndroid Build Coastguard Worker         }
200*c8dee2aaSAndroid Build Coastguard Worker     }
201*c8dee2aaSAndroid Build Coastguard Worker 
202*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const203*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override {
204*c8dee2aaSAndroid Build Coastguard Worker         return fNumShaderCombos;
205*c8dee2aaSAndroid Build Coastguard Worker     }
206*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const207*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
208*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
209*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
210*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
211*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < fNumShaderCombos);
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker         constexpr SkRect kIgnored { 0, 0, 256, 256 }; // ignored bc we're precompiling
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker         // TODO: update CoordClampShaderBlock so this is optional
216*c8dee2aaSAndroid Build Coastguard Worker         CoordClampShaderBlock::CoordClampData data(kIgnored);
217*c8dee2aaSAndroid Build Coastguard Worker 
218*c8dee2aaSAndroid Build Coastguard Worker         CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
219*c8dee2aaSAndroid Build Coastguard Worker             AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders, desiredCombination);
220*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
221*c8dee2aaSAndroid Build Coastguard Worker     }
222*c8dee2aaSAndroid Build Coastguard Worker 
223*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>> fShaders;
224*c8dee2aaSAndroid Build Coastguard Worker     int fNumShaderCombos;
225*c8dee2aaSAndroid Build Coastguard Worker };
226*c8dee2aaSAndroid Build Coastguard Worker 
CoordClamp(SkSpan<const sk_sp<PrecompileShader>> input)227*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::CoordClamp(SkSpan<const sk_sp<PrecompileShader>> input) {
228*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileCoordClampShader>(input);
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
232*c8dee2aaSAndroid Build Coastguard Worker class PrecompileImageShader final : public PrecompileShader {
233*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileImageShader(SkEnumBitMask<PrecompileImageShaderFlags> flags)234*c8dee2aaSAndroid Build Coastguard Worker     PrecompileImageShader(SkEnumBitMask<PrecompileImageShaderFlags> flags) : fFlags(flags) {}
235*c8dee2aaSAndroid Build Coastguard Worker 
236*c8dee2aaSAndroid Build Coastguard Worker private:
237*c8dee2aaSAndroid Build Coastguard Worker     // The ImageShader has 3 potential sampling/tiling variants: hardware-tiled, shader-tiled and
238*c8dee2aaSAndroid Build Coastguard Worker     // cubic sampling (which always uses shader-tiling)
239*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumSamplingTilingCombos = 3;
240*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kCubicSampled = 2;
241*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kHWTiled      = 1;
242*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kShaderTiled  = 0;
243*c8dee2aaSAndroid Build Coastguard Worker 
244*c8dee2aaSAndroid Build Coastguard Worker     // There are also 2 potential alpha combinations: alpha-only and not-alpha-only
245*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumAlphaCombinations = 2;
246*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kAlphaOnly    = 1;
247*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNonAlphaOnly = 0;
248*c8dee2aaSAndroid Build Coastguard Worker 
numIntrinsicCombinations() const249*c8dee2aaSAndroid Build Coastguard Worker     int numIntrinsicCombinations() const override {
250*c8dee2aaSAndroid Build Coastguard Worker         int numSamplingTilingCombos =
251*c8dee2aaSAndroid Build Coastguard Worker                 (fFlags & PrecompileImageShaderFlags::kExcludeCubic) ? 2 : kNumSamplingTilingCombos;
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker         if (fFlags & PrecompileImageShaderFlags::kExcludeAlpha) {
254*c8dee2aaSAndroid Build Coastguard Worker             // RawImageShaders don't blend alpha-only images w/ the paint color
255*c8dee2aaSAndroid Build Coastguard Worker             return numSamplingTilingCombos;
256*c8dee2aaSAndroid Build Coastguard Worker         }
257*c8dee2aaSAndroid Build Coastguard Worker         return numSamplingTilingCombos * kNumAlphaCombinations;
258*c8dee2aaSAndroid Build Coastguard Worker     }
259*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const260*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
261*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
262*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
263*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
264*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numIntrinsicCombinations());
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker         int desiredAlphaCombo, desiredSamplingTilingCombo;
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker         if (fFlags & PrecompileImageShaderFlags::kExcludeAlpha) {
269*c8dee2aaSAndroid Build Coastguard Worker             desiredAlphaCombo = kNonAlphaOnly;
270*c8dee2aaSAndroid Build Coastguard Worker             desiredSamplingTilingCombo = desiredCombination;
271*c8dee2aaSAndroid Build Coastguard Worker         } else {
272*c8dee2aaSAndroid Build Coastguard Worker             desiredAlphaCombo = desiredCombination % kNumAlphaCombinations;
273*c8dee2aaSAndroid Build Coastguard Worker             desiredSamplingTilingCombo = desiredCombination / kNumAlphaCombinations;
274*c8dee2aaSAndroid Build Coastguard Worker         }
275*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(int numSamplingTilingCombos =
276*c8dee2aaSAndroid Build Coastguard Worker             (fFlags & PrecompileImageShaderFlags::kExcludeCubic) ? 2 : kNumSamplingTilingCombos;)
277*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredSamplingTilingCombo < numSamplingTilingCombos);
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
280*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkSamplingOptions kDefaultSampling;
281*c8dee2aaSAndroid Build Coastguard Worker         constexpr ReadSwizzle kIgnoredSwizzle = ReadSwizzle::kRGBA;
282*c8dee2aaSAndroid Build Coastguard Worker 
283*c8dee2aaSAndroid Build Coastguard Worker         // ImageShaderBlock will use hardware tiling when the subset covers the entire image, so we
284*c8dee2aaSAndroid Build Coastguard Worker         // create subset + image size combinations where subset == imgSize (for a shader that uses
285*c8dee2aaSAndroid Build Coastguard Worker         // hardware tiling) and subset < imgSize (for a shader that does shader-based tiling).
286*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkRect kSubset = SkRect::MakeWH(1.0f, 1.0f);
287*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkISize kHWTileableSize = SkISize::Make(1, 1);
288*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkISize kShaderTileableSize = SkISize::Make(2, 2);
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker         ImageShaderBlock::ImageData imgData(
291*c8dee2aaSAndroid Build Coastguard Worker                 desiredSamplingTilingCombo == kCubicSampled ? kDefaultCubicSampling
292*c8dee2aaSAndroid Build Coastguard Worker                                                             : kDefaultSampling,
293*c8dee2aaSAndroid Build Coastguard Worker                 SkTileMode::kClamp, SkTileMode::kClamp,
294*c8dee2aaSAndroid Build Coastguard Worker                 desiredSamplingTilingCombo == kHWTiled ? kHWTileableSize : kShaderTileableSize,
295*c8dee2aaSAndroid Build Coastguard Worker                 kSubset);
296*c8dee2aaSAndroid Build Coastguard Worker         ColorSpaceTransformBlock::ColorSpaceTransformData colorXformData(kIgnoredSwizzle);
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker         if (desiredAlphaCombo == kAlphaOnly) {
299*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!(fFlags & PrecompileImageShaderFlags::kExcludeAlpha));
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker             Blend(keyContext, builder, gatherer,
302*c8dee2aaSAndroid Build Coastguard Worker                   /* addBlendToKey= */ [&] () -> void {
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker                       AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kDstIn);
305*c8dee2aaSAndroid Build Coastguard Worker                   },
306*c8dee2aaSAndroid Build Coastguard Worker                   /* addSrcToKey= */ [&] () -> void {
307*c8dee2aaSAndroid Build Coastguard Worker                       Compose(keyContext, builder, gatherer,
308*c8dee2aaSAndroid Build Coastguard Worker                               /* addInnerToKey= */ [&]() -> void {
309*c8dee2aaSAndroid Build Coastguard Worker                                   ImageShaderBlock::AddBlock(keyContext, builder, gatherer,
310*c8dee2aaSAndroid Build Coastguard Worker                                                              imgData);
311*c8dee2aaSAndroid Build Coastguard Worker                               },
312*c8dee2aaSAndroid Build Coastguard Worker                               /* addOuterToKey= */ [&]() -> void {
313*c8dee2aaSAndroid Build Coastguard Worker                                   ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
314*c8dee2aaSAndroid Build Coastguard Worker                                                                      colorXformData);
315*c8dee2aaSAndroid Build Coastguard Worker                               });
316*c8dee2aaSAndroid Build Coastguard Worker                   },
317*c8dee2aaSAndroid Build Coastguard Worker                   /* addDstToKey= */ [&]() -> void {
318*c8dee2aaSAndroid Build Coastguard Worker                       RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
319*c8dee2aaSAndroid Build Coastguard Worker                   });
320*c8dee2aaSAndroid Build Coastguard Worker         } else {
321*c8dee2aaSAndroid Build Coastguard Worker             Compose(keyContext, builder, gatherer,
322*c8dee2aaSAndroid Build Coastguard Worker                     /* addInnerToKey= */ [&]() -> void {
323*c8dee2aaSAndroid Build Coastguard Worker                         ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
324*c8dee2aaSAndroid Build Coastguard Worker                     },
325*c8dee2aaSAndroid Build Coastguard Worker                     /* addOuterToKey= */ [&]() -> void {
326*c8dee2aaSAndroid Build Coastguard Worker                         ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
327*c8dee2aaSAndroid Build Coastguard Worker                                                            colorXformData);
328*c8dee2aaSAndroid Build Coastguard Worker                     });
329*c8dee2aaSAndroid Build Coastguard Worker         }
330*c8dee2aaSAndroid Build Coastguard Worker     }
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker     SkEnumBitMask<PrecompileImageShaderFlags> fFlags;
333*c8dee2aaSAndroid Build Coastguard Worker };
334*c8dee2aaSAndroid Build Coastguard Worker 
Image()335*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Image() {
336*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix(
337*c8dee2aaSAndroid Build Coastguard Worker             { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kNone) });
338*c8dee2aaSAndroid Build Coastguard Worker }
339*c8dee2aaSAndroid Build Coastguard Worker 
RawImage()340*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::RawImage() {
341*c8dee2aaSAndroid Build Coastguard Worker     // Raw images do not perform color space conversion, but in Graphite, this is represented as
342*c8dee2aaSAndroid Build Coastguard Worker     // an identity color space xform, not as a distinct shader
343*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix(
344*c8dee2aaSAndroid Build Coastguard Worker             { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kExcludeAlpha) });
345*c8dee2aaSAndroid Build Coastguard Worker }
346*c8dee2aaSAndroid Build Coastguard Worker 
Image(SkEnumBitMask<PrecompileImageShaderFlags> flags)347*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::Image(
348*c8dee2aaSAndroid Build Coastguard Worker         SkEnumBitMask<PrecompileImageShaderFlags> flags) {
349*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileImageShader>(flags) });
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker 
RawImage(SkEnumBitMask<PrecompileImageShaderFlags> flags)352*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::RawImage(
353*c8dee2aaSAndroid Build Coastguard Worker         SkEnumBitMask<PrecompileImageShaderFlags> flags) {
354*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix(
355*c8dee2aaSAndroid Build Coastguard Worker             { sk_make_sp<PrecompileImageShader>(flags |
356*c8dee2aaSAndroid Build Coastguard Worker                                                 PrecompileImageShaderFlags::kExcludeAlpha) });
357*c8dee2aaSAndroid Build Coastguard Worker }
358*c8dee2aaSAndroid Build Coastguard Worker 
359*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
360*c8dee2aaSAndroid Build Coastguard Worker class PrecompileYUVImageShader : public PrecompileShader {
361*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileYUVImageShader()362*c8dee2aaSAndroid Build Coastguard Worker     PrecompileYUVImageShader() {}
363*c8dee2aaSAndroid Build Coastguard Worker 
364*c8dee2aaSAndroid Build Coastguard Worker private:
365*c8dee2aaSAndroid Build Coastguard Worker     // There are 8 intrinsic YUV shaders:
366*c8dee2aaSAndroid Build Coastguard Worker     //  4 tiling modes
367*c8dee2aaSAndroid Build Coastguard Worker     //    HW tiling w/o swizzle
368*c8dee2aaSAndroid Build Coastguard Worker     //    HW tiling w/ swizzle
369*c8dee2aaSAndroid Build Coastguard Worker     //    cubic shader tiling
370*c8dee2aaSAndroid Build Coastguard Worker     //    non-cubic shader tiling
371*c8dee2aaSAndroid Build Coastguard Worker     //  crossed with two postambles:
372*c8dee2aaSAndroid Build Coastguard Worker     //    just premul
373*c8dee2aaSAndroid Build Coastguard Worker     //    full-blown colorSpace transform
374*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumTilingModes     = 4;
375*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kHWTiledNoSwizzle   = 3;
376*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kHWTiledWithSwizzle = 2;
377*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kCubicShaderTiled   = 1;
378*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kShaderTiled        = 0;
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumPostambles       = 2;
381*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kWithColorSpaceXform = 1;
382*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kJustPremul          = 0;
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumIntrinsicCombinations = kNumTilingModes * kNumPostambles;
385*c8dee2aaSAndroid Build Coastguard Worker 
numIntrinsicCombinations() const386*c8dee2aaSAndroid Build Coastguard Worker     int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
387*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const388*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
389*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
390*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
391*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
392*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < kNumIntrinsicCombinations);
393*c8dee2aaSAndroid Build Coastguard Worker 
394*c8dee2aaSAndroid Build Coastguard Worker         int desiredPostamble = desiredCombination % kNumPostambles;
395*c8dee2aaSAndroid Build Coastguard Worker         int desiredTiling = desiredCombination / kNumPostambles;
396*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredTiling < kNumTilingModes);
397*c8dee2aaSAndroid Build Coastguard Worker 
398*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
399*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkSamplingOptions kDefaultSampling;
400*c8dee2aaSAndroid Build Coastguard Worker 
401*c8dee2aaSAndroid Build Coastguard Worker         YUVImageShaderBlock::ImageData imgData(desiredTiling == kCubicShaderTiled
402*c8dee2aaSAndroid Build Coastguard Worker                                                                        ? kDefaultCubicSampling
403*c8dee2aaSAndroid Build Coastguard Worker                                                                        : kDefaultSampling,
404*c8dee2aaSAndroid Build Coastguard Worker                                                SkTileMode::kClamp, SkTileMode::kClamp,
405*c8dee2aaSAndroid Build Coastguard Worker                                                /* imgSize= */ { 1, 1 },
406*c8dee2aaSAndroid Build Coastguard Worker                                                /* subset= */ desiredTiling == kShaderTiled
407*c8dee2aaSAndroid Build Coastguard Worker                                                                      ? SkRect::MakeEmpty()
408*c8dee2aaSAndroid Build Coastguard Worker                                                                      : SkRect::MakeWH(1, 1));
409*c8dee2aaSAndroid Build Coastguard Worker 
410*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkV4 kRedChannel{ 1.f, 0.f, 0.f, 0.f };
411*c8dee2aaSAndroid Build Coastguard Worker         imgData.fChannelSelect[0] = kRedChannel;
412*c8dee2aaSAndroid Build Coastguard Worker         imgData.fChannelSelect[1] = kRedChannel;
413*c8dee2aaSAndroid Build Coastguard Worker         if (desiredTiling == kHWTiledNoSwizzle) {
414*c8dee2aaSAndroid Build Coastguard Worker             imgData.fChannelSelect[2] = kRedChannel;
415*c8dee2aaSAndroid Build Coastguard Worker         } else {
416*c8dee2aaSAndroid Build Coastguard Worker             // Having a non-red channel selector forces a swizzle
417*c8dee2aaSAndroid Build Coastguard Worker             imgData.fChannelSelect[2] = { 0.f, 1.f, 0.f, 0.f};
418*c8dee2aaSAndroid Build Coastguard Worker         }
419*c8dee2aaSAndroid Build Coastguard Worker         imgData.fChannelSelect[3] = kRedChannel;
420*c8dee2aaSAndroid Build Coastguard Worker 
421*c8dee2aaSAndroid Build Coastguard Worker         imgData.fYUVtoRGBMatrix.setAll(1, 0, 0, 0, 1, 0, 0, 0, 0);
422*c8dee2aaSAndroid Build Coastguard Worker         imgData.fYUVtoRGBTranslate = { 0, 0, 0 };
423*c8dee2aaSAndroid Build Coastguard Worker 
424*c8dee2aaSAndroid Build Coastguard Worker         ColorSpaceTransformBlock::ColorSpaceTransformData colorXformData(
425*c8dee2aaSAndroid Build Coastguard Worker                                       skgpu::graphite::ReadSwizzle::kRGBA);
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker         if (desiredPostamble == kJustPremul) {
428*c8dee2aaSAndroid Build Coastguard Worker             Compose(keyContext, builder, gatherer,
429*c8dee2aaSAndroid Build Coastguard Worker                     /* addInnerToKey= */ [&]() -> void {
430*c8dee2aaSAndroid Build Coastguard Worker                         YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
431*c8dee2aaSAndroid Build Coastguard Worker                     },
432*c8dee2aaSAndroid Build Coastguard Worker                     /* addOuterToKey= */ [&]() -> void {
433*c8dee2aaSAndroid Build Coastguard Worker                         builder->addBlock(BuiltInCodeSnippetID::kPremulAlphaColorFilter);
434*c8dee2aaSAndroid Build Coastguard Worker                     });
435*c8dee2aaSAndroid Build Coastguard Worker         } else {
436*c8dee2aaSAndroid Build Coastguard Worker             Compose(keyContext, builder, gatherer,
437*c8dee2aaSAndroid Build Coastguard Worker                     /* addInnerToKey= */ [&]() -> void {
438*c8dee2aaSAndroid Build Coastguard Worker                         YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
439*c8dee2aaSAndroid Build Coastguard Worker                     },
440*c8dee2aaSAndroid Build Coastguard Worker                     /* addOuterToKey= */ [&]() -> void {
441*c8dee2aaSAndroid Build Coastguard Worker                         ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
442*c8dee2aaSAndroid Build Coastguard Worker                                                            colorXformData);
443*c8dee2aaSAndroid Build Coastguard Worker                     });
444*c8dee2aaSAndroid Build Coastguard Worker         }
445*c8dee2aaSAndroid Build Coastguard Worker 
446*c8dee2aaSAndroid Build Coastguard Worker     }
447*c8dee2aaSAndroid Build Coastguard Worker };
448*c8dee2aaSAndroid Build Coastguard Worker 
YUVImage()449*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::YUVImage() {
450*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileYUVImageShader>() });
451*c8dee2aaSAndroid Build Coastguard Worker }
452*c8dee2aaSAndroid Build Coastguard Worker 
453*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
454*c8dee2aaSAndroid Build Coastguard Worker class PrecompilePerlinNoiseShader final : public PrecompileShader {
455*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompilePerlinNoiseShader()456*c8dee2aaSAndroid Build Coastguard Worker     PrecompilePerlinNoiseShader() {}
457*c8dee2aaSAndroid Build Coastguard Worker 
458*c8dee2aaSAndroid Build Coastguard Worker private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const459*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
460*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
461*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
462*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
463*c8dee2aaSAndroid Build Coastguard Worker 
464*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination == 0); // The Perlin noise shader only ever has one combination
465*c8dee2aaSAndroid Build Coastguard Worker 
466*c8dee2aaSAndroid Build Coastguard Worker         // TODO: update PerlinNoiseShaderBlock so the NoiseData is optional
467*c8dee2aaSAndroid Build Coastguard Worker         static const PerlinNoiseShaderBlock::PerlinNoiseData kIgnoredNoiseData(
468*c8dee2aaSAndroid Build Coastguard Worker                 PerlinNoiseShaderBlock::Type::kFractalNoise, { 0.0f, 0.0f }, 2, {1, 1});
469*c8dee2aaSAndroid Build Coastguard Worker 
470*c8dee2aaSAndroid Build Coastguard Worker         PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, kIgnoredNoiseData);
471*c8dee2aaSAndroid Build Coastguard Worker     }
472*c8dee2aaSAndroid Build Coastguard Worker 
473*c8dee2aaSAndroid Build Coastguard Worker };
474*c8dee2aaSAndroid Build Coastguard Worker 
MakeFractalNoise()475*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::MakeFractalNoise() {
476*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompilePerlinNoiseShader>();
477*c8dee2aaSAndroid Build Coastguard Worker }
478*c8dee2aaSAndroid Build Coastguard Worker 
MakeTurbulence()479*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::MakeTurbulence() {
480*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompilePerlinNoiseShader>();
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker 
483*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
484*c8dee2aaSAndroid Build Coastguard Worker class PrecompileGradientShader final : public PrecompileShader {
485*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileGradientShader(SkShaderBase::GradientType type)486*c8dee2aaSAndroid Build Coastguard Worker     PrecompileGradientShader(SkShaderBase::GradientType type) : fType(type) {}
487*c8dee2aaSAndroid Build Coastguard Worker 
488*c8dee2aaSAndroid Build Coastguard Worker private:
489*c8dee2aaSAndroid Build Coastguard Worker     /*
490*c8dee2aaSAndroid Build Coastguard Worker      * The gradients currently have three specializations based on the number of stops.
491*c8dee2aaSAndroid Build Coastguard Worker      */
492*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumStopVariants = 3;
493*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kStopVariants[kNumStopVariants] =
494*c8dee2aaSAndroid Build Coastguard Worker             { 4, 8, GradientShaderBlocks::GradientData::kNumInternalStorageStops+1 };
495*c8dee2aaSAndroid Build Coastguard Worker 
numIntrinsicCombinations() const496*c8dee2aaSAndroid Build Coastguard Worker     int numIntrinsicCombinations() const override {
497*c8dee2aaSAndroid Build Coastguard Worker         return kNumStopVariants;
498*c8dee2aaSAndroid Build Coastguard Worker     }
499*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const500*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
501*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
502*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
503*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
504*c8dee2aaSAndroid Build Coastguard Worker         const int intrinsicCombination = desiredCombination / this->numChildCombinations();
505*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(int childCombination = desiredCombination % this->numChildCombinations();)
506*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(intrinsicCombination < kNumStopVariants);
507*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(childCombination == 0);
508*c8dee2aaSAndroid Build Coastguard Worker 
509*c8dee2aaSAndroid Build Coastguard Worker         bool useStorageBuffer = keyContext.caps()->gradientBufferSupport();
510*c8dee2aaSAndroid Build Coastguard Worker 
511*c8dee2aaSAndroid Build Coastguard Worker         GradientShaderBlocks::GradientData gradData(fType,
512*c8dee2aaSAndroid Build Coastguard Worker                                                     kStopVariants[intrinsicCombination],
513*c8dee2aaSAndroid Build Coastguard Worker                                                     useStorageBuffer);
514*c8dee2aaSAndroid Build Coastguard Worker 
515*c8dee2aaSAndroid Build Coastguard Worker         constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
516*c8dee2aaSAndroid Build Coastguard Worker         ColorSpaceTransformBlock::ColorSpaceTransformData csData(sk_srgb_singleton(), kAlphaType,
517*c8dee2aaSAndroid Build Coastguard Worker                                                                  sk_srgb_singleton(), kAlphaType);
518*c8dee2aaSAndroid Build Coastguard Worker 
519*c8dee2aaSAndroid Build Coastguard Worker         Compose(keyContext, builder, gatherer,
520*c8dee2aaSAndroid Build Coastguard Worker                 /* addInnerToKey= */ [&]() -> void {
521*c8dee2aaSAndroid Build Coastguard Worker                     GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
522*c8dee2aaSAndroid Build Coastguard Worker                 },
523*c8dee2aaSAndroid Build Coastguard Worker                 /* addOuterToKey= */  [&]() -> void {
524*c8dee2aaSAndroid Build Coastguard Worker                     ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
525*c8dee2aaSAndroid Build Coastguard Worker                 });
526*c8dee2aaSAndroid Build Coastguard Worker     }
527*c8dee2aaSAndroid Build Coastguard Worker 
528*c8dee2aaSAndroid Build Coastguard Worker     SkShaderBase::GradientType fType;
529*c8dee2aaSAndroid Build Coastguard Worker };
530*c8dee2aaSAndroid Build Coastguard Worker 
LinearGradient()531*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::LinearGradient() {
532*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> s =
533*c8dee2aaSAndroid Build Coastguard Worker             sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kLinear);
534*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ std::move(s) });
535*c8dee2aaSAndroid Build Coastguard Worker }
536*c8dee2aaSAndroid Build Coastguard Worker 
RadialGradient()537*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::RadialGradient() {
538*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> s =
539*c8dee2aaSAndroid Build Coastguard Worker             sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kRadial);
540*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ std::move(s) });
541*c8dee2aaSAndroid Build Coastguard Worker }
542*c8dee2aaSAndroid Build Coastguard Worker 
SweepGradient()543*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::SweepGradient() {
544*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> s =
545*c8dee2aaSAndroid Build Coastguard Worker             sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kSweep);
546*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ std::move(s) });
547*c8dee2aaSAndroid Build Coastguard Worker }
548*c8dee2aaSAndroid Build Coastguard Worker 
TwoPointConicalGradient()549*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::TwoPointConicalGradient() {
550*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> s =
551*c8dee2aaSAndroid Build Coastguard Worker             sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kConical);
552*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ std::move(s) });
553*c8dee2aaSAndroid Build Coastguard Worker }
554*c8dee2aaSAndroid Build Coastguard Worker 
555*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
556*c8dee2aaSAndroid Build Coastguard Worker // The PictureShader ultimately turns into an SkImageShader optionally wrapped in a
557*c8dee2aaSAndroid Build Coastguard Worker // LocalMatrixShader.
558*c8dee2aaSAndroid Build Coastguard Worker // Note that this means each precompile PictureShader will add 12 combinations:
559*c8dee2aaSAndroid Build Coastguard Worker //    2 (pictureshader LM) x 6 (imageShader variations)
Picture()560*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::Picture() {
561*c8dee2aaSAndroid Build Coastguard Worker     // Note: We don't need to consider the PrecompileYUVImageShader since the image
562*c8dee2aaSAndroid Build Coastguard Worker     // being drawn was created internally by Skia (as non-YUV).
563*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShadersPriv::LocalMatrixBothVariants({ PrecompileShaders::Image() });
564*c8dee2aaSAndroid Build Coastguard Worker }
565*c8dee2aaSAndroid Build Coastguard Worker 
Picture(bool withLM)566*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::Picture(bool withLM) {
567*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> s = PrecompileShaders::Image();
568*c8dee2aaSAndroid Build Coastguard Worker     if (withLM) {
569*c8dee2aaSAndroid Build Coastguard Worker         return PrecompileShaders::LocalMatrix({ std::move(s) });
570*c8dee2aaSAndroid Build Coastguard Worker     }
571*c8dee2aaSAndroid Build Coastguard Worker     return s;
572*c8dee2aaSAndroid Build Coastguard Worker }
573*c8dee2aaSAndroid Build Coastguard Worker 
574*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
575*c8dee2aaSAndroid Build Coastguard Worker // In the main Skia API the SkLocalMatrixShader is optimized away when the LM is the identity
576*c8dee2aaSAndroid Build Coastguard Worker // or omitted. The PrecompileLocalMatrixShader captures this by adding two intrinsic options.
577*c8dee2aaSAndroid Build Coastguard Worker // One with the LMShader wrapping the child and one without the LMShader.
578*c8dee2aaSAndroid Build Coastguard Worker class PrecompileLocalMatrixShader final : public PrecompileShader {
579*c8dee2aaSAndroid Build Coastguard Worker public:
580*c8dee2aaSAndroid Build Coastguard Worker     enum class Flags {
581*c8dee2aaSAndroid Build Coastguard Worker         kNone                  = 0b00,
582*c8dee2aaSAndroid Build Coastguard Worker         kIsPerspective         = 0b01,
583*c8dee2aaSAndroid Build Coastguard Worker         kIncludeWithOutVariant = 0b10,
584*c8dee2aaSAndroid Build Coastguard Worker     };
585*c8dee2aaSAndroid Build Coastguard Worker 
PrecompileLocalMatrixShader(SkSpan<const sk_sp<PrecompileShader>> wrapped,SkEnumBitMask<Flags> flags=Flags::kNone)586*c8dee2aaSAndroid Build Coastguard Worker     PrecompileLocalMatrixShader(SkSpan<const sk_sp<PrecompileShader>> wrapped,
587*c8dee2aaSAndroid Build Coastguard Worker                                 SkEnumBitMask<Flags> flags = Flags::kNone)
588*c8dee2aaSAndroid Build Coastguard Worker             : fWrapped(wrapped.begin(), wrapped.end())
589*c8dee2aaSAndroid Build Coastguard Worker             , fFlags(flags) {
590*c8dee2aaSAndroid Build Coastguard Worker         fNumWrappedCombos = 0;
591*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& s : fWrapped) {
592*c8dee2aaSAndroid Build Coastguard Worker             fNumWrappedCombos += s->priv().numCombinations();
593*c8dee2aaSAndroid Build Coastguard Worker         }
594*c8dee2aaSAndroid Build Coastguard Worker     }
595*c8dee2aaSAndroid Build Coastguard Worker 
isConstant(int desiredCombination) const596*c8dee2aaSAndroid Build Coastguard Worker     bool isConstant(int desiredCombination) const override {
597*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numCombinations());
598*c8dee2aaSAndroid Build Coastguard Worker 
599*c8dee2aaSAndroid Build Coastguard Worker         /*
600*c8dee2aaSAndroid Build Coastguard Worker          * Regardless of whether the LocalMatrixShader elides itself or not, we always want
601*c8dee2aaSAndroid Build Coastguard Worker          * the Constant-ness of the wrapped shader.
602*c8dee2aaSAndroid Build Coastguard Worker          */
603*c8dee2aaSAndroid Build Coastguard Worker         int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
604*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
605*c8dee2aaSAndroid Build Coastguard Worker 
606*c8dee2aaSAndroid Build Coastguard Worker         std::pair<sk_sp<PrecompileShader>, int> wrapped =
607*c8dee2aaSAndroid Build Coastguard Worker                 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredWrappedCombination);
608*c8dee2aaSAndroid Build Coastguard Worker         if (wrapped.first) {
609*c8dee2aaSAndroid Build Coastguard Worker             return wrapped.first->priv().isConstant(wrapped.second);
610*c8dee2aaSAndroid Build Coastguard Worker         }
611*c8dee2aaSAndroid Build Coastguard Worker 
612*c8dee2aaSAndroid Build Coastguard Worker         return false;
613*c8dee2aaSAndroid Build Coastguard Worker     }
614*c8dee2aaSAndroid Build Coastguard Worker 
getWrapped() const615*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const sk_sp<PrecompileShader>> getWrapped() const {
616*c8dee2aaSAndroid Build Coastguard Worker         return fWrapped;
617*c8dee2aaSAndroid Build Coastguard Worker     }
618*c8dee2aaSAndroid Build Coastguard Worker 
getFlags() const619*c8dee2aaSAndroid Build Coastguard Worker     SkEnumBitMask<Flags> getFlags() const { return fFlags; }
620*c8dee2aaSAndroid Build Coastguard Worker 
621*c8dee2aaSAndroid Build Coastguard Worker private:
622*c8dee2aaSAndroid Build Coastguard Worker     // The LocalMatrixShader has two potential variants: with and without the LocalMatrixShader
623*c8dee2aaSAndroid Build Coastguard Worker     // In the "with" variant, the kIsPerspective flag will determine if the shader performs
624*c8dee2aaSAndroid Build Coastguard Worker     // the perspective division or not.
625*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumIntrinsicCombinations = 2;
626*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kWithLocalMatrix    = 1;
627*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kWithoutLocalMatrix = 0;
628*c8dee2aaSAndroid Build Coastguard Worker 
isALocalMatrixShader() const629*c8dee2aaSAndroid Build Coastguard Worker     bool isALocalMatrixShader() const override { return true; }
630*c8dee2aaSAndroid Build Coastguard Worker 
numIntrinsicCombinations() const631*c8dee2aaSAndroid Build Coastguard Worker     int numIntrinsicCombinations() const override {
632*c8dee2aaSAndroid Build Coastguard Worker         if (!(fFlags & Flags::kIncludeWithOutVariant)) {
633*c8dee2aaSAndroid Build Coastguard Worker             return 1;   // just kWithLocalMatrix
634*c8dee2aaSAndroid Build Coastguard Worker         }
635*c8dee2aaSAndroid Build Coastguard Worker         return kNumIntrinsicCombinations;
636*c8dee2aaSAndroid Build Coastguard Worker     }
637*c8dee2aaSAndroid Build Coastguard Worker 
numChildCombinations() const638*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumWrappedCombos; }
639*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const640*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
641*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
642*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
643*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
644*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numCombinations());
645*c8dee2aaSAndroid Build Coastguard Worker 
646*c8dee2aaSAndroid Build Coastguard Worker         int desiredLMCombination, desiredWrappedCombination;
647*c8dee2aaSAndroid Build Coastguard Worker 
648*c8dee2aaSAndroid Build Coastguard Worker         if (!(fFlags & Flags::kIncludeWithOutVariant)) {
649*c8dee2aaSAndroid Build Coastguard Worker             desiredLMCombination = kWithLocalMatrix;
650*c8dee2aaSAndroid Build Coastguard Worker             desiredWrappedCombination = desiredCombination;
651*c8dee2aaSAndroid Build Coastguard Worker         } else {
652*c8dee2aaSAndroid Build Coastguard Worker             desiredLMCombination = desiredCombination % kNumIntrinsicCombinations;
653*c8dee2aaSAndroid Build Coastguard Worker             desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
654*c8dee2aaSAndroid Build Coastguard Worker         }
655*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
656*c8dee2aaSAndroid Build Coastguard Worker 
657*c8dee2aaSAndroid Build Coastguard Worker         if (desiredLMCombination == kWithLocalMatrix) {
658*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix matrix = SkMatrix::I();
659*c8dee2aaSAndroid Build Coastguard Worker             if (fFlags & Flags::kIsPerspective) {
660*c8dee2aaSAndroid Build Coastguard Worker                 matrix.setPerspX(0.1f);
661*c8dee2aaSAndroid Build Coastguard Worker             }
662*c8dee2aaSAndroid Build Coastguard Worker             LocalMatrixShaderBlock::LMShaderData lmShaderData(matrix);
663*c8dee2aaSAndroid Build Coastguard Worker 
664*c8dee2aaSAndroid Build Coastguard Worker             LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, matrix);
665*c8dee2aaSAndroid Build Coastguard Worker         }
666*c8dee2aaSAndroid Build Coastguard Worker 
667*c8dee2aaSAndroid Build Coastguard Worker         AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped,
668*c8dee2aaSAndroid Build Coastguard Worker                                    desiredWrappedCombination);
669*c8dee2aaSAndroid Build Coastguard Worker 
670*c8dee2aaSAndroid Build Coastguard Worker         if (desiredLMCombination == kWithLocalMatrix) {
671*c8dee2aaSAndroid Build Coastguard Worker             builder->endBlock();
672*c8dee2aaSAndroid Build Coastguard Worker         }
673*c8dee2aaSAndroid Build Coastguard Worker     }
674*c8dee2aaSAndroid Build Coastguard Worker 
675*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>> fWrapped;
676*c8dee2aaSAndroid Build Coastguard Worker     int fNumWrappedCombos;
677*c8dee2aaSAndroid Build Coastguard Worker     SkEnumBitMask<Flags> fFlags;
678*c8dee2aaSAndroid Build Coastguard Worker };
679*c8dee2aaSAndroid Build Coastguard Worker 
LocalMatrix(SkSpan<const sk_sp<PrecompileShader>> wrapped,bool isPerspective)680*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::LocalMatrix(
681*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> wrapped,
682*c8dee2aaSAndroid Build Coastguard Worker         bool isPerspective) {
683*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileLocalMatrixShader>(
684*c8dee2aaSAndroid Build Coastguard Worker             std::move(wrapped),
685*c8dee2aaSAndroid Build Coastguard Worker             isPerspective ? PrecompileLocalMatrixShader::Flags::kIsPerspective
686*c8dee2aaSAndroid Build Coastguard Worker                           : PrecompileLocalMatrixShader::Flags::kNone);
687*c8dee2aaSAndroid Build Coastguard Worker }
688*c8dee2aaSAndroid Build Coastguard Worker 
LocalMatrixBothVariants(SkSpan<const sk_sp<PrecompileShader>> wrapped)689*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::LocalMatrixBothVariants(
690*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> wrapped) {
691*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileLocalMatrixShader>(
692*c8dee2aaSAndroid Build Coastguard Worker             std::move(wrapped),
693*c8dee2aaSAndroid Build Coastguard Worker             PrecompileLocalMatrixShader::Flags::kIncludeWithOutVariant);
694*c8dee2aaSAndroid Build Coastguard Worker }
695*c8dee2aaSAndroid Build Coastguard Worker 
makeWithLocalMatrix(bool isPerspective) const696*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShader::makeWithLocalMatrix(bool isPerspective) const {
697*c8dee2aaSAndroid Build Coastguard Worker     if (this->priv().isALocalMatrixShader()) {
698*c8dee2aaSAndroid Build Coastguard Worker         // SkShader::makeWithLocalMatrix collapses chains of localMatrix shaders so we need to
699*c8dee2aaSAndroid Build Coastguard Worker         // follow suit here, folding in any new perspective flag if needed.
700*c8dee2aaSAndroid Build Coastguard Worker         auto thisAsLMShader = static_cast<const PrecompileLocalMatrixShader*>(this);
701*c8dee2aaSAndroid Build Coastguard Worker         if (isPerspective && !(thisAsLMShader->getFlags() &
702*c8dee2aaSAndroid Build Coastguard Worker                 PrecompileLocalMatrixShader::Flags::kIsPerspective)) {
703*c8dee2aaSAndroid Build Coastguard Worker             return sk_make_sp<PrecompileLocalMatrixShader>(
704*c8dee2aaSAndroid Build Coastguard Worker                 thisAsLMShader->getWrapped(),
705*c8dee2aaSAndroid Build Coastguard Worker                 thisAsLMShader->getFlags() | PrecompileLocalMatrixShader::Flags::kIsPerspective);
706*c8dee2aaSAndroid Build Coastguard Worker         }
707*c8dee2aaSAndroid Build Coastguard Worker 
708*c8dee2aaSAndroid Build Coastguard Worker         return sk_ref_sp(this);
709*c8dee2aaSAndroid Build Coastguard Worker     }
710*c8dee2aaSAndroid Build Coastguard Worker 
711*c8dee2aaSAndroid Build Coastguard Worker     return PrecompileShaders::LocalMatrix({ sk_ref_sp(this) }, isPerspective);
712*c8dee2aaSAndroid Build Coastguard Worker }
713*c8dee2aaSAndroid Build Coastguard Worker 
714*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
715*c8dee2aaSAndroid Build Coastguard Worker class PrecompileColorFilterShader final : public PrecompileShader {
716*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileColorFilterShader(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)717*c8dee2aaSAndroid Build Coastguard Worker     PrecompileColorFilterShader(SkSpan<const sk_sp<PrecompileShader>> shaders,
718*c8dee2aaSAndroid Build Coastguard Worker                                 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)
719*c8dee2aaSAndroid Build Coastguard Worker             : fShaders(shaders.begin(), shaders.end())
720*c8dee2aaSAndroid Build Coastguard Worker             , fColorFilters(colorFilters.begin(), colorFilters.end()) {
721*c8dee2aaSAndroid Build Coastguard Worker         fNumShaderCombos = 0;
722*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& s : fShaders) {
723*c8dee2aaSAndroid Build Coastguard Worker             fNumShaderCombos += s->priv().numCombinations();
724*c8dee2aaSAndroid Build Coastguard Worker         }
725*c8dee2aaSAndroid Build Coastguard Worker         fNumColorFilterCombos = 0;
726*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& cf : fColorFilters) {
727*c8dee2aaSAndroid Build Coastguard Worker             fNumColorFilterCombos += cf->priv().numCombinations();
728*c8dee2aaSAndroid Build Coastguard Worker         }
729*c8dee2aaSAndroid Build Coastguard Worker     }
730*c8dee2aaSAndroid Build Coastguard Worker 
731*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const732*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumShaderCombos * fNumColorFilterCombos; }
733*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const734*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
735*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
736*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
737*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
738*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numCombinations());
739*c8dee2aaSAndroid Build Coastguard Worker 
740*c8dee2aaSAndroid Build Coastguard Worker         int desiredShaderCombination = desiredCombination % fNumShaderCombos;
741*c8dee2aaSAndroid Build Coastguard Worker         int desiredColorFilterCombination = desiredCombination / fNumShaderCombos;
742*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredColorFilterCombination < fNumColorFilterCombos);
743*c8dee2aaSAndroid Build Coastguard Worker 
744*c8dee2aaSAndroid Build Coastguard Worker         Compose(keyContext, builder, gatherer,
745*c8dee2aaSAndroid Build Coastguard Worker                 /* addInnerToKey= */ [&]() -> void {
746*c8dee2aaSAndroid Build Coastguard Worker                     AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
747*c8dee2aaSAndroid Build Coastguard Worker                                                desiredShaderCombination);
748*c8dee2aaSAndroid Build Coastguard Worker                 },
749*c8dee2aaSAndroid Build Coastguard Worker                 /* addOuterToKey= */ [&]() -> void {
750*c8dee2aaSAndroid Build Coastguard Worker                     AddToKey<PrecompileColorFilter>(keyContext, builder, gatherer, fColorFilters,
751*c8dee2aaSAndroid Build Coastguard Worker                                                     desiredColorFilterCombination);
752*c8dee2aaSAndroid Build Coastguard Worker                 });
753*c8dee2aaSAndroid Build Coastguard Worker     }
754*c8dee2aaSAndroid Build Coastguard Worker 
755*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>>      fShaders;
756*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileColorFilter>> fColorFilters;
757*c8dee2aaSAndroid Build Coastguard Worker     int fNumShaderCombos;
758*c8dee2aaSAndroid Build Coastguard Worker     int fNumColorFilterCombos;
759*c8dee2aaSAndroid Build Coastguard Worker };
760*c8dee2aaSAndroid Build Coastguard Worker 
ColorFilter(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)761*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::ColorFilter(
762*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> shaders,
763*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters) {
764*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileColorFilterShader>(std::move(shaders), std::move(colorFilters));
765*c8dee2aaSAndroid Build Coastguard Worker }
766*c8dee2aaSAndroid Build Coastguard Worker 
767*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
768*c8dee2aaSAndroid Build Coastguard Worker class PrecompileWorkingColorSpaceShader final : public PrecompileShader {
769*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileWorkingColorSpaceShader(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<SkColorSpace>> colorSpaces)770*c8dee2aaSAndroid Build Coastguard Worker     PrecompileWorkingColorSpaceShader(SkSpan<const sk_sp<PrecompileShader>> shaders,
771*c8dee2aaSAndroid Build Coastguard Worker                                       SkSpan<const sk_sp<SkColorSpace>> colorSpaces)
772*c8dee2aaSAndroid Build Coastguard Worker             : fShaders(shaders.begin(), shaders.end())
773*c8dee2aaSAndroid Build Coastguard Worker             , fColorSpaces(colorSpaces.begin(), colorSpaces.end()) {
774*c8dee2aaSAndroid Build Coastguard Worker         fNumShaderCombos = 0;
775*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& s : fShaders) {
776*c8dee2aaSAndroid Build Coastguard Worker             fNumShaderCombos += s->priv().numCombinations();
777*c8dee2aaSAndroid Build Coastguard Worker         }
778*c8dee2aaSAndroid Build Coastguard Worker     }
779*c8dee2aaSAndroid Build Coastguard Worker 
780*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const781*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumShaderCombos * fColorSpaces.size(); }
782*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const783*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
784*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
785*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
786*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
787*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numCombinations());
788*c8dee2aaSAndroid Build Coastguard Worker 
789*c8dee2aaSAndroid Build Coastguard Worker         int desiredShaderCombination = desiredCombination % fNumShaderCombos;
790*c8dee2aaSAndroid Build Coastguard Worker         int desiredColorSpaceCombination = desiredCombination / fNumShaderCombos;
791*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredColorSpaceCombination < (int) fColorSpaces.size());
792*c8dee2aaSAndroid Build Coastguard Worker 
793*c8dee2aaSAndroid Build Coastguard Worker         const SkColorInfo& dstInfo = keyContext.dstColorInfo();
794*c8dee2aaSAndroid Build Coastguard Worker         const SkAlphaType dstAT = dstInfo.alphaType();
795*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
796*c8dee2aaSAndroid Build Coastguard Worker         if (!dstCS) {
797*c8dee2aaSAndroid Build Coastguard Worker             dstCS = SkColorSpace::MakeSRGB();
798*c8dee2aaSAndroid Build Coastguard Worker         }
799*c8dee2aaSAndroid Build Coastguard Worker 
800*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> workingCS = fColorSpaces[desiredColorSpaceCombination];
801*c8dee2aaSAndroid Build Coastguard Worker         SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
802*c8dee2aaSAndroid Build Coastguard Worker         KeyContextWithColorInfo workingContext(keyContext, workingInfo);
803*c8dee2aaSAndroid Build Coastguard Worker 
804*c8dee2aaSAndroid Build Coastguard Worker         Compose(keyContext, builder, gatherer,
805*c8dee2aaSAndroid Build Coastguard Worker                 /* addInnerToKey= */ [&]() -> void {
806*c8dee2aaSAndroid Build Coastguard Worker                     AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
807*c8dee2aaSAndroid Build Coastguard Worker                                                desiredShaderCombination);
808*c8dee2aaSAndroid Build Coastguard Worker                 },
809*c8dee2aaSAndroid Build Coastguard Worker                 /* addOuterToKey= */ [&]() -> void {
810*c8dee2aaSAndroid Build Coastguard Worker                     ColorSpaceTransformBlock::ColorSpaceTransformData data(
811*c8dee2aaSAndroid Build Coastguard Worker                             workingCS.get(), dstAT, dstCS.get(), dstAT);
812*c8dee2aaSAndroid Build Coastguard Worker                     ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
813*c8dee2aaSAndroid Build Coastguard Worker                 });
814*c8dee2aaSAndroid Build Coastguard Worker     }
815*c8dee2aaSAndroid Build Coastguard Worker 
816*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>> fShaders;
817*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<SkColorSpace>>     fColorSpaces;
818*c8dee2aaSAndroid Build Coastguard Worker     int fNumShaderCombos;
819*c8dee2aaSAndroid Build Coastguard Worker };
820*c8dee2aaSAndroid Build Coastguard Worker 
WorkingColorSpace(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<SkColorSpace>> colorSpaces)821*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShaders::WorkingColorSpace(
822*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<PrecompileShader>> shaders,
823*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const sk_sp<SkColorSpace>> colorSpaces) {
824*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileWorkingColorSpaceShader>(std::move(shaders),
825*c8dee2aaSAndroid Build Coastguard Worker                                                          std::move(colorSpaces));
826*c8dee2aaSAndroid Build Coastguard Worker }
827*c8dee2aaSAndroid Build Coastguard Worker 
828*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
829*c8dee2aaSAndroid Build Coastguard Worker // In Graphite this acts as a non-elidable LocalMatrixShader
830*c8dee2aaSAndroid Build Coastguard Worker class PrecompileCTMShader final : public PrecompileShader {
831*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileCTMShader(SkSpan<const sk_sp<PrecompileShader>> wrapped)832*c8dee2aaSAndroid Build Coastguard Worker     PrecompileCTMShader(SkSpan<const sk_sp<PrecompileShader>> wrapped)
833*c8dee2aaSAndroid Build Coastguard Worker             : fWrapped(wrapped.begin(), wrapped.end()) {
834*c8dee2aaSAndroid Build Coastguard Worker         fNumWrappedCombos = 0;
835*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& s : fWrapped) {
836*c8dee2aaSAndroid Build Coastguard Worker             fNumWrappedCombos += s->priv().numCombinations();
837*c8dee2aaSAndroid Build Coastguard Worker         }
838*c8dee2aaSAndroid Build Coastguard Worker     }
839*c8dee2aaSAndroid Build Coastguard Worker 
isConstant(int desiredCombination) const840*c8dee2aaSAndroid Build Coastguard Worker     bool isConstant(int desiredCombination) const override {
841*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < fNumWrappedCombos);
842*c8dee2aaSAndroid Build Coastguard Worker 
843*c8dee2aaSAndroid Build Coastguard Worker         std::pair<sk_sp<PrecompileShader>, int> wrapped =
844*c8dee2aaSAndroid Build Coastguard Worker                 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredCombination);
845*c8dee2aaSAndroid Build Coastguard Worker         if (wrapped.first) {
846*c8dee2aaSAndroid Build Coastguard Worker             return wrapped.first->priv().isConstant(wrapped.second);
847*c8dee2aaSAndroid Build Coastguard Worker         }
848*c8dee2aaSAndroid Build Coastguard Worker 
849*c8dee2aaSAndroid Build Coastguard Worker         return false;
850*c8dee2aaSAndroid Build Coastguard Worker     }
851*c8dee2aaSAndroid Build Coastguard Worker 
852*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const853*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumWrappedCombos; }
854*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const855*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
856*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
857*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
858*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
859*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < fNumWrappedCombos);
860*c8dee2aaSAndroid Build Coastguard Worker 
861*c8dee2aaSAndroid Build Coastguard Worker         LocalMatrixShaderBlock::LMShaderData kIgnoredLMShaderData(SkMatrix::I());
862*c8dee2aaSAndroid Build Coastguard Worker 
863*c8dee2aaSAndroid Build Coastguard Worker         LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, kIgnoredLMShaderData);
864*c8dee2aaSAndroid Build Coastguard Worker 
865*c8dee2aaSAndroid Build Coastguard Worker             AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped, desiredCombination);
866*c8dee2aaSAndroid Build Coastguard Worker 
867*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
868*c8dee2aaSAndroid Build Coastguard Worker     }
869*c8dee2aaSAndroid Build Coastguard Worker 
870*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<PrecompileShader>> fWrapped;
871*c8dee2aaSAndroid Build Coastguard Worker     int fNumWrappedCombos;
872*c8dee2aaSAndroid Build Coastguard Worker };
873*c8dee2aaSAndroid Build Coastguard Worker 
CTM(SkSpan<const sk_sp<PrecompileShader>> wrapped)874*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::CTM(SkSpan<const sk_sp<PrecompileShader>> wrapped) {
875*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileCTMShader>(std::move(wrapped));
876*c8dee2aaSAndroid Build Coastguard Worker }
877*c8dee2aaSAndroid Build Coastguard Worker 
878*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
879*c8dee2aaSAndroid Build Coastguard Worker class PrecompileBlurShader final : public PrecompileShader {
880*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileBlurShader(sk_sp<PrecompileShader> wrapped)881*c8dee2aaSAndroid Build Coastguard Worker     PrecompileBlurShader(sk_sp<PrecompileShader> wrapped)
882*c8dee2aaSAndroid Build Coastguard Worker             : fWrapped(std::move(wrapped)) {
883*c8dee2aaSAndroid Build Coastguard Worker         fNumWrappedCombos = fWrapped->priv().numCombinations();
884*c8dee2aaSAndroid Build Coastguard Worker     }
885*c8dee2aaSAndroid Build Coastguard Worker 
886*c8dee2aaSAndroid Build Coastguard Worker private:
887*c8dee2aaSAndroid Build Coastguard Worker     // 6 known 1D blur effects + 6 known 2D blur effects
888*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumIntrinsicCombinations = 12;
889*c8dee2aaSAndroid Build Coastguard Worker 
numIntrinsicCombinations() const890*c8dee2aaSAndroid Build Coastguard Worker     int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
891*c8dee2aaSAndroid Build Coastguard Worker 
numChildCombinations() const892*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumWrappedCombos; }
893*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const894*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
895*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
896*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
897*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
898*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numCombinations());
899*c8dee2aaSAndroid Build Coastguard Worker 
900*c8dee2aaSAndroid Build Coastguard Worker         using namespace SkKnownRuntimeEffects;
901*c8dee2aaSAndroid Build Coastguard Worker 
902*c8dee2aaSAndroid Build Coastguard Worker         int desiredBlurCombination = desiredCombination % kNumIntrinsicCombinations;
903*c8dee2aaSAndroid Build Coastguard Worker         int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
904*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
905*c8dee2aaSAndroid Build Coastguard Worker 
906*c8dee2aaSAndroid Build Coastguard Worker         static const StableKey kIDs[kNumIntrinsicCombinations] = {
907*c8dee2aaSAndroid Build Coastguard Worker                 StableKey::k1DBlur4,  StableKey::k1DBlur8,  StableKey::k1DBlur12,
908*c8dee2aaSAndroid Build Coastguard Worker                 StableKey::k1DBlur16, StableKey::k1DBlur20, StableKey::k1DBlur28,
909*c8dee2aaSAndroid Build Coastguard Worker 
910*c8dee2aaSAndroid Build Coastguard Worker                 StableKey::k2DBlur4,  StableKey::k2DBlur8,  StableKey::k2DBlur12,
911*c8dee2aaSAndroid Build Coastguard Worker                 StableKey::k2DBlur16, StableKey::k2DBlur20, StableKey::k2DBlur28,
912*c8dee2aaSAndroid Build Coastguard Worker         };
913*c8dee2aaSAndroid Build Coastguard Worker 
914*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(kIDs[desiredBlurCombination]);
915*c8dee2aaSAndroid Build Coastguard Worker 
916*c8dee2aaSAndroid Build Coastguard Worker         KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
917*c8dee2aaSAndroid Build Coastguard Worker 
918*c8dee2aaSAndroid Build Coastguard Worker         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
919*c8dee2aaSAndroid Build Coastguard Worker             fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
920*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
921*c8dee2aaSAndroid Build Coastguard Worker     }
922*c8dee2aaSAndroid Build Coastguard Worker 
923*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fWrapped;
924*c8dee2aaSAndroid Build Coastguard Worker     int fNumWrappedCombos;
925*c8dee2aaSAndroid Build Coastguard Worker };
926*c8dee2aaSAndroid Build Coastguard Worker 
Blur(sk_sp<PrecompileShader> wrapped)927*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::Blur(sk_sp<PrecompileShader> wrapped) {
928*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileBlurShader>(std::move(wrapped));
929*c8dee2aaSAndroid Build Coastguard Worker }
930*c8dee2aaSAndroid Build Coastguard Worker 
931*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
932*c8dee2aaSAndroid Build Coastguard Worker class PrecompileMatrixConvolutionShader final : public PrecompileShader {
933*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)934*c8dee2aaSAndroid Build Coastguard Worker     PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)
935*c8dee2aaSAndroid Build Coastguard Worker             : fWrapped(std::move(wrapped)) {
936*c8dee2aaSAndroid Build Coastguard Worker         fNumWrappedCombos = fWrapped->priv().numCombinations();
937*c8dee2aaSAndroid Build Coastguard Worker 
938*c8dee2aaSAndroid Build Coastguard Worker         // When the matrix convolution ImageFilter uses a texture we know it will only ever
939*c8dee2aaSAndroid Build Coastguard Worker         // be SkFilterMode::kNearest and SkTileMode::kClamp.
940*c8dee2aaSAndroid Build Coastguard Worker         // TODO: add a PrecompileImageShaderFlags to further limit the raw image shader
941*c8dee2aaSAndroid Build Coastguard Worker         // combinations. Right now we're getting two combinations for the raw shader
942*c8dee2aaSAndroid Build Coastguard Worker         // (sk_image_shader and sk_hw_image_shader).
943*c8dee2aaSAndroid Build Coastguard Worker         fRawImageShader =
944*c8dee2aaSAndroid Build Coastguard Worker                 PrecompileShadersPriv::RawImage(PrecompileImageShaderFlags::kExcludeCubic);
945*c8dee2aaSAndroid Build Coastguard Worker         fNumRawImageShaderCombos = fRawImageShader->priv().numCombinations();
946*c8dee2aaSAndroid Build Coastguard Worker     }
947*c8dee2aaSAndroid Build Coastguard Worker 
948*c8dee2aaSAndroid Build Coastguard Worker private:
numIntrinsicCombinations() const949*c8dee2aaSAndroid Build Coastguard Worker     int numIntrinsicCombinations() const override {
950*c8dee2aaSAndroid Build Coastguard Worker         // The uniform version only has one option but the two texture-based versions will
951*c8dee2aaSAndroid Build Coastguard Worker         // have as many combinations as the raw image shader.
952*c8dee2aaSAndroid Build Coastguard Worker         return 1 + 2 * fNumRawImageShaderCombos;
953*c8dee2aaSAndroid Build Coastguard Worker     }
954*c8dee2aaSAndroid Build Coastguard Worker 
numChildCombinations() const955*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumWrappedCombos; }
956*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const957*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
958*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
959*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
960*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
961*c8dee2aaSAndroid Build Coastguard Worker 
962*c8dee2aaSAndroid Build Coastguard Worker         int desiredTextureCombination = 0;
963*c8dee2aaSAndroid Build Coastguard Worker 
964*c8dee2aaSAndroid Build Coastguard Worker         const int desiredWrappedCombination = desiredCombination % fNumWrappedCombos;
965*c8dee2aaSAndroid Build Coastguard Worker         int remainingCombinations = desiredCombination / fNumWrappedCombos;
966*c8dee2aaSAndroid Build Coastguard Worker 
967*c8dee2aaSAndroid Build Coastguard Worker         SkKnownRuntimeEffects::StableKey stableKey = SkKnownRuntimeEffects::StableKey::kInvalid;
968*c8dee2aaSAndroid Build Coastguard Worker         if (remainingCombinations == 0) {
969*c8dee2aaSAndroid Build Coastguard Worker             stableKey = SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms;
970*c8dee2aaSAndroid Build Coastguard Worker         } else {
971*c8dee2aaSAndroid Build Coastguard Worker             static constexpr SkKnownRuntimeEffects::StableKey kTextureBasedStableKeys[] = {
972*c8dee2aaSAndroid Build Coastguard Worker                     SkKnownRuntimeEffects::StableKey::kMatrixConvTexSm,
973*c8dee2aaSAndroid Build Coastguard Worker                     SkKnownRuntimeEffects::StableKey::kMatrixConvTexLg,
974*c8dee2aaSAndroid Build Coastguard Worker             };
975*c8dee2aaSAndroid Build Coastguard Worker 
976*c8dee2aaSAndroid Build Coastguard Worker             --remainingCombinations;
977*c8dee2aaSAndroid Build Coastguard Worker             stableKey = kTextureBasedStableKeys[remainingCombinations % 2];
978*c8dee2aaSAndroid Build Coastguard Worker             desiredTextureCombination = remainingCombinations / 2;
979*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(desiredTextureCombination < fNumRawImageShaderCombos);
980*c8dee2aaSAndroid Build Coastguard Worker         }
981*c8dee2aaSAndroid Build Coastguard Worker 
982*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(stableKey);
983*c8dee2aaSAndroid Build Coastguard Worker 
984*c8dee2aaSAndroid Build Coastguard Worker         KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
985*c8dee2aaSAndroid Build Coastguard Worker 
986*c8dee2aaSAndroid Build Coastguard Worker         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
987*c8dee2aaSAndroid Build Coastguard Worker             fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
988*c8dee2aaSAndroid Build Coastguard Worker             if (stableKey != SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms) {
989*c8dee2aaSAndroid Build Coastguard Worker                 fRawImageShader->priv().addToKey(childContext, builder, gatherer,
990*c8dee2aaSAndroid Build Coastguard Worker                                                  desiredTextureCombination);
991*c8dee2aaSAndroid Build Coastguard Worker             }
992*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
993*c8dee2aaSAndroid Build Coastguard Worker     }
994*c8dee2aaSAndroid Build Coastguard Worker 
995*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fWrapped;
996*c8dee2aaSAndroid Build Coastguard Worker     int fNumWrappedCombos;
997*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fRawImageShader;
998*c8dee2aaSAndroid Build Coastguard Worker     int fNumRawImageShaderCombos;
999*c8dee2aaSAndroid Build Coastguard Worker };
1000*c8dee2aaSAndroid Build Coastguard Worker 
MatrixConvolution(sk_sp<skgpu::graphite::PrecompileShader> wrapped)1001*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::MatrixConvolution(
1002*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<skgpu::graphite::PrecompileShader> wrapped) {
1003*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileMatrixConvolutionShader>(std::move(wrapped));
1004*c8dee2aaSAndroid Build Coastguard Worker }
1005*c8dee2aaSAndroid Build Coastguard Worker 
1006*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
1007*c8dee2aaSAndroid Build Coastguard Worker class PrecompileMorphologyShader final : public PrecompileShader {
1008*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,SkKnownRuntimeEffects::StableKey stableKey)1009*c8dee2aaSAndroid Build Coastguard Worker     PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,
1010*c8dee2aaSAndroid Build Coastguard Worker                                SkKnownRuntimeEffects::StableKey stableKey)
1011*c8dee2aaSAndroid Build Coastguard Worker             : fWrapped(std::move(wrapped))
1012*c8dee2aaSAndroid Build Coastguard Worker             , fStableKey(stableKey) {
1013*c8dee2aaSAndroid Build Coastguard Worker         fNumWrappedCombos = fWrapped->priv().numCombinations();
1014*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(stableKey == SkKnownRuntimeEffects::StableKey::kLinearMorphology ||
1015*c8dee2aaSAndroid Build Coastguard Worker                  stableKey == SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1016*c8dee2aaSAndroid Build Coastguard Worker     }
1017*c8dee2aaSAndroid Build Coastguard Worker 
1018*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const1019*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumWrappedCombos; }
1020*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1021*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
1022*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
1023*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
1024*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
1025*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < fNumWrappedCombos);
1026*c8dee2aaSAndroid Build Coastguard Worker 
1027*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeEffect* effect = GetKnownRuntimeEffect(fStableKey);
1028*c8dee2aaSAndroid Build Coastguard Worker 
1029*c8dee2aaSAndroid Build Coastguard Worker         KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1030*c8dee2aaSAndroid Build Coastguard Worker 
1031*c8dee2aaSAndroid Build Coastguard Worker         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
1032*c8dee2aaSAndroid Build Coastguard Worker             fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1033*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
1034*c8dee2aaSAndroid Build Coastguard Worker     }
1035*c8dee2aaSAndroid Build Coastguard Worker 
1036*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fWrapped;
1037*c8dee2aaSAndroid Build Coastguard Worker     int fNumWrappedCombos;
1038*c8dee2aaSAndroid Build Coastguard Worker     SkKnownRuntimeEffects::StableKey fStableKey;
1039*c8dee2aaSAndroid Build Coastguard Worker };
1040*c8dee2aaSAndroid Build Coastguard Worker 
LinearMorphology(sk_sp<PrecompileShader> wrapped)1041*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::LinearMorphology(sk_sp<PrecompileShader> wrapped) {
1042*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileMorphologyShader>(
1043*c8dee2aaSAndroid Build Coastguard Worker             std::move(wrapped),
1044*c8dee2aaSAndroid Build Coastguard Worker             SkKnownRuntimeEffects::StableKey::kLinearMorphology);
1045*c8dee2aaSAndroid Build Coastguard Worker }
1046*c8dee2aaSAndroid Build Coastguard Worker 
SparseMorphology(sk_sp<PrecompileShader> wrapped)1047*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::SparseMorphology(sk_sp<PrecompileShader> wrapped) {
1048*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileMorphologyShader>(
1049*c8dee2aaSAndroid Build Coastguard Worker             std::move(wrapped),
1050*c8dee2aaSAndroid Build Coastguard Worker             SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1051*c8dee2aaSAndroid Build Coastguard Worker }
1052*c8dee2aaSAndroid Build Coastguard Worker 
1053*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
1054*c8dee2aaSAndroid Build Coastguard Worker class PrecompileDisplacementShader final : public PrecompileShader {
1055*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileDisplacementShader(sk_sp<PrecompileShader> displacement,sk_sp<PrecompileShader> color)1056*c8dee2aaSAndroid Build Coastguard Worker     PrecompileDisplacementShader(sk_sp<PrecompileShader> displacement,
1057*c8dee2aaSAndroid Build Coastguard Worker                                  sk_sp<PrecompileShader> color)
1058*c8dee2aaSAndroid Build Coastguard Worker             : fDisplacement(std::move(displacement))
1059*c8dee2aaSAndroid Build Coastguard Worker             , fColor(std::move(color)) {
1060*c8dee2aaSAndroid Build Coastguard Worker         fNumDisplacementCombos = fDisplacement->priv().numCombinations();
1061*c8dee2aaSAndroid Build Coastguard Worker         fNumColorCombos = fColor->priv().numCombinations();
1062*c8dee2aaSAndroid Build Coastguard Worker     }
1063*c8dee2aaSAndroid Build Coastguard Worker 
1064*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const1065*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumDisplacementCombos * fNumColorCombos; }
1066*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1067*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
1068*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
1069*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
1070*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
1071*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < this->numChildCombinations());
1072*c8dee2aaSAndroid Build Coastguard Worker 
1073*c8dee2aaSAndroid Build Coastguard Worker         const int desiredDisplacementCombination = desiredCombination % fNumDisplacementCombos;
1074*c8dee2aaSAndroid Build Coastguard Worker         const int desiredColorCombination = desiredCombination / fNumDisplacementCombos;
1075*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredColorCombination < fNumColorCombos);
1076*c8dee2aaSAndroid Build Coastguard Worker 
1077*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeEffect* fEffect =
1078*c8dee2aaSAndroid Build Coastguard Worker                 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kDisplacement);
1079*c8dee2aaSAndroid Build Coastguard Worker 
1080*c8dee2aaSAndroid Build Coastguard Worker         KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1081*c8dee2aaSAndroid Build Coastguard Worker 
1082*c8dee2aaSAndroid Build Coastguard Worker         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
1083*c8dee2aaSAndroid Build Coastguard Worker             fDisplacement->priv().addToKey(childContext, builder, gatherer,
1084*c8dee2aaSAndroid Build Coastguard Worker                                            desiredDisplacementCombination);
1085*c8dee2aaSAndroid Build Coastguard Worker             fColor->priv().addToKey(childContext, builder, gatherer,
1086*c8dee2aaSAndroid Build Coastguard Worker                                     desiredColorCombination);
1087*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
1088*c8dee2aaSAndroid Build Coastguard Worker     }
1089*c8dee2aaSAndroid Build Coastguard Worker 
1090*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fDisplacement;
1091*c8dee2aaSAndroid Build Coastguard Worker     int fNumDisplacementCombos;
1092*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fColor;
1093*c8dee2aaSAndroid Build Coastguard Worker     int fNumColorCombos;
1094*c8dee2aaSAndroid Build Coastguard Worker };
1095*c8dee2aaSAndroid Build Coastguard Worker 
1096*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
Displacement(sk_sp<PrecompileShader> displacement,sk_sp<PrecompileShader> color)1097*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::Displacement(sk_sp<PrecompileShader> displacement,
1098*c8dee2aaSAndroid Build Coastguard Worker                                                             sk_sp<PrecompileShader> color) {
1099*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileDisplacementShader>(std::move(displacement), std::move(color));
1100*c8dee2aaSAndroid Build Coastguard Worker }
1101*c8dee2aaSAndroid Build Coastguard Worker 
1102*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
1103*c8dee2aaSAndroid Build Coastguard Worker class PrecompileLightingShader final : public PrecompileShader {
1104*c8dee2aaSAndroid Build Coastguard Worker public:
PrecompileLightingShader(sk_sp<PrecompileShader> wrapped)1105*c8dee2aaSAndroid Build Coastguard Worker     PrecompileLightingShader(sk_sp<PrecompileShader> wrapped)
1106*c8dee2aaSAndroid Build Coastguard Worker             : fWrapped(std::move(wrapped)) {
1107*c8dee2aaSAndroid Build Coastguard Worker         fNumWrappedCombos = fWrapped->priv().numCombinations();
1108*c8dee2aaSAndroid Build Coastguard Worker     }
1109*c8dee2aaSAndroid Build Coastguard Worker 
1110*c8dee2aaSAndroid Build Coastguard Worker private:
numChildCombinations() const1111*c8dee2aaSAndroid Build Coastguard Worker     int numChildCombinations() const override { return fNumWrappedCombos; }
1112*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1113*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const KeyContext& keyContext,
1114*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
1115*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
1116*c8dee2aaSAndroid Build Coastguard Worker                   int desiredCombination) const override {
1117*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desiredCombination < fNumWrappedCombos);
1118*c8dee2aaSAndroid Build Coastguard Worker 
1119*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeEffect* normalEffect =
1120*c8dee2aaSAndroid Build Coastguard Worker                 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kNormal);
1121*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeEffect* lightingEffect =
1122*c8dee2aaSAndroid Build Coastguard Worker                 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kLighting);
1123*c8dee2aaSAndroid Build Coastguard Worker 
1124*c8dee2aaSAndroid Build Coastguard Worker         KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1125*c8dee2aaSAndroid Build Coastguard Worker 
1126*c8dee2aaSAndroid Build Coastguard Worker         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1127*c8dee2aaSAndroid Build Coastguard Worker                                        { sk_ref_sp(lightingEffect) });
1128*c8dee2aaSAndroid Build Coastguard Worker             RuntimeEffectBlock::BeginBlock(childContext, builder, gatherer,
1129*c8dee2aaSAndroid Build Coastguard Worker                                            { sk_ref_sp(normalEffect) });
1130*c8dee2aaSAndroid Build Coastguard Worker                 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1131*c8dee2aaSAndroid Build Coastguard Worker             builder->endBlock();
1132*c8dee2aaSAndroid Build Coastguard Worker         builder->endBlock();
1133*c8dee2aaSAndroid Build Coastguard Worker     }
1134*c8dee2aaSAndroid Build Coastguard Worker 
1135*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<PrecompileShader> fWrapped;
1136*c8dee2aaSAndroid Build Coastguard Worker     int fNumWrappedCombos;
1137*c8dee2aaSAndroid Build Coastguard Worker };
1138*c8dee2aaSAndroid Build Coastguard Worker 
Lighting(sk_sp<PrecompileShader> wrapped)1139*c8dee2aaSAndroid Build Coastguard Worker sk_sp<PrecompileShader> PrecompileShadersPriv::Lighting(sk_sp<PrecompileShader> wrapped) {
1140*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<PrecompileLightingShader>(std::move(wrapped));
1141*c8dee2aaSAndroid Build Coastguard Worker }
1142*c8dee2aaSAndroid Build Coastguard Worker 
1143*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
1144*c8dee2aaSAndroid Build Coastguard Worker 
1145*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
1146