xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrFragmentProcessors.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2023 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 "src/gpu/ganesh/GrFragmentProcessors.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTLazy.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlendModeBlender.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlenderBase.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkColorSpacePriv.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkColorSpaceXformSteps.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMaskFilterBase.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRuntimeBlender.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRuntimeEffectPriv.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/SkShaderMaskFilterImpl.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkBlendModeColorFilter.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkColorFilterBase.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkColorSpaceXformColorFilter.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkComposeColorFilter.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkGaussianColorFilter.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkMatrixColorFilter.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkRuntimeColorFilter.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkTableColorFilter.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkWorkingFormatColorFilter.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/Swizzle.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorInfo.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFPArgs.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessor.h"
60*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProxyProvider.h"
61*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
62*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSamplerState.h"
63*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
64*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxy.h"
65*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
66*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureProxy.h"
67*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SkGr.h"
68*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
69*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrColorTableEffect.h"
70*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrMatrixEffect.h"
71*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrPerlinNoise2Effect.h"
72*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrSkSLFP.h"
73*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrTextureEffect.h"
74*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/gradients/GrGradientShader.h"
75*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/GrImageUtils.h"
76*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkBlendShader.h"
77*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkColorFilterShader.h"
78*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkColorShader.h"
79*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkCoordClampShader.h"
80*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkEmptyShader.h"
81*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkImageShader.h"
82*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkLocalMatrixShader.h"
83*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkPerlinNoiseShaderImpl.h"
84*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkPictureShader.h"
85*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkRuntimeShader.h"
86*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
87*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkTransformShader.h"
88*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkTriColorShader.h"
89*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkWorkingColorSpaceShader.h"
90*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/gradients/SkConicalGradient.h"
91*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/gradients/SkGradientBaseShader.h"
92*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/gradients/SkLinearGradient.h"
93*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/gradients/SkRadialGradient.h"
94*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/gradients/SkSweepGradient.h"
95*c8dee2aaSAndroid Build Coastguard Worker 
96*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
97*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
98*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
99*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
100*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker class SkBitmap;
103*c8dee2aaSAndroid Build Coastguard Worker enum class SkTileMode;
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker namespace GrFragmentProcessors {
106*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor>
make_fp_from_shader_mask_filter(const SkMaskFilterBase * maskfilter,const GrFPArgs & args,const SkMatrix & ctm)107*c8dee2aaSAndroid Build Coastguard Worker         make_fp_from_shader_mask_filter(const SkMaskFilterBase* maskfilter,
108*c8dee2aaSAndroid Build Coastguard Worker                                         const GrFPArgs& args,
109*c8dee2aaSAndroid Build Coastguard Worker                                         const SkMatrix& ctm) {
110*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(maskfilter);
111*c8dee2aaSAndroid Build Coastguard Worker     auto shaderMF = static_cast<const SkShaderMaskFilterImpl*>(maskfilter);
112*c8dee2aaSAndroid Build Coastguard Worker     auto fp = Make(shaderMF->shader().get(), args, ctm);
113*c8dee2aaSAndroid Build Coastguard Worker     return GrFragmentProcessor::MulInputByChildAlpha(std::move(fp));
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker 
Make(const SkMaskFilter * maskfilter,const GrFPArgs & args,const SkMatrix & ctm)116*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> Make(const SkMaskFilter* maskfilter,
117*c8dee2aaSAndroid Build Coastguard Worker                                           const GrFPArgs& args,
118*c8dee2aaSAndroid Build Coastguard Worker                                           const SkMatrix& ctm) {
119*c8dee2aaSAndroid Build Coastguard Worker     if (!maskfilter) {
120*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker     auto mfb = as_MFB(maskfilter);
123*c8dee2aaSAndroid Build Coastguard Worker     switch (mfb->type()) {
124*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kShader:
125*c8dee2aaSAndroid Build Coastguard Worker             return make_fp_from_shader_mask_filter(mfb, args, ctm);
126*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kBlur:
127*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kEmboss:
128*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kSDF:
129*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kTable:
130*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
131*c8dee2aaSAndroid Build Coastguard Worker     }
132*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker 
IsSupported(const SkMaskFilter * maskfilter)135*c8dee2aaSAndroid Build Coastguard Worker bool IsSupported(const SkMaskFilter* maskfilter) {
136*c8dee2aaSAndroid Build Coastguard Worker     if (!maskfilter) {
137*c8dee2aaSAndroid Build Coastguard Worker         return false;
138*c8dee2aaSAndroid Build Coastguard Worker     }
139*c8dee2aaSAndroid Build Coastguard Worker     auto mfb = as_MFB(maskfilter);
140*c8dee2aaSAndroid Build Coastguard Worker     switch (mfb->type()) {
141*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kShader:
142*c8dee2aaSAndroid Build Coastguard Worker             return true;
143*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kBlur:
144*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kEmboss:
145*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kSDF:
146*c8dee2aaSAndroid Build Coastguard Worker         case SkMaskFilterBase::Type::kTable:
147*c8dee2aaSAndroid Build Coastguard Worker             return false;
148*c8dee2aaSAndroid Build Coastguard Worker     }
149*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker 
152*c8dee2aaSAndroid Build Coastguard Worker using ChildType = SkRuntimeEffect::ChildType;
153*c8dee2aaSAndroid Build Coastguard Worker 
MakeChildFP(const SkRuntimeEffect::ChildPtr & child,const GrFPArgs & childArgs)154*c8dee2aaSAndroid Build Coastguard Worker GrFPResult MakeChildFP(const SkRuntimeEffect::ChildPtr& child, const GrFPArgs& childArgs) {
155*c8dee2aaSAndroid Build Coastguard Worker     std::optional<ChildType> type = child.type();
156*c8dee2aaSAndroid Build Coastguard Worker     if (!type.has_value()) {
157*c8dee2aaSAndroid Build Coastguard Worker         // We have a null child effect.
158*c8dee2aaSAndroid Build Coastguard Worker         return GrFPNullableSuccess(nullptr);
159*c8dee2aaSAndroid Build Coastguard Worker     }
160*c8dee2aaSAndroid Build Coastguard Worker 
161*c8dee2aaSAndroid Build Coastguard Worker     switch (*type) {
162*c8dee2aaSAndroid Build Coastguard Worker         case ChildType::kShader: {
163*c8dee2aaSAndroid Build Coastguard Worker             // Convert a SkShader into a child FP.
164*c8dee2aaSAndroid Build Coastguard Worker             SkShaders::MatrixRec mRec(SkMatrix::I());
165*c8dee2aaSAndroid Build Coastguard Worker             mRec.markTotalMatrixInvalid();
166*c8dee2aaSAndroid Build Coastguard Worker             auto childFP = GrFragmentProcessors::Make(child.shader(), childArgs, mRec);
167*c8dee2aaSAndroid Build Coastguard Worker             return childFP ? GrFPSuccess(std::move(childFP))
168*c8dee2aaSAndroid Build Coastguard Worker                            : GrFPFailure(nullptr);
169*c8dee2aaSAndroid Build Coastguard Worker         }
170*c8dee2aaSAndroid Build Coastguard Worker         case ChildType::kColorFilter: {
171*c8dee2aaSAndroid Build Coastguard Worker             // Convert a SkColorFilter into a child FP.
172*c8dee2aaSAndroid Build Coastguard Worker             auto [success, childFP] = GrFragmentProcessors::Make(childArgs.fContext,
173*c8dee2aaSAndroid Build Coastguard Worker                                                                  child.colorFilter(),
174*c8dee2aaSAndroid Build Coastguard Worker                                                                  /*inputFP=*/nullptr,
175*c8dee2aaSAndroid Build Coastguard Worker                                                                  *childArgs.fDstColorInfo,
176*c8dee2aaSAndroid Build Coastguard Worker                                                                  childArgs.fSurfaceProps);
177*c8dee2aaSAndroid Build Coastguard Worker             return success ? GrFPSuccess(std::move(childFP))
178*c8dee2aaSAndroid Build Coastguard Worker                            : GrFPFailure(nullptr);
179*c8dee2aaSAndroid Build Coastguard Worker         }
180*c8dee2aaSAndroid Build Coastguard Worker         case ChildType::kBlender: {
181*c8dee2aaSAndroid Build Coastguard Worker             // Convert a SkBlender into a child FP.
182*c8dee2aaSAndroid Build Coastguard Worker             auto childFP = GrFragmentProcessors::Make(as_BB(child.blender()),
183*c8dee2aaSAndroid Build Coastguard Worker                                                       /*srcFP=*/nullptr,
184*c8dee2aaSAndroid Build Coastguard Worker                                                       GrFragmentProcessor::DestColor(),
185*c8dee2aaSAndroid Build Coastguard Worker                                                       childArgs);
186*c8dee2aaSAndroid Build Coastguard Worker             return childFP ? GrFPSuccess(std::move(childFP))
187*c8dee2aaSAndroid Build Coastguard Worker                            : GrFPFailure(nullptr);
188*c8dee2aaSAndroid Build Coastguard Worker         }
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker 
make_effect_fp(sk_sp<SkRuntimeEffect> effect,const char * name,sk_sp<const SkData> uniforms,std::unique_ptr<GrFragmentProcessor> inputFP,std::unique_ptr<GrFragmentProcessor> destColorFP,SkSpan<const SkRuntimeEffect::ChildPtr> children,const GrFPArgs & childArgs)194*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_effect_fp(sk_sp<SkRuntimeEffect> effect,
195*c8dee2aaSAndroid Build Coastguard Worker                                  const char* name,
196*c8dee2aaSAndroid Build Coastguard Worker                                  sk_sp<const SkData> uniforms,
197*c8dee2aaSAndroid Build Coastguard Worker                                  std::unique_ptr<GrFragmentProcessor> inputFP,
198*c8dee2aaSAndroid Build Coastguard Worker                                  std::unique_ptr<GrFragmentProcessor> destColorFP,
199*c8dee2aaSAndroid Build Coastguard Worker                                  SkSpan<const SkRuntimeEffect::ChildPtr> children,
200*c8dee2aaSAndroid Build Coastguard Worker                                  const GrFPArgs& childArgs) {
201*c8dee2aaSAndroid Build Coastguard Worker     skia_private::STArray<8, std::unique_ptr<GrFragmentProcessor>> childFPs;
202*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& child : children) {
203*c8dee2aaSAndroid Build Coastguard Worker         auto [success, childFP] = MakeChildFP(child, childArgs);
204*c8dee2aaSAndroid Build Coastguard Worker         if (!success) {
205*c8dee2aaSAndroid Build Coastguard Worker             return GrFPFailure(std::move(inputFP));
206*c8dee2aaSAndroid Build Coastguard Worker         }
207*c8dee2aaSAndroid Build Coastguard Worker         childFPs.push_back(std::move(childFP));
208*c8dee2aaSAndroid Build Coastguard Worker     }
209*c8dee2aaSAndroid Build Coastguard Worker     auto fp = GrSkSLFP::MakeWithData(std::move(effect),
210*c8dee2aaSAndroid Build Coastguard Worker                                      name,
211*c8dee2aaSAndroid Build Coastguard Worker                                      childArgs.fDstColorInfo->refColorSpace(),
212*c8dee2aaSAndroid Build Coastguard Worker                                      std::move(inputFP),
213*c8dee2aaSAndroid Build Coastguard Worker                                      std::move(destColorFP),
214*c8dee2aaSAndroid Build Coastguard Worker                                      std::move(uniforms),
215*c8dee2aaSAndroid Build Coastguard Worker                                      SkSpan(childFPs));
216*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fp);
217*c8dee2aaSAndroid Build Coastguard Worker     return GrFPSuccess(std::move(fp));
218*c8dee2aaSAndroid Build Coastguard Worker }
219*c8dee2aaSAndroid Build Coastguard Worker 
make_blender_fp(const SkRuntimeBlender * rtb,std::unique_ptr<GrFragmentProcessor> srcFP,std::unique_ptr<GrFragmentProcessor> dstFP,const GrFPArgs & fpArgs)220*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_blender_fp(
221*c8dee2aaSAndroid Build Coastguard Worker         const SkRuntimeBlender* rtb,
222*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> srcFP,
223*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> dstFP,
224*c8dee2aaSAndroid Build Coastguard Worker         const GrFPArgs& fpArgs) {
225*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(rtb);
226*c8dee2aaSAndroid Build Coastguard Worker     if (!SkRuntimeEffectPriv::CanDraw(fpArgs.fContext->priv().caps(), rtb->effect().get())) {
227*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
228*c8dee2aaSAndroid Build Coastguard Worker     }
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
231*c8dee2aaSAndroid Build Coastguard Worker             rtb->effect()->uniforms(),
232*c8dee2aaSAndroid Build Coastguard Worker             rtb->uniforms(),
233*c8dee2aaSAndroid Build Coastguard Worker             fpArgs.fDstColorInfo->colorSpace());
234*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(uniforms);
235*c8dee2aaSAndroid Build Coastguard Worker     GrFPArgs childArgs(fpArgs.fContext,
236*c8dee2aaSAndroid Build Coastguard Worker                        fpArgs.fDstColorInfo,
237*c8dee2aaSAndroid Build Coastguard Worker                        fpArgs.fSurfaceProps,
238*c8dee2aaSAndroid Build Coastguard Worker                        GrFPArgs::Scope::kRuntimeEffect);
239*c8dee2aaSAndroid Build Coastguard Worker     auto [success, fp] = make_effect_fp(rtb->effect(),
240*c8dee2aaSAndroid Build Coastguard Worker                                         "runtime_blender",
241*c8dee2aaSAndroid Build Coastguard Worker                                         std::move(uniforms),
242*c8dee2aaSAndroid Build Coastguard Worker                                         std::move(srcFP),
243*c8dee2aaSAndroid Build Coastguard Worker                                         std::move(dstFP),
244*c8dee2aaSAndroid Build Coastguard Worker                                         rtb->children(),
245*c8dee2aaSAndroid Build Coastguard Worker                                         childArgs);
246*c8dee2aaSAndroid Build Coastguard Worker 
247*c8dee2aaSAndroid Build Coastguard Worker     return success ? std::move(fp) : nullptr;
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker 
make_blender_fp(const SkBlendModeBlender * blender,std::unique_ptr<GrFragmentProcessor> srcFP,std::unique_ptr<GrFragmentProcessor> dstFP,const GrFPArgs & fpArgs)250*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_blender_fp(
251*c8dee2aaSAndroid Build Coastguard Worker         const SkBlendModeBlender* blender,
252*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> srcFP,
253*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> dstFP,
254*c8dee2aaSAndroid Build Coastguard Worker         const GrFPArgs& fpArgs) {
255*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(blender);
256*c8dee2aaSAndroid Build Coastguard Worker     return GrBlendFragmentProcessor::Make(std::move(srcFP), std::move(dstFP), blender->mode());
257*c8dee2aaSAndroid Build Coastguard Worker }
258*c8dee2aaSAndroid Build Coastguard Worker 
Make(const SkBlenderBase * blender,std::unique_ptr<GrFragmentProcessor> srcFP,std::unique_ptr<GrFragmentProcessor> dstFP,const GrFPArgs & fpArgs)259*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> Make(const SkBlenderBase* blender,
260*c8dee2aaSAndroid Build Coastguard Worker                                           std::unique_ptr<GrFragmentProcessor> srcFP,
261*c8dee2aaSAndroid Build Coastguard Worker                                           std::unique_ptr<GrFragmentProcessor> dstFP,
262*c8dee2aaSAndroid Build Coastguard Worker                                           const GrFPArgs& fpArgs) {
263*c8dee2aaSAndroid Build Coastguard Worker     if (!blender) {
264*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
265*c8dee2aaSAndroid Build Coastguard Worker     }
266*c8dee2aaSAndroid Build Coastguard Worker     switch (blender->type()) {
267*c8dee2aaSAndroid Build Coastguard Worker #define M(type)                                                                \
268*c8dee2aaSAndroid Build Coastguard Worker     case SkBlenderBase::BlenderType::k##type:                                  \
269*c8dee2aaSAndroid Build Coastguard Worker         return make_blender_fp(static_cast<const Sk##type##Blender*>(blender), \
270*c8dee2aaSAndroid Build Coastguard Worker                                std::move(srcFP),                               \
271*c8dee2aaSAndroid Build Coastguard Worker                                std::move(dstFP),                               \
272*c8dee2aaSAndroid Build Coastguard Worker                                fpArgs);
273*c8dee2aaSAndroid Build Coastguard Worker         SK_ALL_BLENDERS(M)
274*c8dee2aaSAndroid Build Coastguard Worker #undef M
275*c8dee2aaSAndroid Build Coastguard Worker     }
276*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker 
map_color(const SkColor4f & c,SkColorSpace * src,SkColorSpace * dst)279*c8dee2aaSAndroid Build Coastguard Worker static SkPMColor4f map_color(const SkColor4f& c, SkColorSpace* src, SkColorSpace* dst) {
280*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f color = {c.fR, c.fG, c.fB, c.fA};
281*c8dee2aaSAndroid Build Coastguard Worker     SkColorSpaceXformSteps(src, kUnpremul_SkAlphaType, dst, kPremul_SkAlphaType).apply(color.vec());
282*c8dee2aaSAndroid Build Coastguard Worker     return color;
283*c8dee2aaSAndroid Build Coastguard Worker }
make_colorfilter_fp(GrRecordingContext *,const SkBlendModeColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & dstColorInfo,const SkSurfaceProps & props)284*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext*,
285*c8dee2aaSAndroid Build Coastguard Worker                                       const SkBlendModeColorFilter* filter,
286*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
287*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo& dstColorInfo,
288*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps& props) {
289*c8dee2aaSAndroid Build Coastguard Worker     if (filter->mode() == SkBlendMode::kDst) {
290*c8dee2aaSAndroid Build Coastguard Worker         // If the blend mode is "dest," the blend color won't factor into it at all.
291*c8dee2aaSAndroid Build Coastguard Worker         // We can return the input FP as-is.
292*c8dee2aaSAndroid Build Coastguard Worker         return GrFPSuccess(std::move(inputFP));
293*c8dee2aaSAndroid Build Coastguard Worker     }
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(const bool fpHasConstIO = !inputFP || inputFP->hasConstantOutputForConstantInput();)
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f color = map_color(filter->color(), sk_srgb_singleton(), dstColorInfo.colorSpace());
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker     auto colorFP = GrFragmentProcessor::MakeColor(color);
300*c8dee2aaSAndroid Build Coastguard Worker     auto xferFP =
301*c8dee2aaSAndroid Build Coastguard Worker             GrBlendFragmentProcessor::Make(std::move(colorFP), std::move(inputFP), filter->mode());
302*c8dee2aaSAndroid Build Coastguard Worker 
303*c8dee2aaSAndroid Build Coastguard Worker     if (xferFP == nullptr) {
304*c8dee2aaSAndroid Build Coastguard Worker         // This is only expected to happen if the blend mode is "dest" and the input FP is null.
305*c8dee2aaSAndroid Build Coastguard Worker         // Since we already did an early-out in the "dest" blend mode case, we shouldn't get here.
306*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGFAIL("GrBlendFragmentProcessor::Make returned null unexpectedly");
307*c8dee2aaSAndroid Build Coastguard Worker         return GrFPFailure(nullptr);
308*c8dee2aaSAndroid Build Coastguard Worker     }
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker     // With a solid color input this should always be able to compute the blended color
311*c8dee2aaSAndroid Build Coastguard Worker     // (at least for coeff modes).
312*c8dee2aaSAndroid Build Coastguard Worker     // Occasionally, we even do better than we started; specifically, in "src" blend mode, we end up
313*c8dee2aaSAndroid Build Coastguard Worker     // ditching the input FP entirely, which turns a non-constant operation into a constant one.
314*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(filter->mode() > SkBlendMode::kLastCoeffMode ||
315*c8dee2aaSAndroid Build Coastguard Worker              xferFP->hasConstantOutputForConstantInput() >= fpHasConstIO);
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker     return GrFPSuccess(std::move(xferFP));
318*c8dee2aaSAndroid Build Coastguard Worker }
319*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext * context,const SkComposeColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & dstColorInfo,const SkSurfaceProps & props)320*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
321*c8dee2aaSAndroid Build Coastguard Worker                                       const SkComposeColorFilter* filter,
322*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
323*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo& dstColorInfo,
324*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps& props) {
325*c8dee2aaSAndroid Build Coastguard Worker     // Unfortunately, we need to clone the input before we know we need it. This lets us return
326*c8dee2aaSAndroid Build Coastguard Worker     // the original FP if either internal color filter fails.
327*c8dee2aaSAndroid Build Coastguard Worker     auto inputClone = inputFP ? inputFP->clone() : nullptr;
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker     auto [innerSuccess, innerFP] =
330*c8dee2aaSAndroid Build Coastguard Worker             Make(context, filter->inner().get(), std::move(inputFP), dstColorInfo, props);
331*c8dee2aaSAndroid Build Coastguard Worker     if (!innerSuccess) {
332*c8dee2aaSAndroid Build Coastguard Worker         return GrFPFailure(std::move(inputClone));
333*c8dee2aaSAndroid Build Coastguard Worker     }
334*c8dee2aaSAndroid Build Coastguard Worker 
335*c8dee2aaSAndroid Build Coastguard Worker     auto [outerSuccess, outerFP] =
336*c8dee2aaSAndroid Build Coastguard Worker             Make(context, filter->outer().get(), std::move(innerFP), dstColorInfo, props);
337*c8dee2aaSAndroid Build Coastguard Worker     if (!outerSuccess) {
338*c8dee2aaSAndroid Build Coastguard Worker         return GrFPFailure(std::move(inputClone));
339*c8dee2aaSAndroid Build Coastguard Worker     }
340*c8dee2aaSAndroid Build Coastguard Worker 
341*c8dee2aaSAndroid Build Coastguard Worker     return GrFPSuccess(std::move(outerFP));
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext *,const SkColorSpaceXformColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo &,const SkSurfaceProps &)344*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext*,
345*c8dee2aaSAndroid Build Coastguard Worker                                       const SkColorSpaceXformColorFilter* filter,
346*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
347*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo&,
348*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps&) {
349*c8dee2aaSAndroid Build Coastguard Worker     // wish our caller would let us know if our input was opaque...
350*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkAlphaType alphaType = kPremul_SkAlphaType;
351*c8dee2aaSAndroid Build Coastguard Worker     return GrFPSuccess(GrColorSpaceXformEffect::Make(
352*c8dee2aaSAndroid Build Coastguard Worker             std::move(inputFP), filter->src().get(), alphaType, filter->dst().get(), alphaType));
353*c8dee2aaSAndroid Build Coastguard Worker }
354*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext *,const SkGaussianColorFilter *,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo &,const SkSurfaceProps &)355*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext*,
356*c8dee2aaSAndroid Build Coastguard Worker                                       const SkGaussianColorFilter*,
357*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
358*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo&,
359*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps&) {
360*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect =
361*c8dee2aaSAndroid Build Coastguard Worker             SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
362*c8dee2aaSAndroid Build Coastguard Worker                                 "half4 main(half4 inColor) {"
363*c8dee2aaSAndroid Build Coastguard Worker                                 "half factor = 1 - inColor.a;"
364*c8dee2aaSAndroid Build Coastguard Worker                                 "factor = exp(-factor * factor * 4) - 0.018;"
365*c8dee2aaSAndroid Build Coastguard Worker                                 "return half4(factor);"
366*c8dee2aaSAndroid Build Coastguard Worker                                 "}");
367*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
368*c8dee2aaSAndroid Build Coastguard Worker     return GrFPSuccess(
369*c8dee2aaSAndroid Build Coastguard Worker             GrSkSLFP::Make(effect, "gaussian_fp", std::move(inputFP), GrSkSLFP::OptFlags::kNone));
370*c8dee2aaSAndroid Build Coastguard Worker }
371*c8dee2aaSAndroid Build Coastguard Worker 
rgb_to_hsl(std::unique_ptr<GrFragmentProcessor> child)372*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> rgb_to_hsl(std::unique_ptr<GrFragmentProcessor> child) {
373*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect =
374*c8dee2aaSAndroid Build Coastguard Worker             SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
375*c8dee2aaSAndroid Build Coastguard Worker                                 "half4 main(half4 color) {"
376*c8dee2aaSAndroid Build Coastguard Worker                                 "return $rgb_to_hsl(color.rgb, color.a);"
377*c8dee2aaSAndroid Build Coastguard Worker                                 "}");
378*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
379*c8dee2aaSAndroid Build Coastguard Worker     return GrSkSLFP::Make(
380*c8dee2aaSAndroid Build Coastguard Worker             effect, "RgbToHsl", std::move(child), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker 
hsl_to_rgb(std::unique_ptr<GrFragmentProcessor> child)383*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> hsl_to_rgb(std::unique_ptr<GrFragmentProcessor> child) {
384*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect =
385*c8dee2aaSAndroid Build Coastguard Worker             SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
386*c8dee2aaSAndroid Build Coastguard Worker                                 "half4 main(half4 color) {"
387*c8dee2aaSAndroid Build Coastguard Worker                                 "return $hsl_to_rgb(color.rgb, color.a);"
388*c8dee2aaSAndroid Build Coastguard Worker                                 "}");
389*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
390*c8dee2aaSAndroid Build Coastguard Worker     return GrSkSLFP::Make(
391*c8dee2aaSAndroid Build Coastguard Worker             effect, "HslToRgb", std::move(child), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
392*c8dee2aaSAndroid Build Coastguard Worker }
393*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext *,const SkMatrixColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo &,const SkSurfaceProps &)394*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext*,
395*c8dee2aaSAndroid Build Coastguard Worker                                       const SkMatrixColorFilter* filter,
396*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
397*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo&,
398*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps&) {
399*c8dee2aaSAndroid Build Coastguard Worker     switch (filter->domain()) {
400*c8dee2aaSAndroid Build Coastguard Worker         case SkMatrixColorFilter::Domain::kRGBA:
401*c8dee2aaSAndroid Build Coastguard Worker             return GrFPSuccess(GrFragmentProcessor::ColorMatrix(
402*c8dee2aaSAndroid Build Coastguard Worker                     std::move(inputFP),
403*c8dee2aaSAndroid Build Coastguard Worker                     filter->matrix(),
404*c8dee2aaSAndroid Build Coastguard Worker                     /* unpremulInput = */ true,
405*c8dee2aaSAndroid Build Coastguard Worker                     /* clampRGBOutput = */ filter->clamp() == SkMatrixColorFilter::Clamp::kYes,
406*c8dee2aaSAndroid Build Coastguard Worker                     /* premulOutput = */ true));
407*c8dee2aaSAndroid Build Coastguard Worker 
408*c8dee2aaSAndroid Build Coastguard Worker         case SkMatrixColorFilter::Domain::kHSLA: {
409*c8dee2aaSAndroid Build Coastguard Worker             auto fp = rgb_to_hsl(std::move(inputFP));
410*c8dee2aaSAndroid Build Coastguard Worker             fp = GrFragmentProcessor::ColorMatrix(std::move(fp),
411*c8dee2aaSAndroid Build Coastguard Worker                                                   filter->matrix(),
412*c8dee2aaSAndroid Build Coastguard Worker                                                   /* unpremulInput = */ false,
413*c8dee2aaSAndroid Build Coastguard Worker                                                   /* clampRGBOutput = */ false,
414*c8dee2aaSAndroid Build Coastguard Worker                                                   /* premulOutput = */ false);
415*c8dee2aaSAndroid Build Coastguard Worker             return GrFPSuccess(hsl_to_rgb(std::move(fp)));
416*c8dee2aaSAndroid Build Coastguard Worker         }
417*c8dee2aaSAndroid Build Coastguard Worker     }
418*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
419*c8dee2aaSAndroid Build Coastguard Worker }
420*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext * context,const SkRuntimeColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & colorInfo,const SkSurfaceProps & props)421*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
422*c8dee2aaSAndroid Build Coastguard Worker                                       const SkRuntimeColorFilter* filter,
423*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
424*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo& colorInfo,
425*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps& props) {
426*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
427*c8dee2aaSAndroid Build Coastguard Worker             filter->effect()->uniforms(), filter->uniforms(), colorInfo.colorSpace());
428*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(uniforms);
429*c8dee2aaSAndroid Build Coastguard Worker 
430*c8dee2aaSAndroid Build Coastguard Worker     GrFPArgs childArgs(context, &colorInfo, props, GrFPArgs::Scope::kRuntimeEffect);
431*c8dee2aaSAndroid Build Coastguard Worker     return make_effect_fp(filter->effect(),
432*c8dee2aaSAndroid Build Coastguard Worker                           "runtime_color_filter",
433*c8dee2aaSAndroid Build Coastguard Worker                           std::move(uniforms),
434*c8dee2aaSAndroid Build Coastguard Worker                           std::move(inputFP),
435*c8dee2aaSAndroid Build Coastguard Worker                           /*destColorFP=*/nullptr,
436*c8dee2aaSAndroid Build Coastguard Worker                           filter->children(),
437*c8dee2aaSAndroid Build Coastguard Worker                           childArgs);
438*c8dee2aaSAndroid Build Coastguard Worker }
439*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext * context,const SkTableColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo &,const SkSurfaceProps &)440*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
441*c8dee2aaSAndroid Build Coastguard Worker                                       const SkTableColorFilter* filter,
442*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
443*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo&,
444*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps&) {
445*c8dee2aaSAndroid Build Coastguard Worker     auto cte = ColorTableEffect::Make(std::move(inputFP), context, filter->bitmap());
446*c8dee2aaSAndroid Build Coastguard Worker     return cte ? GrFPSuccess(std::move(cte)) : GrFPFailure(nullptr);
447*c8dee2aaSAndroid Build Coastguard Worker }
448*c8dee2aaSAndroid Build Coastguard Worker 
make_colorfilter_fp(GrRecordingContext * context,const SkWorkingFormatColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & dstColorInfo,const SkSurfaceProps & props)449*c8dee2aaSAndroid Build Coastguard Worker static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
450*c8dee2aaSAndroid Build Coastguard Worker                                       const SkWorkingFormatColorFilter* filter,
451*c8dee2aaSAndroid Build Coastguard Worker                                       std::unique_ptr<GrFragmentProcessor> inputFP,
452*c8dee2aaSAndroid Build Coastguard Worker                                       const GrColorInfo& dstColorInfo,
453*c8dee2aaSAndroid Build Coastguard Worker                                       const SkSurfaceProps& props) {
454*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorSpace> dstCS = dstColorInfo.refColorSpace();
455*c8dee2aaSAndroid Build Coastguard Worker     if (!dstCS) {
456*c8dee2aaSAndroid Build Coastguard Worker         dstCS = SkColorSpace::MakeSRGB();
457*c8dee2aaSAndroid Build Coastguard Worker     }
458*c8dee2aaSAndroid Build Coastguard Worker 
459*c8dee2aaSAndroid Build Coastguard Worker     SkAlphaType workingAT;
460*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorSpace> workingCS = filter->workingFormat(dstCS, &workingAT);
461*c8dee2aaSAndroid Build Coastguard Worker 
462*c8dee2aaSAndroid Build Coastguard Worker     GrColorInfo dst = {dstColorInfo.colorType(), dstColorInfo.alphaType(), dstCS},
463*c8dee2aaSAndroid Build Coastguard Worker                 working = {dstColorInfo.colorType(), workingAT, workingCS};
464*c8dee2aaSAndroid Build Coastguard Worker 
465*c8dee2aaSAndroid Build Coastguard Worker     auto [ok, fp] = Make(context,
466*c8dee2aaSAndroid Build Coastguard Worker                          filter->child().get(),
467*c8dee2aaSAndroid Build Coastguard Worker                          GrColorSpaceXformEffect::Make(std::move(inputFP), dst, working),
468*c8dee2aaSAndroid Build Coastguard Worker                          working,
469*c8dee2aaSAndroid Build Coastguard Worker                          props);
470*c8dee2aaSAndroid Build Coastguard Worker 
471*c8dee2aaSAndroid Build Coastguard Worker     return ok ? GrFPSuccess(GrColorSpaceXformEffect::Make(std::move(fp), working, dst))
472*c8dee2aaSAndroid Build Coastguard Worker               : GrFPFailure(std::move(fp));
473*c8dee2aaSAndroid Build Coastguard Worker }
474*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * ctx,const SkColorFilter * cf,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & dstColorInfo,const SkSurfaceProps & props)475*c8dee2aaSAndroid Build Coastguard Worker GrFPResult Make(GrRecordingContext* ctx,
476*c8dee2aaSAndroid Build Coastguard Worker                 const SkColorFilter* cf,
477*c8dee2aaSAndroid Build Coastguard Worker                 std::unique_ptr<GrFragmentProcessor> inputFP,
478*c8dee2aaSAndroid Build Coastguard Worker                 const GrColorInfo& dstColorInfo,
479*c8dee2aaSAndroid Build Coastguard Worker                 const SkSurfaceProps& props) {
480*c8dee2aaSAndroid Build Coastguard Worker     if (!cf) {
481*c8dee2aaSAndroid Build Coastguard Worker         return GrFPFailure(nullptr);
482*c8dee2aaSAndroid Build Coastguard Worker     }
483*c8dee2aaSAndroid Build Coastguard Worker     auto cfb = as_CFB(cf);
484*c8dee2aaSAndroid Build Coastguard Worker     switch (cfb->type()) {
485*c8dee2aaSAndroid Build Coastguard Worker         case SkColorFilterBase::Type::kNoop:
486*c8dee2aaSAndroid Build Coastguard Worker             return GrFPFailure(nullptr);
487*c8dee2aaSAndroid Build Coastguard Worker #define M(type)                                                                   \
488*c8dee2aaSAndroid Build Coastguard Worker     case SkColorFilterBase::Type::k##type:                                        \
489*c8dee2aaSAndroid Build Coastguard Worker         return make_colorfilter_fp(ctx,                                           \
490*c8dee2aaSAndroid Build Coastguard Worker                                    static_cast<const Sk##type##ColorFilter*>(cf), \
491*c8dee2aaSAndroid Build Coastguard Worker                                    std::move(inputFP),                            \
492*c8dee2aaSAndroid Build Coastguard Worker                                    dstColorInfo,                                  \
493*c8dee2aaSAndroid Build Coastguard Worker                                    props);
494*c8dee2aaSAndroid Build Coastguard Worker             SK_ALL_COLOR_FILTERS(M)
495*c8dee2aaSAndroid Build Coastguard Worker #undef M
496*c8dee2aaSAndroid Build Coastguard Worker     }
497*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkBlendShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)500*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkBlendShader* shader,
501*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
502*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
503*c8dee2aaSAndroid Build Coastguard Worker     auto fpA = Make(shader->dst().get(), args, mRec);
504*c8dee2aaSAndroid Build Coastguard Worker     auto fpB = Make(shader->src().get(), args, mRec);
505*c8dee2aaSAndroid Build Coastguard Worker     if (!fpA || !fpB) {
506*c8dee2aaSAndroid Build Coastguard Worker         // This is unexpected. Both src and dst shaders should be valid. Just fail.
507*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
508*c8dee2aaSAndroid Build Coastguard Worker     }
509*c8dee2aaSAndroid Build Coastguard Worker     return GrBlendFragmentProcessor::Make(std::move(fpB), std::move(fpA), shader->mode());
510*c8dee2aaSAndroid Build Coastguard Worker }
511*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkColorFilterShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)512*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkColorFilterShader* shader,
513*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
514*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
515*c8dee2aaSAndroid Build Coastguard Worker     auto shaderFP = Make(shader->shader().get(), args, mRec);
516*c8dee2aaSAndroid Build Coastguard Worker     if (!shaderFP) {
517*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
518*c8dee2aaSAndroid Build Coastguard Worker     }
519*c8dee2aaSAndroid Build Coastguard Worker 
520*c8dee2aaSAndroid Build Coastguard Worker     // TODO I guess, but it shouldn't come up as used today.
521*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(shader->alpha() == 1.0f);
522*c8dee2aaSAndroid Build Coastguard Worker 
523*c8dee2aaSAndroid Build Coastguard Worker     auto [success, fp] = Make(args.fContext,
524*c8dee2aaSAndroid Build Coastguard Worker                               shader->filter().get(),
525*c8dee2aaSAndroid Build Coastguard Worker                               std::move(shaderFP),
526*c8dee2aaSAndroid Build Coastguard Worker                               *args.fDstColorInfo,
527*c8dee2aaSAndroid Build Coastguard Worker                               args.fSurfaceProps);
528*c8dee2aaSAndroid Build Coastguard Worker     // If the filter FP could not be created, we still want to return the shader FP, so checking
529*c8dee2aaSAndroid Build Coastguard Worker     // success can be omitted here.
530*c8dee2aaSAndroid Build Coastguard Worker     return std::move(fp);
531*c8dee2aaSAndroid Build Coastguard Worker }
532*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkColorShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)533*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkColorShader* shader,
534*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
535*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
536*c8dee2aaSAndroid Build Coastguard Worker     return GrFragmentProcessor::MakeColor(SkColorToPMColor4f(shader->color(), *args.fDstColorInfo));
537*c8dee2aaSAndroid Build Coastguard Worker }
538*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkColor4Shader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)539*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkColor4Shader* shader,
540*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
541*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
542*c8dee2aaSAndroid Build Coastguard Worker     SkColorSpaceXformSteps steps{shader->colorSpace().get(),
543*c8dee2aaSAndroid Build Coastguard Worker                                  kUnpremul_SkAlphaType,
544*c8dee2aaSAndroid Build Coastguard Worker                                  args.fDstColorInfo->colorSpace(),
545*c8dee2aaSAndroid Build Coastguard Worker                                  kUnpremul_SkAlphaType};
546*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f color = shader->color();
547*c8dee2aaSAndroid Build Coastguard Worker     steps.apply(color.vec());
548*c8dee2aaSAndroid Build Coastguard Worker     return GrFragmentProcessor::MakeColor(color.premul());
549*c8dee2aaSAndroid Build Coastguard Worker }
550*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkCoordClampShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)551*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkCoordClampShader* shader,
552*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
553*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
554*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect =
555*c8dee2aaSAndroid Build Coastguard Worker             SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
556*c8dee2aaSAndroid Build Coastguard Worker                                 "uniform shader c;"
557*c8dee2aaSAndroid Build Coastguard Worker                                 "uniform float4 s;"
558*c8dee2aaSAndroid Build Coastguard Worker                                 "half4 main(float2 p) {"
559*c8dee2aaSAndroid Build Coastguard Worker                                     "return c.eval(clamp(p, s.LT, s.RB));"
560*c8dee2aaSAndroid Build Coastguard Worker                                 "}");
561*c8dee2aaSAndroid Build Coastguard Worker 
562*c8dee2aaSAndroid Build Coastguard Worker     auto fp = Make(shader->shader().get(), args, mRec.applied());
563*c8dee2aaSAndroid Build Coastguard Worker     if (!fp) {
564*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
565*c8dee2aaSAndroid Build Coastguard Worker     }
566*c8dee2aaSAndroid Build Coastguard Worker 
567*c8dee2aaSAndroid Build Coastguard Worker     GrSkSLFP::OptFlags flags = GrSkSLFP::OptFlags::kNone;
568*c8dee2aaSAndroid Build Coastguard Worker     if (fp->compatibleWithCoverageAsAlpha()) {
569*c8dee2aaSAndroid Build Coastguard Worker         flags |= GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha;
570*c8dee2aaSAndroid Build Coastguard Worker     }
571*c8dee2aaSAndroid Build Coastguard Worker     if (fp->preservesOpaqueInput()) {
572*c8dee2aaSAndroid Build Coastguard Worker         flags |= GrSkSLFP::OptFlags::kPreservesOpaqueInput;
573*c8dee2aaSAndroid Build Coastguard Worker     }
574*c8dee2aaSAndroid Build Coastguard Worker     fp = GrSkSLFP::Make(effect,
575*c8dee2aaSAndroid Build Coastguard Worker                         "clamp_fp",
576*c8dee2aaSAndroid Build Coastguard Worker                         /*inputFP=*/nullptr,
577*c8dee2aaSAndroid Build Coastguard Worker                         flags,
578*c8dee2aaSAndroid Build Coastguard Worker                         "c",
579*c8dee2aaSAndroid Build Coastguard Worker                         std::move(fp),
580*c8dee2aaSAndroid Build Coastguard Worker                         "s",
581*c8dee2aaSAndroid Build Coastguard Worker                         shader->subset());
582*c8dee2aaSAndroid Build Coastguard Worker 
583*c8dee2aaSAndroid Build Coastguard Worker     auto [total, ok] = mRec.applyForFragmentProcessor({});
584*c8dee2aaSAndroid Build Coastguard Worker     if (!ok) {
585*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
586*c8dee2aaSAndroid Build Coastguard Worker     }
587*c8dee2aaSAndroid Build Coastguard Worker     return GrMatrixEffect::Make(total, std::move(fp));
588*c8dee2aaSAndroid Build Coastguard Worker }
589*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkCTMShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)590*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkCTMShader* shader,
591*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
592*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
593*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix ctmInv;
594*c8dee2aaSAndroid Build Coastguard Worker     if (!shader->ctm().invert(&ctmInv)) {
595*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
596*c8dee2aaSAndroid Build Coastguard Worker     }
597*c8dee2aaSAndroid Build Coastguard Worker 
598*c8dee2aaSAndroid Build Coastguard Worker     auto base = Make(shader->proxyShader().get(), args, shader->ctm());
599*c8dee2aaSAndroid Build Coastguard Worker     if (!base) {
600*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
601*c8dee2aaSAndroid Build Coastguard Worker     }
602*c8dee2aaSAndroid Build Coastguard Worker 
603*c8dee2aaSAndroid Build Coastguard Worker     // In order for the shader to be evaluated with the original CTM, we explicitly evaluate it
604*c8dee2aaSAndroid Build Coastguard Worker     // at sk_FragCoord, and pass that through the inverse of the original CTM. This avoids requiring
605*c8dee2aaSAndroid Build Coastguard Worker     // local coords for the shader and mapping from the draw's local to device and then back.
606*c8dee2aaSAndroid Build Coastguard Worker     return GrFragmentProcessor::DeviceSpace(GrMatrixEffect::Make(ctmInv, std::move(base)));
607*c8dee2aaSAndroid Build Coastguard Worker }
608*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkEmptyShader * shader,const GrFPArgs &,const SkShaders::MatrixRec &)609*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkEmptyShader* shader,
610*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs&,
611*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec&) {
612*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
613*c8dee2aaSAndroid Build Coastguard Worker }
614*c8dee2aaSAndroid Build Coastguard Worker 
needs_subset(sk_sp<const SkImage> img,const SkRect & subset)615*c8dee2aaSAndroid Build Coastguard Worker static bool needs_subset(sk_sp<const SkImage> img, const SkRect& subset) {
616*c8dee2aaSAndroid Build Coastguard Worker     return subset != SkRect::Make(img->dimensions());
617*c8dee2aaSAndroid Build Coastguard Worker }
618*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkImageShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)619*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkImageShader* shader,
620*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
621*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
622*c8dee2aaSAndroid Build Coastguard Worker     SkTileMode tileModes[2] = {shader->tileModeX(), shader->tileModeY()};
623*c8dee2aaSAndroid Build Coastguard Worker     const SkRect shaderSubset = shader->subset();
624*c8dee2aaSAndroid Build Coastguard Worker     const SkRect* subset = needs_subset(shader->image(), shaderSubset) ? &shaderSubset : nullptr;
625*c8dee2aaSAndroid Build Coastguard Worker     auto fp = skgpu::ganesh::AsFragmentProcessor(
626*c8dee2aaSAndroid Build Coastguard Worker             args.fContext, shader->image(), shader->sampling(), tileModes, SkMatrix::I(), subset);
627*c8dee2aaSAndroid Build Coastguard Worker     if (!fp) {
628*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
629*c8dee2aaSAndroid Build Coastguard Worker     }
630*c8dee2aaSAndroid Build Coastguard Worker 
631*c8dee2aaSAndroid Build Coastguard Worker     auto [total, ok] = mRec.applyForFragmentProcessor({});
632*c8dee2aaSAndroid Build Coastguard Worker     if (!ok) {
633*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
634*c8dee2aaSAndroid Build Coastguard Worker     }
635*c8dee2aaSAndroid Build Coastguard Worker     fp = GrMatrixEffect::Make(total, std::move(fp));
636*c8dee2aaSAndroid Build Coastguard Worker 
637*c8dee2aaSAndroid Build Coastguard Worker     if (!shader->isRaw()) {
638*c8dee2aaSAndroid Build Coastguard Worker         fp = GrColorSpaceXformEffect::Make(std::move(fp),
639*c8dee2aaSAndroid Build Coastguard Worker                                            shader->image()->colorSpace(),
640*c8dee2aaSAndroid Build Coastguard Worker                                            shader->image()->alphaType(),
641*c8dee2aaSAndroid Build Coastguard Worker                                            args.fDstColorInfo->colorSpace(),
642*c8dee2aaSAndroid Build Coastguard Worker                                            kPremul_SkAlphaType);
643*c8dee2aaSAndroid Build Coastguard Worker 
644*c8dee2aaSAndroid Build Coastguard Worker         // Alpha-only image shaders are tinted by the input color (typically the paint color).
645*c8dee2aaSAndroid Build Coastguard Worker         // We suppress that behavior when sampled from a runtime effect.
646*c8dee2aaSAndroid Build Coastguard Worker         if (shader->image()->isAlphaOnly() && args.fScope != GrFPArgs::Scope::kRuntimeEffect) {
647*c8dee2aaSAndroid Build Coastguard Worker             fp = GrBlendFragmentProcessor::Make<SkBlendMode::kDstIn>(std::move(fp), nullptr);
648*c8dee2aaSAndroid Build Coastguard Worker         }
649*c8dee2aaSAndroid Build Coastguard Worker     }
650*c8dee2aaSAndroid Build Coastguard Worker 
651*c8dee2aaSAndroid Build Coastguard Worker     return fp;
652*c8dee2aaSAndroid Build Coastguard Worker }
653*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkLocalMatrixShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)654*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkLocalMatrixShader* shader,
655*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
656*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
657*c8dee2aaSAndroid Build Coastguard Worker     return Make(shader->wrappedShader().get(), args, mRec.concat(shader->localMatrix()));
658*c8dee2aaSAndroid Build Coastguard Worker }
659*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkPerlinNoiseShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)660*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkPerlinNoiseShader* shader,
661*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
662*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
663*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(args.fContext);
664*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(shader->numOctaves());
665*c8dee2aaSAndroid Build Coastguard Worker 
666*c8dee2aaSAndroid Build Coastguard Worker     // Either we don't stitch tiles, or we have a valid tile size
667*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!shader->stitchTiles() || !shader->tileSize().isEmpty());
668*c8dee2aaSAndroid Build Coastguard Worker 
669*c8dee2aaSAndroid Build Coastguard Worker     auto paintingData = shader->getPaintingData();
670*c8dee2aaSAndroid Build Coastguard Worker     paintingData->generateBitmaps();
671*c8dee2aaSAndroid Build Coastguard Worker 
672*c8dee2aaSAndroid Build Coastguard Worker     GrRecordingContext* context = args.fContext;
673*c8dee2aaSAndroid Build Coastguard Worker 
674*c8dee2aaSAndroid Build Coastguard Worker     const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
675*c8dee2aaSAndroid Build Coastguard Worker     const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
676*c8dee2aaSAndroid Build Coastguard Worker 
677*c8dee2aaSAndroid Build Coastguard Worker     auto permutationsView = std::get<0>(GrMakeCachedBitmapProxyView(
678*c8dee2aaSAndroid Build Coastguard Worker             context,
679*c8dee2aaSAndroid Build Coastguard Worker             permutationsBitmap,
680*c8dee2aaSAndroid Build Coastguard Worker             /*label=*/"PerlinNoiseShader_FragmentProcessor_PermutationsView"));
681*c8dee2aaSAndroid Build Coastguard Worker 
682*c8dee2aaSAndroid Build Coastguard Worker     auto noiseView = std::get<0>(GrMakeCachedBitmapProxyView(
683*c8dee2aaSAndroid Build Coastguard Worker             context, noiseBitmap, /*label=*/"PerlinNoiseShader_FragmentProcessor_NoiseView"));
684*c8dee2aaSAndroid Build Coastguard Worker 
685*c8dee2aaSAndroid Build Coastguard Worker     if (!permutationsView || !noiseView) {
686*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
687*c8dee2aaSAndroid Build Coastguard Worker     }
688*c8dee2aaSAndroid Build Coastguard Worker 
689*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GrFragmentProcessor> fp =
690*c8dee2aaSAndroid Build Coastguard Worker             GrPerlinNoise2Effect::Make(shader->noiseType(),
691*c8dee2aaSAndroid Build Coastguard Worker                                        shader->numOctaves(),
692*c8dee2aaSAndroid Build Coastguard Worker                                        shader->stitchTiles(),
693*c8dee2aaSAndroid Build Coastguard Worker                                        std::move(paintingData),
694*c8dee2aaSAndroid Build Coastguard Worker                                        std::move(permutationsView),
695*c8dee2aaSAndroid Build Coastguard Worker                                        std::move(noiseView),
696*c8dee2aaSAndroid Build Coastguard Worker                                        *context->priv().caps());
697*c8dee2aaSAndroid Build Coastguard Worker     if (!fp) {
698*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
699*c8dee2aaSAndroid Build Coastguard Worker     }
700*c8dee2aaSAndroid Build Coastguard Worker     auto [total, ok] = mRec.applyForFragmentProcessor({});
701*c8dee2aaSAndroid Build Coastguard Worker     if (!ok) {
702*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
703*c8dee2aaSAndroid Build Coastguard Worker     }
704*c8dee2aaSAndroid Build Coastguard Worker     return GrMatrixEffect::Make(total, std::move(fp));
705*c8dee2aaSAndroid Build Coastguard Worker }
706*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkPictureShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)707*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkPictureShader* shader,
708*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
709*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
710*c8dee2aaSAndroid Build Coastguard Worker     auto ctx = args.fContext;
711*c8dee2aaSAndroid Build Coastguard Worker     SkColorType dstColorType = GrColorTypeToSkColorType(args.fDstColorInfo->colorType());
712*c8dee2aaSAndroid Build Coastguard Worker     if (dstColorType == kUnknown_SkColorType) {
713*c8dee2aaSAndroid Build Coastguard Worker         dstColorType = kRGBA_8888_SkColorType;
714*c8dee2aaSAndroid Build Coastguard Worker     }
715*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorSpace> dstCS = SkColorSpace::MakeSRGB();
716*c8dee2aaSAndroid Build Coastguard Worker     if (args.fDstColorInfo->colorSpace()) {
717*c8dee2aaSAndroid Build Coastguard Worker         dstCS = sk_ref_sp(args.fDstColorInfo->colorSpace());
718*c8dee2aaSAndroid Build Coastguard Worker     }
719*c8dee2aaSAndroid Build Coastguard Worker 
720*c8dee2aaSAndroid Build Coastguard Worker     auto info = SkPictureShader::CachedImageInfo::Make(shader->tile(),
721*c8dee2aaSAndroid Build Coastguard Worker                                                        mRec.totalMatrix(),
722*c8dee2aaSAndroid Build Coastguard Worker                                                        dstColorType,
723*c8dee2aaSAndroid Build Coastguard Worker                                                        dstCS.get(),
724*c8dee2aaSAndroid Build Coastguard Worker                                                        ctx->priv().caps()->maxTextureSize(),
725*c8dee2aaSAndroid Build Coastguard Worker                                                        args.fSurfaceProps);
726*c8dee2aaSAndroid Build Coastguard Worker     if (!info.success) {
727*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
728*c8dee2aaSAndroid Build Coastguard Worker     }
729*c8dee2aaSAndroid Build Coastguard Worker 
730*c8dee2aaSAndroid Build Coastguard Worker     // Gotta be sure the GPU can support our requested colortype (might be FP16)
731*c8dee2aaSAndroid Build Coastguard Worker     if (!ctx->colorTypeSupportedAsSurface(info.imageInfo.colorType())) {
732*c8dee2aaSAndroid Build Coastguard Worker         info.imageInfo = info.imageInfo.makeColorType(kRGBA_8888_SkColorType);
733*c8dee2aaSAndroid Build Coastguard Worker     }
734*c8dee2aaSAndroid Build Coastguard Worker 
735*c8dee2aaSAndroid Build Coastguard Worker     static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain();
736*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKey key;
737*c8dee2aaSAndroid Build Coastguard Worker     std::tuple keyData = {dstCS->toXYZD50Hash(),
738*c8dee2aaSAndroid Build Coastguard Worker                           dstCS->transferFnHash(),
739*c8dee2aaSAndroid Build Coastguard Worker                           static_cast<uint32_t>(dstColorType),
740*c8dee2aaSAndroid Build Coastguard Worker                           shader->picture()->uniqueID(),
741*c8dee2aaSAndroid Build Coastguard Worker                           shader->tile(),
742*c8dee2aaSAndroid Build Coastguard Worker                           info.tileScale,
743*c8dee2aaSAndroid Build Coastguard Worker                           info.props};
744*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKey::Builder builder(
745*c8dee2aaSAndroid Build Coastguard Worker             &key, kDomain, sizeof(keyData) / sizeof(uint32_t), "Picture Shader Image");
746*c8dee2aaSAndroid Build Coastguard Worker     memcpy(&builder[0], &keyData, sizeof(keyData));
747*c8dee2aaSAndroid Build Coastguard Worker     builder.finish();
748*c8dee2aaSAndroid Build Coastguard Worker 
749*c8dee2aaSAndroid Build Coastguard Worker     GrProxyProvider* provider = ctx->priv().proxyProvider();
750*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView view;
751*c8dee2aaSAndroid Build Coastguard Worker     if (auto proxy = provider->findOrCreateProxyByUniqueKey(key)) {
752*c8dee2aaSAndroid Build Coastguard Worker         view = GrSurfaceProxyView(proxy, kTopLeft_GrSurfaceOrigin, skgpu::Swizzle());
753*c8dee2aaSAndroid Build Coastguard Worker     } else {
754*c8dee2aaSAndroid Build Coastguard Worker         const int msaaSampleCount = 0;
755*c8dee2aaSAndroid Build Coastguard Worker         const bool createWithMips = false;
756*c8dee2aaSAndroid Build Coastguard Worker         const bool kUnprotected = false;
757*c8dee2aaSAndroid Build Coastguard Worker         auto image = info.makeImage(SkSurfaces::RenderTarget(ctx,
758*c8dee2aaSAndroid Build Coastguard Worker                                                              skgpu::Budgeted::kYes,
759*c8dee2aaSAndroid Build Coastguard Worker                                                              info.imageInfo,
760*c8dee2aaSAndroid Build Coastguard Worker                                                              msaaSampleCount,
761*c8dee2aaSAndroid Build Coastguard Worker                                                              kTopLeft_GrSurfaceOrigin,
762*c8dee2aaSAndroid Build Coastguard Worker                                                              &info.props,
763*c8dee2aaSAndroid Build Coastguard Worker                                                              createWithMips,
764*c8dee2aaSAndroid Build Coastguard Worker                                                              kUnprotected),
765*c8dee2aaSAndroid Build Coastguard Worker                                     shader->picture().get());
766*c8dee2aaSAndroid Build Coastguard Worker         if (!image) {
767*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
768*c8dee2aaSAndroid Build Coastguard Worker         }
769*c8dee2aaSAndroid Build Coastguard Worker 
770*c8dee2aaSAndroid Build Coastguard Worker         auto [v, ct] = skgpu::ganesh::AsView(ctx, image, skgpu::Mipmapped::kNo);
771*c8dee2aaSAndroid Build Coastguard Worker         view = std::move(v);
772*c8dee2aaSAndroid Build Coastguard Worker         provider->assignUniqueKeyToProxy(key, view.asTextureProxy());
773*c8dee2aaSAndroid Build Coastguard Worker     }
774*c8dee2aaSAndroid Build Coastguard Worker 
775*c8dee2aaSAndroid Build Coastguard Worker     const GrSamplerState sampler(static_cast<GrSamplerState::WrapMode>(shader->tileModeX()),
776*c8dee2aaSAndroid Build Coastguard Worker                                  static_cast<GrSamplerState::WrapMode>(shader->tileModeY()),
777*c8dee2aaSAndroid Build Coastguard Worker                                  shader->filter());
778*c8dee2aaSAndroid Build Coastguard Worker     auto fp = GrTextureEffect::Make(
779*c8dee2aaSAndroid Build Coastguard Worker             std::move(view), kPremul_SkAlphaType, SkMatrix::I(), sampler, *ctx->priv().caps());
780*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix scale = SkMatrix::Scale(info.tileScale.width(), info.tileScale.height());
781*c8dee2aaSAndroid Build Coastguard Worker     auto [total, ok] = mRec.applyForFragmentProcessor(scale);
782*c8dee2aaSAndroid Build Coastguard Worker     if (!ok) {
783*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
784*c8dee2aaSAndroid Build Coastguard Worker     }
785*c8dee2aaSAndroid Build Coastguard Worker     return GrMatrixEffect::Make(total, std::move(fp));
786*c8dee2aaSAndroid Build Coastguard Worker }
787*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkRuntimeShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)788*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkRuntimeShader* shader,
789*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
790*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
791*c8dee2aaSAndroid Build Coastguard Worker     if (!SkRuntimeEffectPriv::CanDraw(args.fContext->priv().caps(), shader->asRuntimeEffect())) {
792*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
793*c8dee2aaSAndroid Build Coastguard Worker     }
794*c8dee2aaSAndroid Build Coastguard Worker 
795*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
796*c8dee2aaSAndroid Build Coastguard Worker             shader->asRuntimeEffect()->uniforms(),
797*c8dee2aaSAndroid Build Coastguard Worker             shader->uniformData(args.fDstColorInfo->colorSpace()),
798*c8dee2aaSAndroid Build Coastguard Worker             args.fDstColorInfo->colorSpace());
799*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(uniforms);
800*c8dee2aaSAndroid Build Coastguard Worker 
801*c8dee2aaSAndroid Build Coastguard Worker     bool success;
802*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GrFragmentProcessor> fp;
803*c8dee2aaSAndroid Build Coastguard Worker     GrFPArgs childArgs(
804*c8dee2aaSAndroid Build Coastguard Worker             args.fContext, args.fDstColorInfo, args.fSurfaceProps, GrFPArgs::Scope::kRuntimeEffect);
805*c8dee2aaSAndroid Build Coastguard Worker     std::tie(success, fp) = make_effect_fp(shader->effect(),
806*c8dee2aaSAndroid Build Coastguard Worker                                            "runtime_shader",
807*c8dee2aaSAndroid Build Coastguard Worker                                            std::move(uniforms),
808*c8dee2aaSAndroid Build Coastguard Worker                                            /*inputFP=*/nullptr,
809*c8dee2aaSAndroid Build Coastguard Worker                                            /*destColorFP=*/nullptr,
810*c8dee2aaSAndroid Build Coastguard Worker                                            shader->children(),
811*c8dee2aaSAndroid Build Coastguard Worker                                            childArgs);
812*c8dee2aaSAndroid Build Coastguard Worker     if (!success) {
813*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
814*c8dee2aaSAndroid Build Coastguard Worker     }
815*c8dee2aaSAndroid Build Coastguard Worker 
816*c8dee2aaSAndroid Build Coastguard Worker     auto [total, ok] = mRec.applyForFragmentProcessor({});
817*c8dee2aaSAndroid Build Coastguard Worker     if (!ok) {
818*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
819*c8dee2aaSAndroid Build Coastguard Worker     }
820*c8dee2aaSAndroid Build Coastguard Worker     return GrMatrixEffect::Make(total, std::move(fp));
821*c8dee2aaSAndroid Build Coastguard Worker }
822*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkTransformShader * shader,const GrFPArgs &,const SkShaders::MatrixRec &)823*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkTransformShader* shader,
824*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs&,
825*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec&) {
826*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
827*c8dee2aaSAndroid Build Coastguard Worker }
828*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkTriColorShader * shader,const GrFPArgs &,const SkShaders::MatrixRec &)829*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkTriColorShader* shader,
830*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs&,
831*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec&) {
832*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
833*c8dee2aaSAndroid Build Coastguard Worker }
834*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkWorkingColorSpaceShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)835*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkWorkingColorSpaceShader* shader,
836*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
837*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
838*c8dee2aaSAndroid Build Coastguard Worker     const GrColorInfo* dstInfo = args.fDstColorInfo;
839*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorSpace> dstCS = dstInfo->refColorSpace();
840*c8dee2aaSAndroid Build Coastguard Worker     if (!dstCS) {
841*c8dee2aaSAndroid Build Coastguard Worker         dstCS = SkColorSpace::MakeSRGB();
842*c8dee2aaSAndroid Build Coastguard Worker     }
843*c8dee2aaSAndroid Build Coastguard Worker 
844*c8dee2aaSAndroid Build Coastguard Worker     GrColorInfo dst     = {dstInfo->colorType(), dstInfo->alphaType(), dstCS},
845*c8dee2aaSAndroid Build Coastguard Worker                 working = {dstInfo->colorType(), dstInfo->alphaType(), shader->workingSpace()};
846*c8dee2aaSAndroid Build Coastguard Worker     GrFPArgs workingArgs(args.fContext, &working, args.fSurfaceProps, args.fScope);
847*c8dee2aaSAndroid Build Coastguard Worker 
848*c8dee2aaSAndroid Build Coastguard Worker     auto childFP = Make(shader->shader().get(), workingArgs, mRec);
849*c8dee2aaSAndroid Build Coastguard Worker     if (!childFP) {
850*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
851*c8dee2aaSAndroid Build Coastguard Worker     }
852*c8dee2aaSAndroid Build Coastguard Worker 
853*c8dee2aaSAndroid Build Coastguard Worker     auto childWithWorkingInput = GrFragmentProcessor::Compose(
854*c8dee2aaSAndroid Build Coastguard Worker             std::move(childFP), GrColorSpaceXformEffect::Make(nullptr, dst, working));
855*c8dee2aaSAndroid Build Coastguard Worker 
856*c8dee2aaSAndroid Build Coastguard Worker     return GrColorSpaceXformEffect::Make(std::move(childWithWorkingInput), working, dst);
857*c8dee2aaSAndroid Build Coastguard Worker }
858*c8dee2aaSAndroid Build Coastguard Worker 
859*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////////////////////
860*c8dee2aaSAndroid Build Coastguard Worker 
make_gradient_fp(const SkConicalGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)861*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkConicalGradient* shader,
862*c8dee2aaSAndroid Build Coastguard Worker                                                              const GrFPArgs& args,
863*c8dee2aaSAndroid Build Coastguard Worker                                                              const SkShaders::MatrixRec& mRec) {
864*c8dee2aaSAndroid Build Coastguard Worker     // The 2 point conical gradient can reject a pixel so it does change opacity even if the input
865*c8dee2aaSAndroid Build Coastguard Worker     // was opaque. Thus, all of these layout FPs disable that optimization.
866*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GrFragmentProcessor> fp;
867*c8dee2aaSAndroid Build Coastguard Worker     SkTLazy<SkMatrix> matrix;
868*c8dee2aaSAndroid Build Coastguard Worker     switch (shader->getType()) {
869*c8dee2aaSAndroid Build Coastguard Worker         case SkConicalGradient::Type::kStrip: {
870*c8dee2aaSAndroid Build Coastguard Worker             static const SkRuntimeEffect* kEffect =
871*c8dee2aaSAndroid Build Coastguard Worker                 SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
872*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half r0_2;"
873*c8dee2aaSAndroid Build Coastguard Worker                         "half4 main(float2 p) {"
874*c8dee2aaSAndroid Build Coastguard Worker                             // validation flag, set to negative to discard fragment later.
875*c8dee2aaSAndroid Build Coastguard Worker                             "half v = 1;"
876*c8dee2aaSAndroid Build Coastguard Worker                             "float t = r0_2 - p.y * p.y;"
877*c8dee2aaSAndroid Build Coastguard Worker                             "if (t >= 0) {"
878*c8dee2aaSAndroid Build Coastguard Worker                                 "t = p.x + sqrt(t);"
879*c8dee2aaSAndroid Build Coastguard Worker                             "} else {"
880*c8dee2aaSAndroid Build Coastguard Worker                                 "v = -1;"
881*c8dee2aaSAndroid Build Coastguard Worker                             "}"
882*c8dee2aaSAndroid Build Coastguard Worker                             "return half4(half(t), v, 0, 0);"
883*c8dee2aaSAndroid Build Coastguard Worker                         "}"
884*c8dee2aaSAndroid Build Coastguard Worker                     );
885*c8dee2aaSAndroid Build Coastguard Worker             float r0 = shader->getStartRadius() / shader->getCenterX1();
886*c8dee2aaSAndroid Build Coastguard Worker             fp = GrSkSLFP::Make(kEffect,
887*c8dee2aaSAndroid Build Coastguard Worker                                 "TwoPointConicalStripLayout",
888*c8dee2aaSAndroid Build Coastguard Worker                                 /*inputFP=*/nullptr,
889*c8dee2aaSAndroid Build Coastguard Worker                                 GrSkSLFP::OptFlags::kNone,
890*c8dee2aaSAndroid Build Coastguard Worker                                 "r0_2",
891*c8dee2aaSAndroid Build Coastguard Worker                                 r0 * r0);
892*c8dee2aaSAndroid Build Coastguard Worker         } break;
893*c8dee2aaSAndroid Build Coastguard Worker 
894*c8dee2aaSAndroid Build Coastguard Worker         case SkConicalGradient::Type::kRadial: {
895*c8dee2aaSAndroid Build Coastguard Worker             static const SkRuntimeEffect* kEffect =
896*c8dee2aaSAndroid Build Coastguard Worker                 SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
897*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half r0;"
898*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half lengthScale;"
899*c8dee2aaSAndroid Build Coastguard Worker                         "half4 main(float2 p) {"
900*c8dee2aaSAndroid Build Coastguard Worker                             // validation flag, set to negative to discard fragment later
901*c8dee2aaSAndroid Build Coastguard Worker                             "half v = 1;"
902*c8dee2aaSAndroid Build Coastguard Worker                             "float t = length(p) * lengthScale - r0;"
903*c8dee2aaSAndroid Build Coastguard Worker                             "return half4(half(t), v, 0, 0);"
904*c8dee2aaSAndroid Build Coastguard Worker                         "}"
905*c8dee2aaSAndroid Build Coastguard Worker                     );
906*c8dee2aaSAndroid Build Coastguard Worker             float dr = shader->getDiffRadius();
907*c8dee2aaSAndroid Build Coastguard Worker             float r0 = shader->getStartRadius() / dr;
908*c8dee2aaSAndroid Build Coastguard Worker             bool isRadiusIncreasing = dr >= 0;
909*c8dee2aaSAndroid Build Coastguard Worker             fp = GrSkSLFP::Make(kEffect,
910*c8dee2aaSAndroid Build Coastguard Worker                                 "TwoPointConicalRadialLayout",
911*c8dee2aaSAndroid Build Coastguard Worker                                 /*inputFP=*/nullptr,
912*c8dee2aaSAndroid Build Coastguard Worker                                 GrSkSLFP::OptFlags::kNone,
913*c8dee2aaSAndroid Build Coastguard Worker                                 "r0",
914*c8dee2aaSAndroid Build Coastguard Worker                                 r0,
915*c8dee2aaSAndroid Build Coastguard Worker                                 "lengthScale",
916*c8dee2aaSAndroid Build Coastguard Worker                                 isRadiusIncreasing ? 1.0f : -1.0f);
917*c8dee2aaSAndroid Build Coastguard Worker 
918*c8dee2aaSAndroid Build Coastguard Worker             // GPU radial matrix is different from the original matrix, since we map the diff radius
919*c8dee2aaSAndroid Build Coastguard Worker             // to have |dr| = 1, so manually compute the final gradient matrix here.
920*c8dee2aaSAndroid Build Coastguard Worker 
921*c8dee2aaSAndroid Build Coastguard Worker             // Map center to (0, 0)
922*c8dee2aaSAndroid Build Coastguard Worker             matrix.set(SkMatrix::Translate(-shader->getStartCenter().fX,
923*c8dee2aaSAndroid Build Coastguard Worker                                            -shader->getStartCenter().fY));
924*c8dee2aaSAndroid Build Coastguard Worker             // scale |diffRadius| to 1
925*c8dee2aaSAndroid Build Coastguard Worker             matrix->postScale(1 / dr, 1 / dr);
926*c8dee2aaSAndroid Build Coastguard Worker         } break;
927*c8dee2aaSAndroid Build Coastguard Worker 
928*c8dee2aaSAndroid Build Coastguard Worker         case SkConicalGradient::Type::kFocal: {
929*c8dee2aaSAndroid Build Coastguard Worker             static const SkRuntimeEffect* kEffect =
930*c8dee2aaSAndroid Build Coastguard Worker                 SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
931*c8dee2aaSAndroid Build Coastguard Worker                         // Optimization flags, all specialized:
932*c8dee2aaSAndroid Build Coastguard Worker                         "uniform int isRadiusIncreasing;"
933*c8dee2aaSAndroid Build Coastguard Worker                         "uniform int isFocalOnCircle;"
934*c8dee2aaSAndroid Build Coastguard Worker                         "uniform int isWellBehaved;"
935*c8dee2aaSAndroid Build Coastguard Worker                         "uniform int isSwapped;"
936*c8dee2aaSAndroid Build Coastguard Worker                         "uniform int isNativelyFocal;"
937*c8dee2aaSAndroid Build Coastguard Worker 
938*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half invR1;"  // 1/r1
939*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half fx;"     // focalX = r0/(r0-r1)
940*c8dee2aaSAndroid Build Coastguard Worker 
941*c8dee2aaSAndroid Build Coastguard Worker                         "half4 main(float2 p) {"
942*c8dee2aaSAndroid Build Coastguard Worker                             "float t = -1;"
943*c8dee2aaSAndroid Build Coastguard Worker                             "half v = 1;" // validation flag,set to negative to discard fragment later
944*c8dee2aaSAndroid Build Coastguard Worker 
945*c8dee2aaSAndroid Build Coastguard Worker                             "float x_t = -1;"
946*c8dee2aaSAndroid Build Coastguard Worker                             "if (bool(isFocalOnCircle)) {"
947*c8dee2aaSAndroid Build Coastguard Worker                                 "x_t = dot(p, p) / p.x;"
948*c8dee2aaSAndroid Build Coastguard Worker                             "} else if (bool(isWellBehaved)) {"
949*c8dee2aaSAndroid Build Coastguard Worker                                 "x_t = length(p) - p.x * invR1;"
950*c8dee2aaSAndroid Build Coastguard Worker                             "} else {"
951*c8dee2aaSAndroid Build Coastguard Worker                                 "float temp = p.x * p.x - p.y * p.y;"
952*c8dee2aaSAndroid Build Coastguard Worker 
953*c8dee2aaSAndroid Build Coastguard Worker                                 // Only do sqrt if temp >= 0; this is significantly slower than
954*c8dee2aaSAndroid Build Coastguard Worker                                 // checking temp >= 0 in the if statement that checks r(t) >= 0.
955*c8dee2aaSAndroid Build Coastguard Worker                                 // But GPU may break if we sqrt a negative float. (Although I
956*c8dee2aaSAndroid Build Coastguard Worker                                 // haven't observed that on any devices so far, and the old
957*c8dee2aaSAndroid Build Coastguard Worker                                 // approach also does sqrt negative value without a check.) If
958*c8dee2aaSAndroid Build Coastguard Worker                                 // the performance is really critical, maybe we should just
959*c8dee2aaSAndroid Build Coastguard Worker                                 // compute the area where temp and x_t are always valid and drop
960*c8dee2aaSAndroid Build Coastguard Worker                                 // all these ifs.
961*c8dee2aaSAndroid Build Coastguard Worker                                 "if (temp >= 0) {"
962*c8dee2aaSAndroid Build Coastguard Worker                                     "if (bool(isSwapped) || !bool(isRadiusIncreasing)) {"
963*c8dee2aaSAndroid Build Coastguard Worker                                         "x_t = -sqrt(temp) - p.x * invR1;"
964*c8dee2aaSAndroid Build Coastguard Worker                                     "} else {"
965*c8dee2aaSAndroid Build Coastguard Worker                                         "x_t = sqrt(temp) - p.x * invR1;"
966*c8dee2aaSAndroid Build Coastguard Worker                                     "}"
967*c8dee2aaSAndroid Build Coastguard Worker                                 "}"
968*c8dee2aaSAndroid Build Coastguard Worker                             "}"
969*c8dee2aaSAndroid Build Coastguard Worker 
970*c8dee2aaSAndroid Build Coastguard Worker                             // The final calculation of t from x_t has lots of static
971*c8dee2aaSAndroid Build Coastguard Worker                             // optimizations but only do them when x_t is positive (which
972*c8dee2aaSAndroid Build Coastguard Worker                             // can be assumed true if isWellBehaved is true)
973*c8dee2aaSAndroid Build Coastguard Worker                             "if (!bool(isWellBehaved)) {"
974*c8dee2aaSAndroid Build Coastguard Worker                                 // This will still calculate t even though it will be ignored
975*c8dee2aaSAndroid Build Coastguard Worker                                 // later in the pipeline to avoid a branch
976*c8dee2aaSAndroid Build Coastguard Worker                                 "if (x_t <= 0.0) {"
977*c8dee2aaSAndroid Build Coastguard Worker                                     "v = -1;"
978*c8dee2aaSAndroid Build Coastguard Worker                                 "}"
979*c8dee2aaSAndroid Build Coastguard Worker                             "}"
980*c8dee2aaSAndroid Build Coastguard Worker                             "if (bool(isRadiusIncreasing)) {"
981*c8dee2aaSAndroid Build Coastguard Worker                                 "if (bool(isNativelyFocal)) {"
982*c8dee2aaSAndroid Build Coastguard Worker                                     "t = x_t;"
983*c8dee2aaSAndroid Build Coastguard Worker                                 "} else {"
984*c8dee2aaSAndroid Build Coastguard Worker                                     "t = x_t + fx;"
985*c8dee2aaSAndroid Build Coastguard Worker                                 "}"
986*c8dee2aaSAndroid Build Coastguard Worker                             "} else {"
987*c8dee2aaSAndroid Build Coastguard Worker                                 "if (bool(isNativelyFocal)) {"
988*c8dee2aaSAndroid Build Coastguard Worker                                     "t = -x_t;"
989*c8dee2aaSAndroid Build Coastguard Worker                                 "} else {"
990*c8dee2aaSAndroid Build Coastguard Worker                                     "t = -x_t + fx;"
991*c8dee2aaSAndroid Build Coastguard Worker                                 "}"
992*c8dee2aaSAndroid Build Coastguard Worker                             "}"
993*c8dee2aaSAndroid Build Coastguard Worker 
994*c8dee2aaSAndroid Build Coastguard Worker                             "if (bool(isSwapped)) {"
995*c8dee2aaSAndroid Build Coastguard Worker                                 "t = 1 - t;"
996*c8dee2aaSAndroid Build Coastguard Worker                             "}"
997*c8dee2aaSAndroid Build Coastguard Worker 
998*c8dee2aaSAndroid Build Coastguard Worker                             "return half4(half(t), v, 0, 0);"
999*c8dee2aaSAndroid Build Coastguard Worker                         "}"
1000*c8dee2aaSAndroid Build Coastguard Worker                     );
1001*c8dee2aaSAndroid Build Coastguard Worker 
1002*c8dee2aaSAndroid Build Coastguard Worker             const SkConicalGradient::FocalData& focalData = shader->getFocalData();
1003*c8dee2aaSAndroid Build Coastguard Worker             bool isRadiusIncreasing = (1 - focalData.fFocalX) > 0,
1004*c8dee2aaSAndroid Build Coastguard Worker                  isFocalOnCircle = focalData.isFocalOnCircle(),
1005*c8dee2aaSAndroid Build Coastguard Worker                  isWellBehaved = focalData.isWellBehaved(), isSwapped = focalData.isSwapped(),
1006*c8dee2aaSAndroid Build Coastguard Worker                  isNativelyFocal = focalData.isNativelyFocal();
1007*c8dee2aaSAndroid Build Coastguard Worker 
1008*c8dee2aaSAndroid Build Coastguard Worker             fp = GrSkSLFP::Make(kEffect, "TwoPointConicalFocalLayout", /*inputFP=*/nullptr,
1009*c8dee2aaSAndroid Build Coastguard Worker                                 GrSkSLFP::OptFlags::kNone,
1010*c8dee2aaSAndroid Build Coastguard Worker                                 "isRadiusIncreasing", GrSkSLFP::Specialize<int>(isRadiusIncreasing),
1011*c8dee2aaSAndroid Build Coastguard Worker                                 "isFocalOnCircle",    GrSkSLFP::Specialize<int>(isFocalOnCircle),
1012*c8dee2aaSAndroid Build Coastguard Worker                                 "isWellBehaved",      GrSkSLFP::Specialize<int>(isWellBehaved),
1013*c8dee2aaSAndroid Build Coastguard Worker                                 "isSwapped",          GrSkSLFP::Specialize<int>(isSwapped),
1014*c8dee2aaSAndroid Build Coastguard Worker                                 "isNativelyFocal",    GrSkSLFP::Specialize<int>(isNativelyFocal),
1015*c8dee2aaSAndroid Build Coastguard Worker                                 "invR1",              1.0f / focalData.fR1,
1016*c8dee2aaSAndroid Build Coastguard Worker                                 "fx",                 focalData.fFocalX);
1017*c8dee2aaSAndroid Build Coastguard Worker         } break;
1018*c8dee2aaSAndroid Build Coastguard Worker     }
1019*c8dee2aaSAndroid Build Coastguard Worker     return GrGradientShader::MakeGradientFP(
1020*c8dee2aaSAndroid Build Coastguard Worker             *shader, args, mRec, std::move(fp), matrix.getMaybeNull());
1021*c8dee2aaSAndroid Build Coastguard Worker }
1022*c8dee2aaSAndroid Build Coastguard Worker 
make_gradient_fp(const SkLinearGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1023*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkLinearGradient* shader,
1024*c8dee2aaSAndroid Build Coastguard Worker                                                              const GrFPArgs& args,
1025*c8dee2aaSAndroid Build Coastguard Worker                                                              const SkShaders::MatrixRec& mRec) {
1026*c8dee2aaSAndroid Build Coastguard Worker     return GrGradientShader::MakeLinear(*shader, args, mRec);
1027*c8dee2aaSAndroid Build Coastguard Worker }
1028*c8dee2aaSAndroid Build Coastguard Worker 
make_gradient_fp(const SkRadialGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1029*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkRadialGradient* shader,
1030*c8dee2aaSAndroid Build Coastguard Worker                                                              const GrFPArgs& args,
1031*c8dee2aaSAndroid Build Coastguard Worker                                                              const SkShaders::MatrixRec& mRec) {
1032*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(
1033*c8dee2aaSAndroid Build Coastguard Worker             SkRuntimeEffect::MakeForShader,
1034*c8dee2aaSAndroid Build Coastguard Worker             "float4 main(float2 coord) {"
1035*c8dee2aaSAndroid Build Coastguard Worker                 "return float4(length(coord), 1, 0, 0);"  // y = 1 for always valid
1036*c8dee2aaSAndroid Build Coastguard Worker             "}");
1037*c8dee2aaSAndroid Build Coastguard Worker     // The radial gradient never rejects a pixel so it doesn't change opacity
1038*c8dee2aaSAndroid Build Coastguard Worker     auto fp = GrSkSLFP::Make(
1039*c8dee2aaSAndroid Build Coastguard Worker             effect, "RadialLayout", /*inputFP=*/nullptr, GrSkSLFP::OptFlags::kPreservesOpaqueInput);
1040*c8dee2aaSAndroid Build Coastguard Worker     return GrGradientShader::MakeGradientFP(*shader, args, mRec, std::move(fp));
1041*c8dee2aaSAndroid Build Coastguard Worker }
1042*c8dee2aaSAndroid Build Coastguard Worker 
make_gradient_fp(const SkSweepGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1043*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkSweepGradient* shader,
1044*c8dee2aaSAndroid Build Coastguard Worker                                                              const GrFPArgs& args,
1045*c8dee2aaSAndroid Build Coastguard Worker                                                              const SkShaders::MatrixRec& mRec) {
1046*c8dee2aaSAndroid Build Coastguard Worker     // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is
1047*c8dee2aaSAndroid Build Coastguard Worker     // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in (sqrt(x^2
1048*c8dee2aaSAndroid Build Coastguard Worker     // + y^2) + x) as the second parameter to atan2 in these cases. We let the device handle the
1049*c8dee2aaSAndroid Build Coastguard Worker     // undefined behavior of the second paramenter being 0 instead of doing the divide ourselves and
1050*c8dee2aaSAndroid Build Coastguard Worker     // using atan instead.
1051*c8dee2aaSAndroid Build Coastguard Worker     int useAtanWorkaround =
1052*c8dee2aaSAndroid Build Coastguard Worker             args.fContext->priv().caps()->shaderCaps()->fAtan2ImplementedAsAtanYOverX;
1053*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
1054*c8dee2aaSAndroid Build Coastguard Worker         "uniform half bias;"
1055*c8dee2aaSAndroid Build Coastguard Worker         "uniform half scale;"
1056*c8dee2aaSAndroid Build Coastguard Worker         "uniform int useAtanWorkaround;"  // specialized
1057*c8dee2aaSAndroid Build Coastguard Worker 
1058*c8dee2aaSAndroid Build Coastguard Worker         "half4 main(float2 coord) {"
1059*c8dee2aaSAndroid Build Coastguard Worker             "half angle;"
1060*c8dee2aaSAndroid Build Coastguard Worker             "if (bool(useAtanWorkaround)) {"
1061*c8dee2aaSAndroid Build Coastguard Worker                 "angle = half(2 * atan(-coord.y, length(coord) - coord.x));"
1062*c8dee2aaSAndroid Build Coastguard Worker             "} else {"
1063*c8dee2aaSAndroid Build Coastguard Worker                 // Hardcode pi/2 for the angle when x == 0, to avoid undefined behavior in this
1064*c8dee2aaSAndroid Build Coastguard Worker                 // case. This hasn't proven to be necessary in the atan workaround case.
1065*c8dee2aaSAndroid Build Coastguard Worker                 "angle = (coord.x != 0) ? half(atan(-coord.y, -coord.x)) :"
1066*c8dee2aaSAndroid Build Coastguard Worker                                         " sign(coord.y) * -1.5707963267949;"
1067*c8dee2aaSAndroid Build Coastguard Worker             "}"
1068*c8dee2aaSAndroid Build Coastguard Worker 
1069*c8dee2aaSAndroid Build Coastguard Worker             // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
1070*c8dee2aaSAndroid Build Coastguard Worker             "half t = (angle * 0.1591549430918 + 0.5 + bias) * scale;"
1071*c8dee2aaSAndroid Build Coastguard Worker             "return half4(t, 1, 0, 0);" // y = 1 for always valid
1072*c8dee2aaSAndroid Build Coastguard Worker         "}"
1073*c8dee2aaSAndroid Build Coastguard Worker     );
1074*c8dee2aaSAndroid Build Coastguard Worker 
1075*c8dee2aaSAndroid Build Coastguard Worker     // The sweep gradient never rejects a pixel so it doesn't change opacity
1076*c8dee2aaSAndroid Build Coastguard Worker     auto fp = GrSkSLFP::Make(effect, "SweepLayout", /*inputFP=*/nullptr,
1077*c8dee2aaSAndroid Build Coastguard Worker                              GrSkSLFP::OptFlags::kPreservesOpaqueInput,
1078*c8dee2aaSAndroid Build Coastguard Worker                              "bias", shader->tBias(),
1079*c8dee2aaSAndroid Build Coastguard Worker                              "scale", shader->tScale(),
1080*c8dee2aaSAndroid Build Coastguard Worker                              "useAtanWorkaround", GrSkSLFP::Specialize(useAtanWorkaround));
1081*c8dee2aaSAndroid Build Coastguard Worker     return GrGradientShader::MakeGradientFP(*shader, args, mRec, std::move(fp));
1082*c8dee2aaSAndroid Build Coastguard Worker }
1083*c8dee2aaSAndroid Build Coastguard Worker 
make_shader_fp(const SkGradientBaseShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1084*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkGradientBaseShader* shader,
1085*c8dee2aaSAndroid Build Coastguard Worker                                                            const GrFPArgs& args,
1086*c8dee2aaSAndroid Build Coastguard Worker                                                            const SkShaders::MatrixRec& mRec) {
1087*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(shader);
1088*c8dee2aaSAndroid Build Coastguard Worker 
1089*c8dee2aaSAndroid Build Coastguard Worker     switch (shader->asGradient()) {
1090*c8dee2aaSAndroid Build Coastguard Worker #define M(type)                               \
1091*c8dee2aaSAndroid Build Coastguard Worker     case SkShaderBase::GradientType::k##type: \
1092*c8dee2aaSAndroid Build Coastguard Worker         return make_gradient_fp(static_cast<const Sk##type##Gradient*>(shader), args, mRec);
1093*c8dee2aaSAndroid Build Coastguard Worker         SK_ALL_GRADIENTS(M)
1094*c8dee2aaSAndroid Build Coastguard Worker #undef M
1095*c8dee2aaSAndroid Build Coastguard Worker         case SkShaderBase::GradientType::kNone:
1096*c8dee2aaSAndroid Build Coastguard Worker             SkDEBUGFAIL("Gradient shader says its type is none");
1097*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
1098*c8dee2aaSAndroid Build Coastguard Worker     }
1099*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
1100*c8dee2aaSAndroid Build Coastguard Worker }
1101*c8dee2aaSAndroid Build Coastguard Worker 
Make(const SkShader * shader,const GrFPArgs & args,const SkMatrix & ctm)1102*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> Make(const SkShader* shader,
1103*c8dee2aaSAndroid Build Coastguard Worker                                           const GrFPArgs& args,
1104*c8dee2aaSAndroid Build Coastguard Worker                                           const SkMatrix& ctm) {
1105*c8dee2aaSAndroid Build Coastguard Worker     return Make(shader, args, SkShaders::MatrixRec(ctm));
1106*c8dee2aaSAndroid Build Coastguard Worker }
1107*c8dee2aaSAndroid Build Coastguard Worker 
Make(const SkShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1108*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> Make(const SkShader* shader,
1109*c8dee2aaSAndroid Build Coastguard Worker                                           const GrFPArgs& args,
1110*c8dee2aaSAndroid Build Coastguard Worker                                           const SkShaders::MatrixRec& mRec) {
1111*c8dee2aaSAndroid Build Coastguard Worker     if (!shader) {
1112*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
1113*c8dee2aaSAndroid Build Coastguard Worker     }
1114*c8dee2aaSAndroid Build Coastguard Worker     auto base = as_SB(shader);
1115*c8dee2aaSAndroid Build Coastguard Worker     switch (base->type()) {
1116*c8dee2aaSAndroid Build Coastguard Worker #define M(type)                             \
1117*c8dee2aaSAndroid Build Coastguard Worker     case SkShaderBase::ShaderType::k##type: \
1118*c8dee2aaSAndroid Build Coastguard Worker         return make_shader_fp(static_cast<const Sk##type##Shader*>(base), args, mRec);
1119*c8dee2aaSAndroid Build Coastguard Worker         SK_ALL_SHADERS(M)
1120*c8dee2aaSAndroid Build Coastguard Worker #undef M
1121*c8dee2aaSAndroid Build Coastguard Worker     }
1122*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
1123*c8dee2aaSAndroid Build Coastguard Worker }
1124*c8dee2aaSAndroid Build Coastguard Worker 
1125*c8dee2aaSAndroid Build Coastguard Worker }  // namespace GrFragmentProcessors
1126