• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrRecordingContext.h"
28 #include "include/gpu/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(std::move(inputFP),
402                                                                 filter->matrix(),
403                                                                 /* unpremulInput = */ true,
404                                                                 /* clampRGBOutput = */ true,
405                                                                 /* premulOutput = */ true));
406 
407         case SkMatrixColorFilter::Domain::kHSLA: {
408             auto fp = rgb_to_hsl(std::move(inputFP));
409             fp = GrFragmentProcessor::ColorMatrix(std::move(fp),
410                                                   filter->matrix(),
411                                                   /* unpremulInput = */ false,
412                                                   /* clampRGBOutput = */ false,
413                                                   /* premulOutput = */ false);
414             return GrFPSuccess(hsl_to_rgb(std::move(fp)));
415         }
416     }
417     SkUNREACHABLE;
418 }
419 
make_colorfilter_fp(GrRecordingContext * context,const SkRuntimeColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & colorInfo,const SkSurfaceProps & props)420 static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
421                                       const SkRuntimeColorFilter* filter,
422                                       std::unique_ptr<GrFragmentProcessor> inputFP,
423                                       const GrColorInfo& colorInfo,
424                                       const SkSurfaceProps& props) {
425     sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
426             filter->effect()->uniforms(), filter->uniforms(), colorInfo.colorSpace());
427     SkASSERT(uniforms);
428 
429     GrFPArgs childArgs(context, &colorInfo, props, GrFPArgs::Scope::kRuntimeEffect);
430     return make_effect_fp(filter->effect(),
431                           "runtime_color_filter",
432                           std::move(uniforms),
433                           std::move(inputFP),
434                           /*destColorFP=*/nullptr,
435                           filter->children(),
436                           childArgs);
437 }
438 
make_colorfilter_fp(GrRecordingContext * context,const SkTableColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo &,const SkSurfaceProps &)439 static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
440                                       const SkTableColorFilter* filter,
441                                       std::unique_ptr<GrFragmentProcessor> inputFP,
442                                       const GrColorInfo&,
443                                       const SkSurfaceProps&) {
444     auto cte = ColorTableEffect::Make(std::move(inputFP), context, filter->bitmap());
445     return cte ? GrFPSuccess(std::move(cte)) : GrFPFailure(nullptr);
446 }
447 
make_colorfilter_fp(GrRecordingContext * context,const SkWorkingFormatColorFilter * filter,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & dstColorInfo,const SkSurfaceProps & props)448 static GrFPResult make_colorfilter_fp(GrRecordingContext* context,
449                                       const SkWorkingFormatColorFilter* filter,
450                                       std::unique_ptr<GrFragmentProcessor> inputFP,
451                                       const GrColorInfo& dstColorInfo,
452                                       const SkSurfaceProps& props) {
453     sk_sp<SkColorSpace> dstCS = dstColorInfo.refColorSpace();
454     if (!dstCS) {
455         dstCS = SkColorSpace::MakeSRGB();
456     }
457 
458     SkAlphaType workingAT;
459     sk_sp<SkColorSpace> workingCS = filter->workingFormat(dstCS, &workingAT);
460 
461     GrColorInfo dst = {dstColorInfo.colorType(), dstColorInfo.alphaType(), dstCS},
462                 working = {dstColorInfo.colorType(), workingAT, workingCS};
463 
464     auto [ok, fp] = Make(context,
465                          filter->child().get(),
466                          GrColorSpaceXformEffect::Make(std::move(inputFP), dst, working),
467                          working,
468                          props);
469 
470     return ok ? GrFPSuccess(GrColorSpaceXformEffect::Make(std::move(fp), working, dst))
471               : GrFPFailure(std::move(fp));
472 }
473 
Make(GrRecordingContext * ctx,const SkColorFilter * cf,std::unique_ptr<GrFragmentProcessor> inputFP,const GrColorInfo & dstColorInfo,const SkSurfaceProps & props)474 GrFPResult Make(GrRecordingContext* ctx,
475                 const SkColorFilter* cf,
476                 std::unique_ptr<GrFragmentProcessor> inputFP,
477                 const GrColorInfo& dstColorInfo,
478                 const SkSurfaceProps& props) {
479     if (!cf) {
480         return GrFPFailure(nullptr);
481     }
482     auto cfb = as_CFB(cf);
483     switch (cfb->type()) {
484         case SkColorFilterBase::Type::kNoop:
485             return GrFPFailure(nullptr);
486 #define M(type)                                                                   \
487     case SkColorFilterBase::Type::k##type:                                        \
488         return make_colorfilter_fp(ctx,                                           \
489                                    static_cast<const Sk##type##ColorFilter*>(cf), \
490                                    std::move(inputFP),                            \
491                                    dstColorInfo,                                  \
492                                    props);
493             SK_ALL_COLOR_FILTERS(M)
494 #undef M
495     }
496     SkUNREACHABLE;
497 }
498 
make_shader_fp(const SkBlendShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)499 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkBlendShader* shader,
500                                                            const GrFPArgs& args,
501                                                            const SkShaders::MatrixRec& mRec) {
502     auto fpA = Make(shader->dst().get(), args, mRec);
503     auto fpB = Make(shader->src().get(), args, mRec);
504     if (!fpA || !fpB) {
505         // This is unexpected. Both src and dst shaders should be valid. Just fail.
506         return nullptr;
507     }
508     return GrBlendFragmentProcessor::Make(std::move(fpB), std::move(fpA), shader->mode());
509 }
510 
make_shader_fp(const SkColorFilterShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)511 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkColorFilterShader* shader,
512                                                            const GrFPArgs& args,
513                                                            const SkShaders::MatrixRec& mRec) {
514     auto shaderFP = Make(shader->shader().get(), args, mRec);
515     if (!shaderFP) {
516         return nullptr;
517     }
518 
519     // TODO I guess, but it shouldn't come up as used today.
520     SkASSERT(shader->alpha() == 1.0f);
521 
522     auto [success, fp] = Make(args.fContext,
523                               shader->filter().get(),
524                               std::move(shaderFP),
525                               *args.fDstColorInfo,
526                               args.fSurfaceProps);
527     // If the filter FP could not be created, we still want to return the shader FP, so checking
528     // success can be omitted here.
529     return std::move(fp);
530 }
531 
make_shader_fp(const SkColorShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)532 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkColorShader* shader,
533                                                            const GrFPArgs& args,
534                                                            const SkShaders::MatrixRec& mRec) {
535     return GrFragmentProcessor::MakeColor(SkColorToPMColor4f(shader->color(), *args.fDstColorInfo));
536 }
537 
make_shader_fp(const SkColor4Shader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)538 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkColor4Shader* shader,
539                                                            const GrFPArgs& args,
540                                                            const SkShaders::MatrixRec& mRec) {
541     SkColorSpaceXformSteps steps{shader->colorSpace().get(),
542                                  kUnpremul_SkAlphaType,
543                                  args.fDstColorInfo->colorSpace(),
544                                  kUnpremul_SkAlphaType};
545     SkColor4f color = shader->color();
546     steps.apply(color.vec());
547     return GrFragmentProcessor::MakeColor(color.premul());
548 }
549 
make_shader_fp(const SkCoordClampShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)550 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkCoordClampShader* shader,
551                                                            const GrFPArgs& args,
552                                                            const SkShaders::MatrixRec& mRec) {
553     static const SkRuntimeEffect* effect =
554             SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
555                                 "uniform shader c;"
556                                 "uniform float4 s;"
557                                 "half4 main(float2 p) {"
558                                     "return c.eval(clamp(p, s.LT, s.RB));"
559                                 "}");
560 
561     auto fp = Make(shader->shader().get(), args, mRec.applied());
562     if (!fp) {
563         return nullptr;
564     }
565 
566     GrSkSLFP::OptFlags flags = GrSkSLFP::OptFlags::kNone;
567     if (fp->compatibleWithCoverageAsAlpha()) {
568         flags |= GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha;
569     }
570     if (fp->preservesOpaqueInput()) {
571         flags |= GrSkSLFP::OptFlags::kPreservesOpaqueInput;
572     }
573     fp = GrSkSLFP::Make(effect,
574                         "clamp_fp",
575                         /*inputFP=*/nullptr,
576                         flags,
577                         "c",
578                         std::move(fp),
579                         "s",
580                         shader->subset());
581 
582     auto [total, ok] = mRec.applyForFragmentProcessor({});
583     if (!ok) {
584         return nullptr;
585     }
586     return GrMatrixEffect::Make(total, std::move(fp));
587 }
588 
make_shader_fp(const SkCTMShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)589 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkCTMShader* shader,
590                                                            const GrFPArgs& args,
591                                                            const SkShaders::MatrixRec& mRec) {
592     SkMatrix ctmInv;
593     if (!shader->ctm().invert(&ctmInv)) {
594         return nullptr;
595     }
596 
597     auto base = Make(shader->proxyShader().get(), args, shader->ctm());
598     if (!base) {
599         return nullptr;
600     }
601 
602     // In order for the shader to be evaluated with the original CTM, we explicitly evaluate it
603     // at sk_FragCoord, and pass that through the inverse of the original CTM. This avoids requiring
604     // local coords for the shader and mapping from the draw's local to device and then back.
605     return GrFragmentProcessor::DeviceSpace(GrMatrixEffect::Make(ctmInv, std::move(base)));
606 }
607 
make_shader_fp(const SkEmptyShader * shader,const GrFPArgs &,const SkShaders::MatrixRec &)608 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkEmptyShader* shader,
609                                                            const GrFPArgs&,
610                                                            const SkShaders::MatrixRec&) {
611     return nullptr;
612 }
613 
needs_subset(sk_sp<const SkImage> img,const SkRect & subset)614 static bool needs_subset(sk_sp<const SkImage> img, const SkRect& subset) {
615     return subset != SkRect::Make(img->dimensions());
616 }
617 
make_shader_fp(const SkImageShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)618 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkImageShader* shader,
619                                                            const GrFPArgs& args,
620                                                            const SkShaders::MatrixRec& mRec) {
621     SkTileMode tileModes[2] = {shader->tileModeX(), shader->tileModeY()};
622     const SkRect shaderSubset = shader->subset();
623     const SkRect* subset = needs_subset(shader->image(), shaderSubset) ? &shaderSubset : nullptr;
624     auto fp = skgpu::ganesh::AsFragmentProcessor(
625             args.fContext, shader->image(), shader->sampling(), tileModes, SkMatrix::I(), subset);
626     if (!fp) {
627         return nullptr;
628     }
629 
630     auto [total, ok] = mRec.applyForFragmentProcessor({});
631     if (!ok) {
632         return nullptr;
633     }
634     fp = GrMatrixEffect::Make(total, std::move(fp));
635 
636     if (!shader->isRaw()) {
637         fp = GrColorSpaceXformEffect::Make(std::move(fp),
638                                            shader->image()->colorSpace(),
639                                            shader->image()->alphaType(),
640                                            args.fDstColorInfo->colorSpace(),
641                                            kPremul_SkAlphaType);
642 
643         // Alpha-only image shaders are tinted by the input color (typically the paint color).
644         // We suppress that behavior when sampled from a runtime effect.
645         if (shader->image()->isAlphaOnly() && args.fScope != GrFPArgs::Scope::kRuntimeEffect) {
646             fp = GrBlendFragmentProcessor::Make<SkBlendMode::kDstIn>(std::move(fp), nullptr);
647         }
648     }
649 
650     return fp;
651 }
652 
make_shader_fp(const SkLocalMatrixShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)653 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkLocalMatrixShader* shader,
654                                                            const GrFPArgs& args,
655                                                            const SkShaders::MatrixRec& mRec) {
656     return Make(shader->wrappedShader().get(), args, mRec.concat(shader->localMatrix()));
657 }
658 
make_shader_fp(const SkPerlinNoiseShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)659 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkPerlinNoiseShader* shader,
660                                                            const GrFPArgs& args,
661                                                            const SkShaders::MatrixRec& mRec) {
662     SkASSERT(args.fContext);
663     SkASSERT(shader->numOctaves());
664 
665     // Either we don't stitch tiles, or we have a valid tile size
666     SkASSERT(!shader->stitchTiles() || !shader->tileSize().isEmpty());
667 
668     auto paintingData = shader->getPaintingData();
669     paintingData->generateBitmaps();
670 
671     GrRecordingContext* context = args.fContext;
672 
673     const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
674     const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
675 
676     auto permutationsView = std::get<0>(GrMakeCachedBitmapProxyView(
677             context,
678             permutationsBitmap,
679             /*label=*/"PerlinNoiseShader_FragmentProcessor_PermutationsView"));
680 
681     auto noiseView = std::get<0>(GrMakeCachedBitmapProxyView(
682             context, noiseBitmap, /*label=*/"PerlinNoiseShader_FragmentProcessor_NoiseView"));
683 
684     if (!permutationsView || !noiseView) {
685         return nullptr;
686     }
687 
688     std::unique_ptr<GrFragmentProcessor> fp =
689             GrPerlinNoise2Effect::Make(shader->noiseType(),
690                                        shader->numOctaves(),
691                                        shader->stitchTiles(),
692                                        std::move(paintingData),
693                                        std::move(permutationsView),
694                                        std::move(noiseView),
695                                        *context->priv().caps());
696     if (!fp) {
697         return nullptr;
698     }
699     auto [total, ok] = mRec.applyForFragmentProcessor({});
700     if (!ok) {
701         return nullptr;
702     }
703     return GrMatrixEffect::Make(total, std::move(fp));
704 }
705 
make_shader_fp(const SkPictureShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)706 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkPictureShader* shader,
707                                                            const GrFPArgs& args,
708                                                            const SkShaders::MatrixRec& mRec) {
709     auto ctx = args.fContext;
710     SkColorType dstColorType = GrColorTypeToSkColorType(args.fDstColorInfo->colorType());
711     if (dstColorType == kUnknown_SkColorType) {
712         dstColorType = kRGBA_8888_SkColorType;
713     }
714     sk_sp<SkColorSpace> dstCS = SkColorSpace::MakeSRGB();
715     if (args.fDstColorInfo->colorSpace()) {
716         dstCS = sk_ref_sp(args.fDstColorInfo->colorSpace());
717     }
718 
719     auto info = SkPictureShader::CachedImageInfo::Make(shader->tile(),
720                                                        mRec.totalMatrix(),
721                                                        dstColorType,
722                                                        dstCS.get(),
723                                                        ctx->priv().caps()->maxTextureSize(),
724                                                        args.fSurfaceProps);
725     if (!info.success) {
726         return nullptr;
727     }
728 
729     // Gotta be sure the GPU can support our requested colortype (might be FP16)
730     if (!ctx->colorTypeSupportedAsSurface(info.imageInfo.colorType())) {
731         info.imageInfo = info.imageInfo.makeColorType(kRGBA_8888_SkColorType);
732     }
733 
734     static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain();
735     skgpu::UniqueKey key;
736     std::tuple keyData = {dstCS->toXYZD50Hash(),
737                           dstCS->transferFnHash(),
738                           static_cast<uint32_t>(dstColorType),
739                           shader->picture()->uniqueID(),
740                           shader->tile(),
741                           info.tileScale,
742                           info.props};
743     skgpu::UniqueKey::Builder builder(
744             &key, kDomain, sizeof(keyData) / sizeof(uint32_t), "Picture Shader Image");
745     memcpy(&builder[0], &keyData, sizeof(keyData));
746     builder.finish();
747 
748     GrProxyProvider* provider = ctx->priv().proxyProvider();
749     GrSurfaceProxyView view;
750     if (auto proxy = provider->findOrCreateProxyByUniqueKey(key)) {
751         view = GrSurfaceProxyView(proxy, kTopLeft_GrSurfaceOrigin, skgpu::Swizzle());
752     } else {
753         const int msaaSampleCount = 0;
754         const bool createWithMips = false;
755         const bool kUnprotected = false;
756         auto image = info.makeImage(SkSurfaces::RenderTarget(ctx,
757                                                              skgpu::Budgeted::kYes,
758                                                              info.imageInfo,
759                                                              msaaSampleCount,
760                                                              kTopLeft_GrSurfaceOrigin,
761                                                              &info.props,
762                                                              createWithMips,
763                                                              kUnprotected),
764                                     shader->picture().get());
765         if (!image) {
766             return nullptr;
767         }
768 
769         auto [v, ct] = skgpu::ganesh::AsView(ctx, image, skgpu::Mipmapped::kNo);
770         view = std::move(v);
771         provider->assignUniqueKeyToProxy(key, view.asTextureProxy());
772     }
773 
774     const GrSamplerState sampler(static_cast<GrSamplerState::WrapMode>(shader->tileModeX()),
775                                  static_cast<GrSamplerState::WrapMode>(shader->tileModeY()),
776                                  shader->filter());
777     auto fp = GrTextureEffect::Make(
778             std::move(view), kPremul_SkAlphaType, SkMatrix::I(), sampler, *ctx->priv().caps());
779     SkMatrix scale = SkMatrix::Scale(info.tileScale.width(), info.tileScale.height());
780     auto [total, ok] = mRec.applyForFragmentProcessor(scale);
781     if (!ok) {
782         return nullptr;
783     }
784     return GrMatrixEffect::Make(total, std::move(fp));
785 }
786 
make_shader_fp(const SkRuntimeShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)787 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkRuntimeShader* shader,
788                                                            const GrFPArgs& args,
789                                                            const SkShaders::MatrixRec& mRec) {
790     if (!SkRuntimeEffectPriv::CanDraw(args.fContext->priv().caps(), shader->asRuntimeEffect())) {
791         return nullptr;
792     }
793 
794     sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
795             shader->asRuntimeEffect()->uniforms(),
796             shader->uniformData(args.fDstColorInfo->colorSpace()),
797             args.fDstColorInfo->colorSpace());
798     SkASSERT(uniforms);
799 
800     bool success;
801     std::unique_ptr<GrFragmentProcessor> fp;
802     GrFPArgs childArgs(
803             args.fContext, args.fDstColorInfo, args.fSurfaceProps, GrFPArgs::Scope::kRuntimeEffect);
804     std::tie(success, fp) = make_effect_fp(shader->effect(),
805                                            "runtime_shader",
806                                            std::move(uniforms),
807                                            /*inputFP=*/nullptr,
808                                            /*destColorFP=*/nullptr,
809                                            shader->children(),
810                                            childArgs);
811     if (!success) {
812         return nullptr;
813     }
814 
815     auto [total, ok] = mRec.applyForFragmentProcessor({});
816     if (!ok) {
817         return nullptr;
818     }
819     return GrMatrixEffect::Make(total, std::move(fp));
820 }
821 
make_shader_fp(const SkTransformShader * shader,const GrFPArgs &,const SkShaders::MatrixRec &)822 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkTransformShader* shader,
823                                                            const GrFPArgs&,
824                                                            const SkShaders::MatrixRec&) {
825     return nullptr;
826 }
827 
make_shader_fp(const SkTriColorShader * shader,const GrFPArgs &,const SkShaders::MatrixRec &)828 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkTriColorShader* shader,
829                                                            const GrFPArgs&,
830                                                            const SkShaders::MatrixRec&) {
831     return nullptr;
832 }
833 
make_shader_fp(const SkWorkingColorSpaceShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)834 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkWorkingColorSpaceShader* shader,
835                                                            const GrFPArgs& args,
836                                                            const SkShaders::MatrixRec& mRec) {
837     const GrColorInfo* dstInfo = args.fDstColorInfo;
838     sk_sp<SkColorSpace> dstCS = dstInfo->refColorSpace();
839     if (!dstCS) {
840         dstCS = SkColorSpace::MakeSRGB();
841     }
842 
843     GrColorInfo dst     = {dstInfo->colorType(), dstInfo->alphaType(), dstCS},
844                 working = {dstInfo->colorType(), dstInfo->alphaType(), shader->workingSpace()};
845     GrFPArgs workingArgs(args.fContext, &working, args.fSurfaceProps, args.fScope);
846 
847     auto childFP = Make(shader->shader().get(), workingArgs, mRec);
848     if (!childFP) {
849         return nullptr;
850     }
851 
852     auto childWithWorkingInput = GrFragmentProcessor::Compose(
853             std::move(childFP), GrColorSpaceXformEffect::Make(nullptr, dst, working));
854 
855     return GrColorSpaceXformEffect::Make(std::move(childWithWorkingInput), working, dst);
856 }
857 
858 //////////////////////////////////////////////////////////////////////////////////////////////
859 
make_gradient_fp(const SkConicalGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)860 static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkConicalGradient* shader,
861                                                              const GrFPArgs& args,
862                                                              const SkShaders::MatrixRec& mRec) {
863     // The 2 point conical gradient can reject a pixel so it does change opacity even if the input
864     // was opaque. Thus, all of these layout FPs disable that optimization.
865     std::unique_ptr<GrFragmentProcessor> fp;
866     SkTLazy<SkMatrix> matrix;
867     switch (shader->getType()) {
868         case SkConicalGradient::Type::kStrip: {
869             static const SkRuntimeEffect* kEffect =
870                 SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
871                         "uniform half r0_2;"
872                         "half4 main(float2 p) {"
873                             // validation flag, set to negative to discard fragment later.
874                             "half v = 1;"
875                             "float t = r0_2 - p.y * p.y;"
876                             "if (t >= 0) {"
877                                 "t = p.x + sqrt(t);"
878                             "} else {"
879                                 "v = -1;"
880                             "}"
881                             "return half4(half(t), v, 0, 0);"
882                         "}"
883                     );
884             float r0 = shader->getStartRadius() / shader->getCenterX1();
885             fp = GrSkSLFP::Make(kEffect,
886                                 "TwoPointConicalStripLayout",
887                                 /*inputFP=*/nullptr,
888                                 GrSkSLFP::OptFlags::kNone,
889                                 "r0_2",
890                                 r0 * r0);
891         } break;
892 
893         case SkConicalGradient::Type::kRadial: {
894             static const SkRuntimeEffect* kEffect =
895                 SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
896                         "uniform half r0;"
897                         "uniform half lengthScale;"
898                         "half4 main(float2 p) {"
899                             // validation flag, set to negative to discard fragment later
900                             "half v = 1;"
901                             "float t = length(p) * lengthScale - r0;"
902                             "return half4(half(t), v, 0, 0);"
903                         "}"
904                     );
905             float dr = shader->getDiffRadius();
906             float r0 = shader->getStartRadius() / dr;
907             bool isRadiusIncreasing = dr >= 0;
908             fp = GrSkSLFP::Make(kEffect,
909                                 "TwoPointConicalRadialLayout",
910                                 /*inputFP=*/nullptr,
911                                 GrSkSLFP::OptFlags::kNone,
912                                 "r0",
913                                 r0,
914                                 "lengthScale",
915                                 isRadiusIncreasing ? 1.0f : -1.0f);
916 
917             // GPU radial matrix is different from the original matrix, since we map the diff radius
918             // to have |dr| = 1, so manually compute the final gradient matrix here.
919 
920             // Map center to (0, 0)
921             matrix.set(SkMatrix::Translate(-shader->getStartCenter().fX,
922                                            -shader->getStartCenter().fY));
923             // scale |diffRadius| to 1
924             matrix->postScale(1 / dr, 1 / dr);
925         } break;
926 
927         case SkConicalGradient::Type::kFocal: {
928             static const SkRuntimeEffect* kEffect =
929                 SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
930                         // Optimization flags, all specialized:
931                         "uniform int isRadiusIncreasing;"
932                         "uniform int isFocalOnCircle;"
933                         "uniform int isWellBehaved;"
934                         "uniform int isSwapped;"
935                         "uniform int isNativelyFocal;"
936 
937                         "uniform half invR1;"  // 1/r1
938                         "uniform half fx;"     // focalX = r0/(r0-r1)
939 
940                         "half4 main(float2 p) {"
941                             "float t = -1;"
942                             "half v = 1;" // validation flag,set to negative to discard fragment later
943 
944                             "float x_t = -1;"
945                             "if (bool(isFocalOnCircle)) {"
946                                 "x_t = dot(p, p) / p.x;"
947                             "} else if (bool(isWellBehaved)) {"
948                                 "x_t = length(p) - p.x * invR1;"
949                             "} else {"
950                                 "float temp = p.x * p.x - p.y * p.y;"
951 
952                                 // Only do sqrt if temp >= 0; this is significantly slower than
953                                 // checking temp >= 0 in the if statement that checks r(t) >= 0.
954                                 // But GPU may break if we sqrt a negative float. (Although I
955                                 // haven't observed that on any devices so far, and the old
956                                 // approach also does sqrt negative value without a check.) If
957                                 // the performance is really critical, maybe we should just
958                                 // compute the area where temp and x_t are always valid and drop
959                                 // all these ifs.
960                                 "if (temp >= 0) {"
961                                     "if (bool(isSwapped) || !bool(isRadiusIncreasing)) {"
962                                         "x_t = -sqrt(temp) - p.x * invR1;"
963                                     "} else {"
964                                         "x_t = sqrt(temp) - p.x * invR1;"
965                                     "}"
966                                 "}"
967                             "}"
968 
969                             // The final calculation of t from x_t has lots of static
970                             // optimizations but only do them when x_t is positive (which
971                             // can be assumed true if isWellBehaved is true)
972                             "if (!bool(isWellBehaved)) {"
973                                 // This will still calculate t even though it will be ignored
974                                 // later in the pipeline to avoid a branch
975                                 "if (x_t <= 0.0) {"
976                                     "v = -1;"
977                                 "}"
978                             "}"
979                             "if (bool(isRadiusIncreasing)) {"
980                                 "if (bool(isNativelyFocal)) {"
981                                     "t = x_t;"
982                                 "} else {"
983                                     "t = x_t + fx;"
984                                 "}"
985                             "} else {"
986                                 "if (bool(isNativelyFocal)) {"
987                                     "t = -x_t;"
988                                 "} else {"
989                                     "t = -x_t + fx;"
990                                 "}"
991                             "}"
992 
993                             "if (bool(isSwapped)) {"
994                                 "t = 1 - t;"
995                             "}"
996 
997                             "return half4(half(t), v, 0, 0);"
998                         "}"
999                     );
1000 
1001             const SkConicalGradient::FocalData& focalData = shader->getFocalData();
1002             bool isRadiusIncreasing = (1 - focalData.fFocalX) > 0,
1003                  isFocalOnCircle = focalData.isFocalOnCircle(),
1004                  isWellBehaved = focalData.isWellBehaved(), isSwapped = focalData.isSwapped(),
1005                  isNativelyFocal = focalData.isNativelyFocal();
1006 
1007             fp = GrSkSLFP::Make(kEffect, "TwoPointConicalFocalLayout", /*inputFP=*/nullptr,
1008                                 GrSkSLFP::OptFlags::kNone,
1009                                 "isRadiusIncreasing", GrSkSLFP::Specialize<int>(isRadiusIncreasing),
1010                                 "isFocalOnCircle",    GrSkSLFP::Specialize<int>(isFocalOnCircle),
1011                                 "isWellBehaved",      GrSkSLFP::Specialize<int>(isWellBehaved),
1012                                 "isSwapped",          GrSkSLFP::Specialize<int>(isSwapped),
1013                                 "isNativelyFocal",    GrSkSLFP::Specialize<int>(isNativelyFocal),
1014                                 "invR1",              1.0f / focalData.fR1,
1015                                 "fx",                 focalData.fFocalX);
1016         } break;
1017     }
1018     return GrGradientShader::MakeGradientFP(
1019             *shader, args, mRec, std::move(fp), matrix.getMaybeNull());
1020 }
1021 
make_gradient_fp(const SkLinearGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1022 static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkLinearGradient* shader,
1023                                                              const GrFPArgs& args,
1024                                                              const SkShaders::MatrixRec& mRec) {
1025     return GrGradientShader::MakeLinear(*shader, args, mRec);
1026 }
1027 
make_gradient_fp(const SkRadialGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1028 static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkRadialGradient* shader,
1029                                                              const GrFPArgs& args,
1030                                                              const SkShaders::MatrixRec& mRec) {
1031     static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(
1032             SkRuntimeEffect::MakeForShader,
1033             "half4 main(float2 coord) {"
1034                 "return half4(half(length(coord)), 1, 0, 0);"  // y = 1 for always valid
1035             "}");
1036     // The radial gradient never rejects a pixel so it doesn't change opacity
1037     auto fp = GrSkSLFP::Make(
1038             effect, "RadialLayout", /*inputFP=*/nullptr, GrSkSLFP::OptFlags::kPreservesOpaqueInput);
1039     return GrGradientShader::MakeGradientFP(*shader, args, mRec, std::move(fp));
1040 }
1041 
make_gradient_fp(const SkSweepGradient * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1042 static std::unique_ptr<GrFragmentProcessor> make_gradient_fp(const SkSweepGradient* shader,
1043                                                              const GrFPArgs& args,
1044                                                              const SkShaders::MatrixRec& mRec) {
1045     // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is
1046     // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in (sqrt(x^2
1047     // + y^2) + x) as the second parameter to atan2 in these cases. We let the device handle the
1048     // undefined behavior of the second paramenter being 0 instead of doing the divide ourselves and
1049     // using atan instead.
1050     int useAtanWorkaround =
1051             args.fContext->priv().caps()->shaderCaps()->fAtan2ImplementedAsAtanYOverX;
1052     static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
1053         "uniform half bias;"
1054         "uniform half scale;"
1055         "uniform int useAtanWorkaround;"  // specialized
1056 
1057         "half4 main(float2 coord) {"
1058             "half angle;"
1059             "if (bool(useAtanWorkaround)) {"
1060                 "angle = half(2 * atan(-coord.y, length(coord) - coord.x));"
1061             "} else {"
1062                 // Hardcode pi/2 for the angle when x == 0, to avoid undefined behavior in this
1063                 // case. This hasn't proven to be necessary in the atan workaround case.
1064                 "angle = (coord.x != 0) ? half(atan(-coord.y, -coord.x)) :"
1065                                         " sign(coord.y) * -1.5707963267949;"
1066             "}"
1067 
1068             // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
1069             "half t = (angle * 0.1591549430918 + 0.5 + bias) * scale;"
1070             "return half4(t, 1, 0, 0);" // y = 1 for always valid
1071         "}"
1072     );
1073 
1074     // The sweep gradient never rejects a pixel so it doesn't change opacity
1075     auto fp = GrSkSLFP::Make(effect, "SweepLayout", /*inputFP=*/nullptr,
1076                              GrSkSLFP::OptFlags::kPreservesOpaqueInput,
1077                              "bias", shader->tBias(),
1078                              "scale", shader->tScale(),
1079                              "useAtanWorkaround", GrSkSLFP::Specialize(useAtanWorkaround));
1080     return GrGradientShader::MakeGradientFP(*shader, args, mRec, std::move(fp));
1081 }
1082 
make_shader_fp(const SkGradientBaseShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1083 static std::unique_ptr<GrFragmentProcessor> make_shader_fp(const SkGradientBaseShader* shader,
1084                                                            const GrFPArgs& args,
1085                                                            const SkShaders::MatrixRec& mRec) {
1086     SkASSERT(shader);
1087 
1088     switch (shader->asGradient()) {
1089 #define M(type)                               \
1090     case SkShaderBase::GradientType::k##type: \
1091         return make_gradient_fp(static_cast<const Sk##type##Gradient*>(shader), args, mRec);
1092         SK_ALL_GRADIENTS(M)
1093 #undef M
1094         case SkShaderBase::GradientType::kNone:
1095             SkDEBUGFAIL("Gradient shader says its type is none");
1096             return nullptr;
1097     }
1098     SkUNREACHABLE;
1099 }
1100 
Make(const SkShader * shader,const GrFPArgs & args,const SkMatrix & ctm)1101 std::unique_ptr<GrFragmentProcessor> Make(const SkShader* shader,
1102                                           const GrFPArgs& args,
1103                                           const SkMatrix& ctm) {
1104     return Make(shader, args, SkShaders::MatrixRec(ctm));
1105 }
1106 
Make(const SkShader * shader,const GrFPArgs & args,const SkShaders::MatrixRec & mRec)1107 std::unique_ptr<GrFragmentProcessor> Make(const SkShader* shader,
1108                                           const GrFPArgs& args,
1109                                           const SkShaders::MatrixRec& mRec) {
1110     if (!shader) {
1111         return nullptr;
1112     }
1113     auto base = as_SB(shader);
1114     switch (base->type()) {
1115 #define M(type)                             \
1116     case SkShaderBase::ShaderType::k##type: \
1117         return make_shader_fp(static_cast<const Sk##type##Shader*>(base), args, mRec);
1118         SK_ALL_SHADERS(M)
1119 #undef M
1120     }
1121     SkUNREACHABLE;
1122 }
1123 
1124 }  // namespace GrFragmentProcessors
1125