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