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