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