• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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/graphite/FactoryFunctions.h"
9 
10 #include "include/core/SkSamplingOptions.h"
11 #include "include/gpu/graphite/precompile/PrecompileBase.h"
12 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
13 #include "include/gpu/graphite/precompile/PrecompileShader.h"
14 #include "src/core/SkColorSpacePriv.h"
15 #include "src/core/SkKnownRuntimeEffects.h"
16 #include "src/gpu/graphite/FactoryFunctionsPriv.h"
17 #include "src/gpu/graphite/KeyContext.h"
18 #include "src/gpu/graphite/KeyHelpers.h"
19 #include "src/gpu/graphite/PaintParams.h"
20 #include "src/gpu/graphite/PaintParamsKey.h"
21 #include "src/gpu/graphite/PrecompileInternal.h"
22 #include "src/gpu/graphite/Renderer.h"
23 #include "src/gpu/graphite/precompile/PrecompileBaseComplete.h"
24 #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
25 #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
26 #include "src/gpu/graphite/precompile/PrecompileShaderPriv.h"
27 
28 namespace skgpu::graphite {
29 
30 namespace {
31 
32 #ifdef SK_DEBUG
33 
precompilebase_is_valid_as_child(const PrecompileBase * child)34 bool precompilebase_is_valid_as_child(const PrecompileBase *child) {
35     if (!child) {
36         return true;
37     }
38 
39     switch (child->type()) {
40         case PrecompileBase::Type::kShader:
41         case PrecompileBase::Type::kColorFilter:
42         case PrecompileBase::Type::kBlender:
43             return true;
44         default:
45             return false;
46     }
47 }
48 
49 #endif // SK_DEBUG
50 
51 // If all the options are null the span is considered empty
is_empty(SkSpan<const sk_sp<PrecompileColorFilter>> options)52 bool is_empty(SkSpan<const sk_sp<PrecompileColorFilter>> options) {
53     if (options.empty()) {
54         return true;
55     }
56 
57     for (const auto& o : options) {
58         if (o) {
59             return false;
60         }
61     }
62 
63     return true;
64 }
65 
66 } // anonymous namespace
67 
68 //--------------------------------------------------------------------------------------------------
69 class PrecompileYUVImageShader : public PrecompileShader {
70 public:
PrecompileYUVImageShader()71     PrecompileYUVImageShader() {}
72 
73 private:
74     // non-cubic and cubic sampling
75     inline static constexpr int kNumIntrinsicCombinations = 2;
76 
numIntrinsicCombinations() const77     int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
78 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const79     void addToKey(const KeyContext& keyContext,
80                   PaintParamsKeyBuilder* builder,
81                   PipelineDataGatherer* gatherer,
82                   int desiredCombination) const override {
83         SkASSERT(desiredCombination < kNumIntrinsicCombinations);
84 
85         static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
86         static constexpr SkSamplingOptions kDefaultSampling;
87 
88         YUVImageShaderBlock::ImageData imgData(desiredCombination == 1 ? kDefaultCubicSampling
89                                                                        : kDefaultSampling,
90                                                SkTileMode::kClamp, SkTileMode::kClamp,
91                                                SkISize::MakeEmpty(), SkRect::MakeEmpty());
92 
93         YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
94     }
95 };
96 
YUVImage()97 sk_sp<PrecompileShader> PrecompileShaders::YUVImage() {
98     return sk_make_sp<PrecompileYUVImageShader>();
99 }
100 
101 //--------------------------------------------------------------------------------------------------
102 class PrecompileBlendFilterImageFilter : public PrecompileImageFilter {
103 public:
PrecompileBlendFilterImageFilter(sk_sp<PrecompileBlender> blender,SkSpan<sk_sp<PrecompileImageFilter>> inputs)104     PrecompileBlendFilterImageFilter(sk_sp<PrecompileBlender> blender,
105                                      SkSpan<sk_sp<PrecompileImageFilter>> inputs)
106             : PrecompileImageFilter(std::move(inputs))
107             , fBlender(std::move(blender)) {
108     }
109 
110 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const111     void onCreatePipelines(
112             const KeyContext& keyContext,
113             PipelineDataGatherer* gatherer,
114             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
115 
116         PaintOptions paintOptions;
117 
118         sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
119                 PrecompileImageShaderFlags::kExcludeAlpha |
120                 PrecompileImageShaderFlags::kExcludeCubic);
121 
122         sk_sp<PrecompileShader> blendShader = PrecompileShaders::Blend(
123                 SkSpan<const sk_sp<PrecompileBlender>>(&fBlender, 1),
124                 { imageShader },
125                 { imageShader });
126 
127         paintOptions.setShaders({ std::move(blendShader) });
128 
129         paintOptions.priv().buildCombinations(keyContext,
130                                               gatherer,
131                                               DrawTypeFlags::kSimpleShape,
132                                               /* withPrimitiveBlender= */ false,
133                                               Coverage::kSingleChannel,
134                                               processCombination);
135     }
136 
137     sk_sp<PrecompileBlender> fBlender;
138 };
139 
Arithmetic(sk_sp<PrecompileImageFilter> background,sk_sp<PrecompileImageFilter> foreground)140 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Arithmetic(
141         sk_sp<PrecompileImageFilter> background,
142         sk_sp<PrecompileImageFilter> foreground) {
143     return Blend(PrecompileBlenders::Arithmetic(), std::move(background), std::move(foreground));
144 }
145 
Blend(SkBlendMode bm,sk_sp<PrecompileImageFilter> background,sk_sp<PrecompileImageFilter> foreground)146 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Blend(
147         SkBlendMode bm,
148         sk_sp<PrecompileImageFilter> background,
149         sk_sp<PrecompileImageFilter> foreground) {
150     return Blend(PrecompileBlenders::Mode(bm), std::move(background), std::move(foreground));
151 }
152 
Blend(sk_sp<PrecompileBlender> blender,sk_sp<PrecompileImageFilter> background,sk_sp<PrecompileImageFilter> foreground)153 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Blend(
154         sk_sp<PrecompileBlender> blender,
155         sk_sp<PrecompileImageFilter> background,
156         sk_sp<PrecompileImageFilter> foreground) {
157 
158     if (!blender) {
159         blender = PrecompileBlenders::Mode(SkBlendMode::kSrcOver);
160     }
161 
162     if (std::optional<SkBlendMode> bm = blender->priv().asBlendMode()) {
163         if (bm == SkBlendMode::kSrc) {
164             return foreground;
165         } else if (bm == SkBlendMode::kDst) {
166             return background;
167         } else if (bm == SkBlendMode::kClear) {
168             return nullptr; // TODO: actually return PrecompileImageFilters::Empty
169         }
170     }
171 
172     sk_sp<PrecompileImageFilter> inputs[2] = { std::move(background), std::move(foreground) };
173     return sk_make_sp<PrecompileBlendFilterImageFilter>(std::move(blender), inputs);
174 }
175 
176 namespace {
177 
create_blur_imagefilter_pipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination)178 void create_blur_imagefilter_pipelines(
179         const KeyContext& keyContext,
180         PipelineDataGatherer* gatherer,
181         const PaintOptionsPriv::ProcessCombination& processCombination) {
182 
183     PaintOptions blurPaintOptions;
184 
185     // For blur imagefilters we know we don't have alpha-only textures and don't need cubic
186     // filtering.
187     sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
188             PrecompileImageShaderFlags::kExcludeAlpha | PrecompileImageShaderFlags::kExcludeCubic);
189 
190     static const SkBlendMode kBlurBlendModes[] = { SkBlendMode::kSrc };
191     blurPaintOptions.setShaders({ PrecompileShadersPriv::Blur(imageShader) });
192     blurPaintOptions.setBlendModes(kBlurBlendModes);
193 
194     blurPaintOptions.priv().buildCombinations(keyContext,
195                                               gatherer,
196                                               DrawTypeFlags::kSimpleShape,
197                                               /* withPrimitiveBlender= */ false,
198                                               Coverage::kSingleChannel,
199                                               processCombination);
200 }
201 
202 } // anonymous namespace
203 
204 class PrecompileBlurImageFilter : public PrecompileImageFilter {
205 public:
PrecompileBlurImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)206     PrecompileBlurImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
207             : PrecompileImageFilter(std::move(inputs)) {
208     }
209 
210 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const211     void onCreatePipelines(
212             const KeyContext& keyContext,
213             PipelineDataGatherer* gatherer,
214             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
215 
216         create_blur_imagefilter_pipelines(keyContext, gatherer, processCombination);
217     }
218 };
219 
Blur(sk_sp<PrecompileImageFilter> input)220 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Blur(
221             sk_sp<PrecompileImageFilter> input) {
222     return sk_make_sp<PrecompileBlurImageFilter>(SkSpan(&input, 1));
223 }
224 
225 //--------------------------------------------------------------------------------------------------
226 class PrecompileColorFilterImageFilter : public PrecompileImageFilter {
227 public:
PrecompileColorFilterImageFilter(sk_sp<PrecompileColorFilter> colorFilter,sk_sp<PrecompileImageFilter> input)228     PrecompileColorFilterImageFilter(sk_sp<PrecompileColorFilter> colorFilter,
229                                      sk_sp<PrecompileImageFilter> input)
230             : PrecompileImageFilter(SkSpan(&input, 1))
231             , fColorFilter(std::move(colorFilter)) {
232     }
233 
234 private:
isColorFilterNode() const235     sk_sp<PrecompileColorFilter> isColorFilterNode() const override {
236         return fColorFilter;
237     }
238 
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const239     void onCreatePipelines(
240             const KeyContext& keyContext,
241             PipelineDataGatherer* gatherer,
242             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
243         PaintOptions paintOptions;
244 
245         sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
246                 PrecompileImageShaderFlags::kExcludeAlpha |
247                 PrecompileImageShaderFlags::kExcludeCubic);
248 
249         static const SkBlendMode kBlendModes[] = { SkBlendMode::kDstOut };
250         paintOptions.setShaders({ std::move(imageShader) });
251         paintOptions.setColorFilters({ fColorFilter });
252         paintOptions.setBlendModes(kBlendModes);
253 
254         paintOptions.priv().buildCombinations(keyContext,
255                                               gatherer,
256                                               DrawTypeFlags::kSimpleShape,
257                                               /* withPrimitiveBlender= */ false,
258                                               Coverage::kSingleChannel,
259                                               processCombination);
260     }
261 
262     sk_sp<PrecompileColorFilter> fColorFilter;
263 };
264 
ColorFilter(sk_sp<PrecompileColorFilter> colorFilter,sk_sp<PrecompileImageFilter> input)265 sk_sp<PrecompileImageFilter> PrecompileImageFilters::ColorFilter(
266         sk_sp<PrecompileColorFilter> colorFilter,
267         sk_sp<PrecompileImageFilter> input) {
268     if (colorFilter && input) {
269         sk_sp<PrecompileColorFilter> inputCF = input->isColorFilterNode();
270         if (inputCF) {
271             colorFilter = colorFilter->makeComposed(std::move(inputCF));
272             input = sk_ref_sp(input->getInput(0));
273         }
274     }
275 
276     sk_sp<PrecompileImageFilter> filter = std::move(input);
277     if (colorFilter) {
278         filter = sk_make_sp<PrecompileColorFilterImageFilter>(std::move(colorFilter),
279                                                               std::move(filter));
280     }
281     return filter;
282 }
283 
284 //--------------------------------------------------------------------------------------------------
285 class PrecompileDisplacementMapImageFilter : public PrecompileImageFilter {
286 public:
PrecompileDisplacementMapImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)287     PrecompileDisplacementMapImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
288             : PrecompileImageFilter(std::move(inputs)) {
289     }
290 
291 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const292     void onCreatePipelines(
293             const KeyContext& keyContext,
294             PipelineDataGatherer* gatherer,
295             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
296 
297         PaintOptions displacement;
298 
299         // For displacement imagefilters we know we don't have alpha-only textures and don't need
300         // cubic filtering.
301         sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
302                 PrecompileImageShaderFlags::kExcludeAlpha |
303                 PrecompileImageShaderFlags::kExcludeCubic);
304 
305         displacement.setShaders({ PrecompileShadersPriv::Displacement(imageShader, imageShader) });
306 
307         displacement.priv().buildCombinations(keyContext,
308                                               gatherer,
309                                               DrawTypeFlags::kSimpleShape,
310                                               /* withPrimitiveBlender= */ false,
311                                               Coverage::kSingleChannel,
312                                               processCombination);
313     }
314 };
315 
DisplacementMap(sk_sp<PrecompileImageFilter> input)316 sk_sp<PrecompileImageFilter> PrecompileImageFilters::DisplacementMap(
317             sk_sp<PrecompileImageFilter> input) {
318     return sk_make_sp<PrecompileDisplacementMapImageFilter>(SkSpan(&input, 1));
319 }
320 
321 //--------------------------------------------------------------------------------------------------
322 class PrecompileLightingImageFilter : public PrecompileImageFilter {
323 public:
PrecompileLightingImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)324     PrecompileLightingImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
325             : PrecompileImageFilter(std::move(inputs)) {
326     }
327 
328 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const329     void onCreatePipelines(
330             const KeyContext& keyContext,
331             PipelineDataGatherer* gatherer,
332             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
333 
334         sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
335                 PrecompileImageShaderFlags::kExcludeAlpha |
336                 PrecompileImageShaderFlags::kExcludeCubic);
337 
338         PaintOptions lighting;
339         lighting.setShaders({ PrecompileShadersPriv::Lighting(std::move(imageShader)) });
340 
341         lighting.priv().buildCombinations(keyContext,
342                                           gatherer,
343                                           DrawTypeFlags::kSimpleShape,
344                                           /* withPrimitiveBlender= */ false,
345                                           Coverage::kSingleChannel,
346                                           processCombination);
347     }
348 };
349 
Lighting(sk_sp<PrecompileImageFilter> input)350 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Lighting(
351             sk_sp<PrecompileImageFilter> input) {
352     return sk_make_sp<PrecompileLightingImageFilter>(SkSpan(&input, 1));
353 }
354 
355 //--------------------------------------------------------------------------------------------------
356 class PrecompileMatrixConvolutionImageFilter : public PrecompileImageFilter {
357 public:
PrecompileMatrixConvolutionImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)358     PrecompileMatrixConvolutionImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
359             : PrecompileImageFilter(std::move(inputs)) {
360     }
361 
362 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const363     void onCreatePipelines(
364             const KeyContext& keyContext,
365             PipelineDataGatherer* gatherer,
366             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
367 
368         PaintOptions matrixConv;
369 
370         // For matrix convolution imagefilters we know we don't have alpha-only textures and don't
371         // need cubic filtering.
372         sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
373                 PrecompileImageShaderFlags::kExcludeAlpha |
374                 PrecompileImageShaderFlags::kExcludeCubic);
375 
376         matrixConv.setShaders({ PrecompileShadersPriv::MatrixConvolution(imageShader) });
377 
378         matrixConv.priv().buildCombinations(keyContext,
379                                             gatherer,
380                                             DrawTypeFlags::kSimpleShape,
381                                             /* withPrimitiveBlender= */ false,
382                                             Coverage::kSingleChannel,
383                                             processCombination);
384     }
385 };
386 
MatrixConvolution(sk_sp<PrecompileImageFilter> input)387 sk_sp<PrecompileImageFilter> PrecompileImageFilters::MatrixConvolution(
388             sk_sp<PrecompileImageFilter> input) {
389     return sk_make_sp<PrecompileMatrixConvolutionImageFilter>(SkSpan(&input, 1));
390 }
391 
392 //--------------------------------------------------------------------------------------------------
393 class PrecompileMorphologyImageFilter : public PrecompileImageFilter {
394 public:
PrecompileMorphologyImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)395     PrecompileMorphologyImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
396             : PrecompileImageFilter(std::move(inputs)) {
397     }
398 
399 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const400     void onCreatePipelines(
401             const KeyContext& keyContext,
402             PipelineDataGatherer* gatherer,
403             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
404 
405         // For morphology imagefilters we know we don't have alpha-only textures and don't need
406         // cubic filtering.
407         sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
408             PrecompileImageShaderFlags::kExcludeAlpha | PrecompileImageShaderFlags::kExcludeCubic);
409 
410         {
411             PaintOptions sparse;
412 
413             static const SkBlendMode kBlendModes[] = { SkBlendMode::kSrc };
414             sparse.setShaders({ PrecompileShadersPriv::SparseMorphology(imageShader) });
415             sparse.setBlendModes(kBlendModes);
416 
417             sparse.priv().buildCombinations(keyContext,
418                                             gatherer,
419                                             DrawTypeFlags::kSimpleShape,
420                                             /* withPrimitiveBlender= */ false,
421                                             Coverage::kSingleChannel,
422                                             processCombination);
423         }
424 
425         {
426             PaintOptions linear;
427 
428             static const SkBlendMode kBlendModes[] = { SkBlendMode::kSrcOver };
429             linear.setShaders({ PrecompileShadersPriv::LinearMorphology(std::move(imageShader)) });
430             linear.setBlendModes(kBlendModes);
431 
432             linear.priv().buildCombinations(keyContext,
433                                             gatherer,
434                                             DrawTypeFlags::kSimpleShape,
435                                             /* withPrimitiveBlender= */ false,
436                                             Coverage::kSingleChannel,
437                                             processCombination);
438         }
439     }
440 };
441 
Morphology(sk_sp<PrecompileImageFilter> input)442 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Morphology(
443         sk_sp<PrecompileImageFilter> input) {
444     return sk_make_sp<PrecompileMorphologyImageFilter>(SkSpan(&input, 1));
445 }
446 
447 //--------------------------------------------------------------------------------------------------
448 // TODO(b/342413572): the analytic blurmasks are triggered off of the simple DrawType thus
449 // over-generate when a simple draw doesn't have a blur mask.
450 class PrecompileBlurMaskFilter : public PrecompileMaskFilter {
451 public:
PrecompileBlurMaskFilter()452     PrecompileBlurMaskFilter() {}
453 
454 private:
createPipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const PaintOptionsPriv::ProcessCombination & processCombination) const455     void createPipelines(
456             const KeyContext& keyContext,
457             PipelineDataGatherer* gatherer,
458             const PaintOptionsPriv::ProcessCombination& processCombination) const override {
459         create_blur_imagefilter_pipelines(keyContext, gatherer, processCombination);
460     }
461 };
462 
Blur()463 sk_sp<PrecompileMaskFilter> PrecompileMaskFilters::Blur() {
464     return sk_make_sp<PrecompileBlurMaskFilter>();
465 }
466 
467 //--------------------------------------------------------------------------------------------------
468 //--------------------------------------------------------------------------------------------------
469 class PrecompileBlendModeColorFilter : public PrecompileColorFilter {
470 public:
PrecompileBlendModeColorFilter()471     PrecompileBlendModeColorFilter() {}
472 
473 private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const474     void addToKey(const KeyContext& keyContext,
475                   PaintParamsKeyBuilder* builder,
476                   PipelineDataGatherer* gatherer,
477                   int desiredCombination) const override {
478         SkASSERT(desiredCombination == 0);
479 
480         // Here, kSrcOver and the white color are just a stand-ins for some later blend mode
481         // and color.
482         AddBlendModeColorFilter(keyContext, builder, gatherer,
483                                 SkBlendMode::kSrcOver, SK_PMColor4fWHITE);
484     }
485 };
486 
Blend()487 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Blend() {
488     return sk_make_sp<PrecompileBlendModeColorFilter>();
489 }
490 
491 //--------------------------------------------------------------------------------------------------
492 class PrecompileColorSpaceXformColorFilter : public PrecompileColorFilter {
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const493     void addToKey(const KeyContext& keyContext,
494                   PaintParamsKeyBuilder* builder,
495                   PipelineDataGatherer* gatherer,
496                   int desiredCombination) const override {
497         SkASSERT(desiredCombination == 0);
498 
499         constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
500         ColorSpaceTransformBlock::ColorSpaceTransformData csData(sk_srgb_singleton(), kAlphaType,
501                                                                  sk_srgb_singleton(), kAlphaType);
502 
503         ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
504     }
505 };
506 
LinearToSRGBGamma()507 sk_sp<PrecompileColorFilter> PrecompileColorFilters::LinearToSRGBGamma() {
508     return sk_make_sp<PrecompileColorSpaceXformColorFilter>();
509 }
510 
SRGBToLinearGamma()511 sk_sp<PrecompileColorFilter> PrecompileColorFilters::SRGBToLinearGamma() {
512     return sk_make_sp<PrecompileColorSpaceXformColorFilter>();
513 }
514 
ColorSpaceXform()515 sk_sp<PrecompileColorFilter> PrecompileColorFiltersPriv::ColorSpaceXform() {
516     return sk_make_sp<PrecompileColorSpaceXformColorFilter>();
517 }
518 
519 //--------------------------------------------------------------------------------------------------
HighContrast()520 sk_sp<PrecompileColorFilter> PrecompileColorFilters::HighContrast() {
521     const SkRuntimeEffect* highContrastEffect =
522             GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kHighContrast);
523 
524     sk_sp<PrecompileColorFilter> cf = MakePrecompileColorFilter(sk_ref_sp(highContrastEffect));
525     if (!cf) {
526         return nullptr;
527     }
528     return PrecompileColorFiltersPriv::WithWorkingFormat({ std::move(cf) });
529 }
530 
531 //--------------------------------------------------------------------------------------------------
Luma()532 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Luma() {
533     const SkRuntimeEffect* lumaEffect =
534             GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kLuma);
535 
536     return MakePrecompileColorFilter(sk_ref_sp(lumaEffect));
537 }
538 
539 //--------------------------------------------------------------------------------------------------
Overdraw()540 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Overdraw() {
541     const SkRuntimeEffect* overdrawEffect =
542             GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kOverdraw);
543 
544     return MakePrecompileColorFilter(sk_ref_sp(overdrawEffect));
545 }
546 
547 //--------------------------------------------------------------------------------------------------
548 class PrecompileComposeColorFilter : public PrecompileColorFilter {
549 public:
PrecompileComposeColorFilter(SkSpan<const sk_sp<PrecompileColorFilter>> outerOptions,SkSpan<const sk_sp<PrecompileColorFilter>> innerOptions)550     PrecompileComposeColorFilter(SkSpan<const sk_sp<PrecompileColorFilter>> outerOptions,
551                                  SkSpan<const sk_sp<PrecompileColorFilter>> innerOptions)
552             : fOuterOptions(outerOptions.begin(), outerOptions.end())
553             , fInnerOptions(innerOptions.begin(), innerOptions.end()) {
554 
555         fNumOuterCombos = 0;
556         for (const auto& outerOption : fOuterOptions) {
557             fNumOuterCombos += outerOption ? outerOption->priv().numCombinations() : 1;
558         }
559 
560         fNumInnerCombos = 0;
561         for (const auto& innerOption : fInnerOptions) {
562             fNumInnerCombos += innerOption ? innerOption->priv().numCombinations() : 1;
563         }
564     }
565 
566 private:
numChildCombinations() const567     int numChildCombinations() const override { return fNumOuterCombos * fNumInnerCombos; }
568 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const569     void addToKey(const KeyContext& keyContext,
570                   PaintParamsKeyBuilder* builder,
571                   PipelineDataGatherer* gatherer,
572                   int desiredCombination) const override {
573         SkASSERT(desiredCombination < this->numCombinations());
574 
575         const int desiredOuterCombination = desiredCombination % fNumOuterCombos;
576         int remainingCombinations = desiredCombination / fNumOuterCombos;
577 
578         const int desiredInnerCombination = remainingCombinations % fNumInnerCombos;
579         remainingCombinations /= fNumInnerCombos;
580 
581         SkASSERT(!remainingCombinations);
582 
583         sk_sp<PrecompileColorFilter> inner, outer;
584         int innerChildOptions, outerChildOptions;
585 
586         std::tie(outer, outerChildOptions) = SelectOption<PrecompileColorFilter>(
587                 fOuterOptions, desiredOuterCombination);
588         std::tie(inner, innerChildOptions) = SelectOption<PrecompileColorFilter>(
589                 fInnerOptions, desiredInnerCombination);
590 
591         if (!inner && !outer) {
592             // A "passthrough" color filter returns the input color as-is.
593             builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
594         } else if (!inner) {
595             outer->priv().addToKey(keyContext, builder, gatherer, outerChildOptions);
596         } else if (!outer) {
597             inner->priv().addToKey(keyContext, builder, gatherer, innerChildOptions);
598         } else {
599             Compose(keyContext, builder, gatherer,
600                     /* addInnerToKey= */ [&]() -> void {
601                         inner->priv().addToKey(keyContext, builder, gatherer, innerChildOptions);
602                     },
603                     /* addOuterToKey= */ [&]() -> void {
604                         outer->priv().addToKey(keyContext, builder, gatherer, outerChildOptions);
605                     });
606         }
607     }
608 
609     std::vector<sk_sp<PrecompileColorFilter>> fOuterOptions;
610     std::vector<sk_sp<PrecompileColorFilter>> fInnerOptions;
611 
612     int fNumOuterCombos;
613     int fNumInnerCombos;
614 };
615 
Compose(SkSpan<const sk_sp<PrecompileColorFilter>> outerOptions,SkSpan<const sk_sp<PrecompileColorFilter>> innerOptions)616 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Compose(
617         SkSpan<const sk_sp<PrecompileColorFilter>> outerOptions,
618         SkSpan<const sk_sp<PrecompileColorFilter>> innerOptions) {
619     if (is_empty(outerOptions) && is_empty(innerOptions)) {
620         return nullptr;
621     }
622 
623     return sk_make_sp<PrecompileComposeColorFilter>(outerOptions, innerOptions);
624 }
625 
626 //--------------------------------------------------------------------------------------------------
627 class PrecompileGaussianColorFilter : public PrecompileColorFilter {
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const628     void addToKey(const KeyContext& keyContext,
629                   PaintParamsKeyBuilder* builder,
630                   PipelineDataGatherer* gatherer,
631                   int desiredCombination) const override {
632         SkASSERT(desiredCombination == 0);
633 
634         builder->addBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
635     }
636 };
637 
Gaussian()638 sk_sp<PrecompileColorFilter> PrecompileColorFiltersPriv::Gaussian() {
639     return sk_make_sp<PrecompileGaussianColorFilter>();
640 }
641 
642 //--------------------------------------------------------------------------------------------------
643 class PrecompileMatrixColorFilter : public PrecompileColorFilter {
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const644     void addToKey(const KeyContext& keyContext,
645                   PaintParamsKeyBuilder* builder,
646                   PipelineDataGatherer* gatherer,
647                   int desiredCombination) const override {
648         SkASSERT(desiredCombination == 0);
649 
650         static constexpr float kIdentity[20] = { 1, 0, 0, 0, 0,
651                                                  0, 1, 0, 0, 0,
652                                                  0, 0, 1, 0, 0,
653                                                  0, 0, 0, 1, 0 };
654 
655         MatrixColorFilterBlock::MatrixColorFilterData matrixCFData(kIdentity, /* inHSLA= */ false);
656 
657         MatrixColorFilterBlock::AddBlock(keyContext, builder, gatherer, matrixCFData);
658     }
659 };
660 
Matrix()661 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Matrix() {
662     return sk_make_sp<PrecompileMatrixColorFilter>();
663 }
664 
HSLAMatrix()665 sk_sp<PrecompileColorFilter> PrecompileColorFilters::HSLAMatrix() {
666     return sk_make_sp<PrecompileMatrixColorFilter>();
667 }
668 
669 //--------------------------------------------------------------------------------------------------
Lerp(SkSpan<const sk_sp<PrecompileColorFilter>> dstOptions,SkSpan<const sk_sp<PrecompileColorFilter>> srcOptions)670 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Lerp(
671         SkSpan<const sk_sp<PrecompileColorFilter>> dstOptions,
672         SkSpan<const sk_sp<PrecompileColorFilter>> srcOptions) {
673 
674     if (dstOptions.empty() && srcOptions.empty()) {
675         return nullptr;
676     }
677 
678     const SkRuntimeEffect* lerpEffect =
679             GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kLerp);
680 
681     // Since the RuntimeEffect Precompile objects behave differently we have to manually create
682     // all the combinations here (b/332690425).
683     skia_private::TArray<std::array<const PrecompileChildPtr, 2>> combos;
684     combos.reserve(dstOptions.size() * srcOptions.size());
685     for (const sk_sp<PrecompileColorFilter>& d : dstOptions) {
686         for (const sk_sp<PrecompileColorFilter>& s : srcOptions) {
687             combos.push_back({ d, s });
688         }
689     }
690     skia_private::TArray<SkSpan<const PrecompileChildPtr>> comboSpans;
691     comboSpans.reserve(combos.size());
692     for (const std::array<const PrecompileChildPtr, 2>& combo : combos) {
693         comboSpans.push_back({ combo });
694     }
695 
696     return MakePrecompileColorFilter(sk_ref_sp(lerpEffect), comboSpans);
697 }
698 
699 //--------------------------------------------------------------------------------------------------
700 class PrecompileTableColorFilter : public PrecompileColorFilter {
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const701     void addToKey(const KeyContext& keyContext,
702                   PaintParamsKeyBuilder* builder,
703                   PipelineDataGatherer* gatherer,
704                   int desiredCombination) const override {
705         SkASSERT(desiredCombination == 0);
706 
707         TableColorFilterBlock::TableColorFilterData data(/* proxy= */ nullptr);
708 
709         TableColorFilterBlock::AddBlock(keyContext, builder, gatherer, data);
710     }
711 };
712 
Table()713 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Table() {
714     return sk_make_sp<PrecompileTableColorFilter>();
715 }
716 
717 //--------------------------------------------------------------------------------------------------
Lighting()718 sk_sp<PrecompileColorFilter> PrecompileColorFilters::Lighting() {
719     return PrecompileColorFilters::Matrix();
720 }
721 
722 //--------------------------------------------------------------------------------------------------
723 class PrecompileWithWorkingFormatColorFilter : public PrecompileColorFilter {
724 public:
PrecompileWithWorkingFormatColorFilter(SkSpan<const sk_sp<PrecompileColorFilter>> childOptions)725     PrecompileWithWorkingFormatColorFilter(SkSpan<const sk_sp<PrecompileColorFilter>> childOptions)
726             : fChildOptions(childOptions.begin(), childOptions.end()) {
727 
728         fNumChildCombos = 0;
729         for (const auto& childOption : fChildOptions) {
730             fNumChildCombos += childOption->priv().numCombinations();
731         }
732     }
733 
734 private:
numChildCombinations() const735     int numChildCombinations() const override { return fNumChildCombos; }
736 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const737     void addToKey(const KeyContext& keyContext,
738                   PaintParamsKeyBuilder* builder,
739                   PipelineDataGatherer* gatherer,
740                   int desiredCombination) const override {
741         SkASSERT(desiredCombination < fNumChildCombos);
742 
743         constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
744         ColorSpaceTransformBlock::ColorSpaceTransformData csData(sk_srgb_singleton(), kAlphaType,
745                                                                  sk_srgb_singleton(), kAlphaType);
746 
747         // Use two nested compose blocks to chain (dst->working), child, and (working->dst) together
748         // while appearing as one block to the parent node.
749         Compose(keyContext, builder, gatherer,
750                 /* addInnerToKey= */ [&]() -> void {
751                     // Inner compose
752                     Compose(keyContext, builder, gatherer,
753                             /* addInnerToKey= */ [&]() -> void {
754                                 // Innermost (inner of inner compose)
755                                 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
756                                                                    csData);
757                             },
758                             /* addOuterToKey= */ [&]() -> void {
759                                 // Middle (outer of inner compose)
760                                 AddToKey<PrecompileColorFilter>(keyContext, builder, gatherer,
761                                                                 fChildOptions, desiredCombination);
762                             });
763                 },
764                 /* addOuterToKey= */ [&]() -> void {
765                     // Outermost (outer of outer compose)
766                     ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
767                 });
768     }
769 
770     std::vector<sk_sp<PrecompileColorFilter>> fChildOptions;
771 
772     int fNumChildCombos;
773 };
774 
WithWorkingFormat(SkSpan<const sk_sp<PrecompileColorFilter>> childOptions)775 sk_sp<PrecompileColorFilter> PrecompileColorFiltersPriv::WithWorkingFormat(
776         SkSpan<const sk_sp<PrecompileColorFilter>> childOptions) {
777     return sk_make_sp<PrecompileWithWorkingFormatColorFilter>(childOptions);
778 }
779 
780 //--------------------------------------------------------------------------------------------------
781 //--------------------------------------------------------------------------------------------------
PrecompileChildPtr(sk_sp<PrecompileShader> s)782 PrecompileChildPtr::PrecompileChildPtr(sk_sp<PrecompileShader> s) : fChild(std::move(s)) {}
PrecompileChildPtr(sk_sp<PrecompileColorFilter> cf)783 PrecompileChildPtr::PrecompileChildPtr(sk_sp<PrecompileColorFilter> cf)
784         : fChild(std::move(cf)) {
785 }
PrecompileChildPtr(sk_sp<PrecompileBlender> b)786 PrecompileChildPtr::PrecompileChildPtr(sk_sp<PrecompileBlender> b) : fChild(std::move(b)) {}
787 
PrecompileChildPtr(sk_sp<PrecompileBase> child)788 PrecompileChildPtr::PrecompileChildPtr(sk_sp<PrecompileBase> child)
789         : fChild(std::move(child)) {
790     SkASSERT(precompilebase_is_valid_as_child(fChild.get()));
791 }
792 
type() const793 std::optional<SkRuntimeEffect::ChildType> PrecompileChildPtr::type() const {
794     if (fChild) {
795         switch (fChild->type()) {
796             case PrecompileBase::Type::kShader:
797                 return SkRuntimeEffect::ChildType::kShader;
798             case PrecompileBase::Type::kColorFilter:
799                 return SkRuntimeEffect::ChildType::kColorFilter;
800             case PrecompileBase::Type::kBlender:
801                 return SkRuntimeEffect::ChildType::kBlender;
802             default:
803                 break;
804         }
805     }
806     return std::nullopt;
807 }
808 
shader() const809 PrecompileShader* PrecompileChildPtr::shader() const {
810     return (fChild && fChild->type() == PrecompileBase::Type::kShader)
811            ? static_cast<PrecompileShader*>(fChild.get())
812            : nullptr;
813 }
814 
colorFilter() const815 PrecompileColorFilter* PrecompileChildPtr::colorFilter() const {
816     return (fChild && fChild->type() == PrecompileBase::Type::kColorFilter)
817            ? static_cast<PrecompileColorFilter*>(fChild.get())
818            : nullptr;
819 }
820 
blender() const821 PrecompileBlender* PrecompileChildPtr::blender() const {
822     return (fChild && fChild->type() == PrecompileBase::Type::kBlender)
823            ? static_cast<PrecompileBlender*>(fChild.get())
824            : nullptr;
825 }
826 
827 //--------------------------------------------------------------------------------------------------
828 namespace {
829 
num_options_in_set(const std::vector<PrecompileChildPtr> & optionSet)830 int num_options_in_set(const std::vector<PrecompileChildPtr>& optionSet) {
831     int numOptions = 1;
832     for (const PrecompileChildPtr& childOption : optionSet) {
833         // A missing child will fall back to a passthrough object
834         if (childOption.base()) {
835             numOptions *= childOption.base()->priv().numCombinations();
836         }
837     }
838 
839     return numOptions;
840 }
841 
842 // This is the precompile correlate to KeyHelper.cpp's add_children_to_key
add_children_to_key(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination,const std::vector<PrecompileChildPtr> & optionSet,SkSpan<const SkRuntimeEffect::Child> childInfo)843 void add_children_to_key(const KeyContext& keyContext,
844                          PaintParamsKeyBuilder* builder,
845                          PipelineDataGatherer* gatherer,
846                          int desiredCombination,
847                          const std::vector<PrecompileChildPtr>& optionSet,
848                          SkSpan<const SkRuntimeEffect::Child> childInfo) {
849     using ChildType = SkRuntimeEffect::ChildType;
850 
851     SkASSERT(optionSet.size() == childInfo.size());
852 
853     KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
854 
855     int remainingCombinations = desiredCombination;
856 
857     for (size_t index = 0; index < optionSet.size(); ++index) {
858         const PrecompileChildPtr& childOption = optionSet[index];
859 
860         const int numChildCombos = childOption.base() ? childOption.base()->priv().numCombinations()
861                                                       : 1;
862         const int curCombo = remainingCombinations % numChildCombos;
863         remainingCombinations /= numChildCombos;
864 
865         std::optional<ChildType> type = childOption.type();
866         if (type == ChildType::kShader) {
867             childOption.shader()->priv().addToKey(childContext, builder, gatherer, curCombo);
868         } else if (type == ChildType::kColorFilter) {
869             childOption.colorFilter()->priv().addToKey(childContext, builder, gatherer, curCombo);
870         } else if (type == ChildType::kBlender) {
871             childOption.blender()->priv().addToKey(childContext, builder, gatherer, curCombo);
872         } else {
873             SkASSERT(curCombo == 0);
874 
875             // We don't have a child effect. Substitute in a no-op effect.
876             switch (childInfo[index].type) {
877                 case ChildType::kShader:
878                     // A missing shader returns transparent black
879                     SolidColorShaderBlock::AddBlock(childContext, builder, gatherer,
880                                                     SK_PMColor4fTRANSPARENT);
881                     break;
882 
883                 case ChildType::kColorFilter:
884                     // A "passthrough" shader returns the input color as-is.
885                     builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
886                     break;
887 
888                 case ChildType::kBlender:
889                     // A "passthrough" blender performs `blend_src_over(src, dest)`.
890                     AddKnownModeBlend(childContext, builder, gatherer, SkBlendMode::kSrcOver);
891                     break;
892             }
893         }
894     }
895 }
896 
897 } // anonymous namespace
898 
899 template<typename T>
900 class PrecompileRTEffect : public T {
901 public:
PrecompileRTEffect(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)902     PrecompileRTEffect(sk_sp<SkRuntimeEffect> effect,
903                        SkSpan<const PrecompileChildOptions> childOptions)
904             : fEffect(std::move(effect)) {
905         fChildOptions.reserve(childOptions.size());
906         for (PrecompileChildOptions c : childOptions) {
907             fChildOptions.push_back({ c.begin(), c.end() });
908         }
909     }
910 
911 private:
numChildCombinations() const912     int numChildCombinations() const override {
913         int numOptions = 0;
914         for (const std::vector<PrecompileChildPtr>& optionSet : fChildOptions) {
915             numOptions += num_options_in_set(optionSet);
916         }
917 
918         return numOptions ? numOptions : 1;
919     }
920 
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const921     void addToKey(const KeyContext& keyContext,
922                   PaintParamsKeyBuilder* builder,
923                   PipelineDataGatherer* gatherer,
924                   int desiredCombination) const override {
925 
926         SkASSERT(desiredCombination < this->numCombinations());
927 
928         SkSpan<const SkRuntimeEffect::Child> childInfo = fEffect->children();
929 
930         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { fEffect });
931 
932         for (const std::vector<PrecompileChildPtr>& optionSet : fChildOptions) {
933             int numOptionsInSet = num_options_in_set(optionSet);
934 
935             if (desiredCombination < numOptionsInSet) {
936                 add_children_to_key(keyContext, builder, gatherer, desiredCombination, optionSet,
937                                     childInfo);
938                 break;
939             }
940 
941             desiredCombination -= numOptionsInSet;
942         }
943 
944         builder->endBlock();
945     }
946 
947     sk_sp<SkRuntimeEffect> fEffect;
948     std::vector<std::vector<PrecompileChildPtr>> fChildOptions;
949 };
950 
MakePrecompileShader(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)951 sk_sp<PrecompileShader> MakePrecompileShader(
952         sk_sp<SkRuntimeEffect> effect,
953         SkSpan<const PrecompileChildOptions> childOptions) {
954     // TODO: check that 'effect' has the kAllowShader_Flag bit set and:
955     //  for each entry in childOptions:
956     //    all the SkPrecompileChildPtrs have the same type as the corresponding child in the effect
957     return sk_make_sp<PrecompileRTEffect<PrecompileShader>>(std::move(effect), childOptions);
958 }
959 
MakePrecompileColorFilter(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)960 sk_sp<PrecompileColorFilter> MakePrecompileColorFilter(
961         sk_sp<SkRuntimeEffect> effect,
962         SkSpan<const PrecompileChildOptions> childOptions) {
963     // TODO: check that 'effect' has the kAllowColorFilter_Flag bit set and:
964     //  for each entry in childOptions:
965     //    all the SkPrecompileChildPtrs have the same type as the corresponding child in the effect
966     return sk_make_sp<PrecompileRTEffect<PrecompileColorFilter>>(std::move(effect), childOptions);
967 }
968 
MakePrecompileBlender(sk_sp<SkRuntimeEffect> effect,SkSpan<const PrecompileChildOptions> childOptions)969 sk_sp<PrecompileBlender> MakePrecompileBlender(
970         sk_sp<SkRuntimeEffect> effect,
971         SkSpan<const PrecompileChildOptions> childOptions) {
972     // TODO: check that 'effect' has the kAllowBlender_Flag bit set and:
973     //  for each entry in childOptions:
974     //    all the SkPrecompileChildPtrs have the same type as the corresponding child in the effect
975     return sk_make_sp<PrecompileRTEffect<PrecompileBlender>>(std::move(effect), childOptions);
976 }
977 
978 } // namespace skgpu::graphite
979 
980 //--------------------------------------------------------------------------------------------------
981