Flutter Engine
The Flutter Engine
PrecompileShader.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 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
9
16#include "src/gpu/Blend.h"
29
30namespace skgpu::graphite {
31
33
35 if (this->priv().isALocalMatrixShader()) {
36 // SkShader::makeWithLocalMatrix collapses chains of localMatrix shaders so we need to
37 // follow suit here
38 return sk_ref_sp(this);
39 }
40
42}
43
45 if (!cf) {
46 return sk_ref_sp(this);
47 }
48
49 return PrecompileShaders::ColorFilter({ sk_ref_sp(this) }, { std::move(cf) });
50}
51
53 if (!cs) {
54 return sk_ref_sp(this);
55 }
56
57 return PrecompileShaders::WorkingColorSpace({ sk_ref_sp(this) }, { std::move(cs) });
58}
59
60//--------------------------------------------------------------------------------------------------
62private:
63 void addToKey(const KeyContext& keyContext,
65 PipelineDataGatherer* gatherer,
66 int desiredCombination) const override {
67
68 SkASSERT(desiredCombination == 0); // The empty shader only ever has one combination
69
71 }
72};
73
75 return sk_make_sp<PrecompileEmptyShader>();
76}
77
78//--------------------------------------------------------------------------------------------------
80private:
81 bool isConstant(int desiredCombination) const override {
82 SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
83 return true;
84 }
85
86 void addToKey(const KeyContext& keyContext,
88 PipelineDataGatherer* gatherer,
89 int desiredCombination) const override {
90
91 SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
92
93 // The white PMColor is just a placeholder for the actual paint params color
95 }
96};
97
99 return sk_make_sp<PrecompileColorShader>();
100}
101
102// The colorSpace is safe to ignore - it is just applied to the color and doesn't modify the
103// generated program.
105 return sk_make_sp<PrecompileColorShader>();
106}
107
108//--------------------------------------------------------------------------------------------------
110public:
114 bool needsPorterDuffBased,
115 bool needsSeparableMode)
116 : fRuntimeBlendEffects(runtimeBlendEffects.begin(), runtimeBlendEffects.end())
117 , fDstOptions(dsts.begin(), dsts.end())
118 , fSrcOptions(srcs.begin(), srcs.end()) {
119
120 fNumBlenderCombos = 0;
121 for (const auto& rt : fRuntimeBlendEffects) {
122 fNumBlenderCombos += rt->priv().numCombinations();
123 }
124 if (needsPorterDuffBased) {
125 ++fNumBlenderCombos;
126 }
127 if (needsSeparableMode) {
128 ++fNumBlenderCombos;
129 }
130
131 SkASSERT(fNumBlenderCombos >= 1);
132
133 fNumDstCombos = 0;
134 for (const auto& d : fDstOptions) {
135 fNumDstCombos += d->priv().numCombinations();
136 }
137
138 fNumSrcCombos = 0;
139 for (const auto& s : fSrcOptions) {
140 fNumSrcCombos += s->priv().numCombinations();
141 }
142
143 if (needsPorterDuffBased) {
144 fPorterDuffIndex = 0;
145 if (needsSeparableMode) {
146 fSeparableModeIndex = 1;
147 if (!fRuntimeBlendEffects.empty()) {
148 fBlenderIndex = 2;
149 }
150 } else if (!fRuntimeBlendEffects.empty()) {
151 fBlenderIndex = 1;
152 }
153 } else if (needsSeparableMode) {
154 fSeparableModeIndex = 0;
155 if (!fRuntimeBlendEffects.empty()) {
156 fBlenderIndex = 1;
157 }
158 } else {
159 SkASSERT(!fRuntimeBlendEffects.empty());
160 fBlenderIndex = 0;
161 }
162 }
163
164private:
165 int numChildCombinations() const override {
166 return fNumBlenderCombos * fNumDstCombos * fNumSrcCombos;
167 }
168
169 void addToKey(const KeyContext& keyContext,
170 PaintParamsKeyBuilder* builder,
171 PipelineDataGatherer* gatherer,
172 int desiredCombination) const override {
173 SkASSERT(desiredCombination < this->numCombinations());
174
175 const int desiredDstCombination = desiredCombination % fNumDstCombos;
176 int remainingCombinations = desiredCombination / fNumDstCombos;
177
178 const int desiredSrcCombination = remainingCombinations % fNumSrcCombos;
179 remainingCombinations /= fNumSrcCombos;
180
181 int desiredBlendCombination = remainingCombinations;
182 SkASSERT(desiredBlendCombination < fNumBlenderCombos);
183
184 if (desiredBlendCombination == fPorterDuffIndex ||
185 desiredBlendCombination == fSeparableModeIndex) {
186 BlendShaderBlock::BeginBlock(keyContext, builder, gatherer);
187
188 } else {
189 const SkRuntimeEffect* blendEffect =
190 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kBlend);
191
192 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
193 { sk_ref_sp(blendEffect) });
194 SkASSERT(desiredBlendCombination >= fBlenderIndex);
195 desiredBlendCombination -= fBlenderIndex;
196 }
197
198 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fSrcOptions,
199 desiredSrcCombination);
200 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fDstOptions,
201 desiredDstCombination);
202
203 if (desiredBlendCombination == fPorterDuffIndex) {
204 CoeffBlenderBlock::AddBlock(keyContext, builder, gatherer,
205 { 0.0f, 0.0f, 0.0f, 0.0f }); // coeffs aren't used
206 } else if (desiredBlendCombination == fSeparableModeIndex) {
207 BlendModeBlenderBlock::AddBlock(keyContext, builder, gatherer,
208 SkBlendMode::kOverlay); // the blendmode is unused
209 } else {
210 AddToKey<PrecompileBlender>(keyContext, builder, gatherer, fRuntimeBlendEffects,
211 desiredBlendCombination);
212 }
213
214 builder->endBlock(); // BlendShaderBlock or RuntimeEffectBlock
215 }
216
217 std::vector<sk_sp<PrecompileBlender>> fRuntimeBlendEffects;
218 std::vector<sk_sp<PrecompileShader>> fDstOptions;
219 std::vector<sk_sp<PrecompileShader>> fSrcOptions;
220
221 int fNumBlenderCombos;
222 int fNumDstCombos;
223 int fNumSrcCombos;
224
225 int fPorterDuffIndex = -1;
226 int fSeparableModeIndex = -1;
227 int fBlenderIndex = -1;
228};
229
231 SkSpan<const sk_sp<PrecompileBlender>> blenders,
234 std::vector<sk_sp<PrecompileBlender>> tmp;
235 tmp.reserve(blenders.size());
236
237 bool needsPorterDuffBased = false;
238 bool needsBlendModeBased = false;
239
240 for (const auto& b : blenders) {
241 if (!b) {
242 needsPorterDuffBased = true; // fall back to kSrcOver
243 } else if (b->priv().asBlendMode().has_value()) {
244 SkBlendMode bm = b->priv().asBlendMode().value();
245
247 if (!coeffs.empty()) {
248 needsPorterDuffBased = true;
249 } else {
250 needsBlendModeBased = true;
251 }
252 } else {
253 tmp.push_back(b);
254 }
255 }
256
257 if (!needsPorterDuffBased && !needsBlendModeBased && tmp.empty()) {
258 needsPorterDuffBased = true; // fallback to kSrcOver
259 }
260
261 return sk_make_sp<PrecompileBlendShader>(SkSpan<const sk_sp<PrecompileBlender>>(tmp),
262 dsts, srcs,
263 needsPorterDuffBased, needsBlendModeBased);
264}
265
267 SkSpan<const SkBlendMode> blendModes,
270
271 bool needsPorterDuffBased = false;
272 bool needsBlendModeBased = false;
273
274 for (SkBlendMode bm : blendModes) {
276 if (!porterDuffConstants.empty()) {
277 needsPorterDuffBased = true;
278 } else {
279 needsBlendModeBased = true;
280 }
281 }
282
283 if (!needsPorterDuffBased && !needsBlendModeBased) {
284 needsPorterDuffBased = true; // fallback to kSrcOver
285 }
286
287 return sk_make_sp<PrecompileBlendShader>(SkSpan<const sk_sp<PrecompileBlender>>(),
288 dsts, srcs,
289 needsPorterDuffBased, needsBlendModeBased);
290}
291
292//--------------------------------------------------------------------------------------------------
294public:
296 : fShaders(shaders.begin(), shaders.end()) {
297 fNumShaderCombos = 0;
298 for (const auto& s : fShaders) {
299 fNumShaderCombos += s->priv().numCombinations();
300 }
301 }
302
303private:
304 int numChildCombinations() const override {
305 return fNumShaderCombos;
306 }
307
308 void addToKey(const KeyContext& keyContext,
309 PaintParamsKeyBuilder* builder,
310 PipelineDataGatherer* gatherer,
311 int desiredCombination) const override {
312 SkASSERT(desiredCombination < fNumShaderCombos);
313
314 constexpr SkRect kIgnored { 0, 0, 256, 256 }; // ignored bc we're precompiling
315
316 // TODO: update CoordClampShaderBlock so this is optional
317 CoordClampShaderBlock::CoordClampData data(kIgnored);
318
319 CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
320 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders, desiredCombination);
321 builder->endBlock();
322 }
323
324 std::vector<sk_sp<PrecompileShader>> fShaders;
325 int fNumShaderCombos;
326};
327
329 return sk_make_sp<PrecompileCoordClampShader>(input);
330}
331
332//--------------------------------------------------------------------------------------------------
333// TODO: Investigate the YUV-image use case
335public:
337
338private:
339 // The ImageShader has 3 potential sampling/tiling variants: hardware-tiled, shader-tiled and
340 // cubic sampling (which always uses shader-tiling)
341 inline static constexpr int kNumSamplingTilingCombos = 3;
342 inline static constexpr int kCubicSampled = 2;
343 inline static constexpr int kHWTiled = 1;
344 inline static constexpr int kShaderTiled = 0;
345
346 // There are also 2 potential alpha combinations: alpha-only and not-alpha-only
347 inline static constexpr int kNumAlphaCombinations = 2;
348 inline static constexpr int kAlphaOnly = 1;
349 inline static constexpr int kNonAlphaOnly = 0;
350
351 int numIntrinsicCombinations() const override {
352 int numSamplingTilingCombos =
353 (fFlags & PrecompileImageShaderFlags::kExcludeCubic) ? 2 : kNumSamplingTilingCombos;
354
356 // RawImageShaders don't blend alpha-only images w/ the paint color
357 return numSamplingTilingCombos;
358 }
359 return numSamplingTilingCombos * kNumAlphaCombinations;
360 }
361
362 void addToKey(const KeyContext& keyContext,
363 PaintParamsKeyBuilder* builder,
364 PipelineDataGatherer* gatherer,
365 int desiredCombination) const override {
366 SkASSERT(desiredCombination < this->numIntrinsicCombinations());
367
368 int desiredAlphaCombo, desiredSamplingTilingCombo;
369
371 desiredAlphaCombo = kNonAlphaOnly;
372 desiredSamplingTilingCombo = desiredCombination;
373 } else {
374 desiredAlphaCombo = desiredCombination % kNumAlphaCombinations;
375 desiredSamplingTilingCombo = desiredCombination / kNumAlphaCombinations;
376 }
377 SkDEBUGCODE(int numSamplingTilingCombos =
378 (fFlags & PrecompileImageShaderFlags::kExcludeCubic) ? 2 : kNumSamplingTilingCombos;)
379 SkASSERT(desiredSamplingTilingCombo < numSamplingTilingCombos);
380
381 static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
382 static constexpr SkSamplingOptions kDefaultSampling;
383 constexpr ReadSwizzle kIgnoredSwizzle = ReadSwizzle::kRGBA;
384
385 // ImageShaderBlock will use hardware tiling when the subset covers the entire image, so we
386 // create subset + image size combinations where subset == imgSize (for a shader that uses
387 // hardware tiling) and subset < imgSize (for a shader that does shader-based tiling).
388 static constexpr SkRect kSubset = SkRect::MakeWH(1.0f, 1.0f);
389 static constexpr SkISize kHWTileableSize = SkISize::Make(1, 1);
390 static constexpr SkISize kShaderTileableSize = SkISize::Make(2, 2);
391
392 ImageShaderBlock::ImageData imgData(
393 desiredSamplingTilingCombo == kCubicSampled ? kDefaultCubicSampling
394 : kDefaultSampling,
396 desiredSamplingTilingCombo == kHWTiled ? kHWTileableSize : kShaderTileableSize,
397 kSubset, kIgnoredSwizzle);
398
399 if (desiredAlphaCombo == kAlphaOnly) {
401
402 Blend(keyContext, builder, gatherer,
403 /* addBlendToKey= */ [&] () -> void {
404 AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kDstIn);
405 },
406 /* addSrcToKey= */ [&] () -> void {
407 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
408 },
409 /* addDstToKey= */ [&]() -> void {
410 RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
411 });
412 } else {
413 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
414 }
415 }
416
418};
419
422 { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kNone) });
423}
424
426 // Raw images do not perform color space conversion, but in Graphite, this is represented as
427 // an identity color space xform, not as a distinct shader
429 { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kExcludeAlpha) });
430}
431
434 return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileImageShader>(flags) });
435}
436
440 { sk_make_sp<PrecompileImageShader>(flags |
442}
443
444//--------------------------------------------------------------------------------------------------
446public:
448
449private:
450 void addToKey(const KeyContext& keyContext,
452 PipelineDataGatherer* gatherer,
453 int desiredCombination) const override {
454
455 SkASSERT(desiredCombination == 0); // The Perlin noise shader only ever has one combination
456
457 // TODO: update PerlinNoiseShaderBlock so the NoiseData is optional
458 static const PerlinNoiseShaderBlock::PerlinNoiseData kIgnoredNoiseData(
459 PerlinNoiseShaderBlock::Type::kFractalNoise, { 0.0f, 0.0f }, 2, {1, 1});
460
461 PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, kIgnoredNoiseData);
462 }
463
464};
465
467 return sk_make_sp<PrecompilePerlinNoiseShader>();
468}
469
471 return sk_make_sp<PrecompilePerlinNoiseShader>();
472}
473
474//--------------------------------------------------------------------------------------------------
476public:
478
479private:
480 /*
481 * The gradients currently have three specializations based on the number of stops.
482 */
483 inline static constexpr int kNumStopVariants = 3;
484 inline static constexpr int kStopVariants[kNumStopVariants] =
486
487 int numIntrinsicCombinations() const override {
488 return kNumStopVariants;
489 }
490
491 void addToKey(const KeyContext& keyContext,
492 PaintParamsKeyBuilder* builder,
493 PipelineDataGatherer* gatherer,
494 int desiredCombination) const override {
495 const int intrinsicCombination = desiredCombination / this->numChildCombinations();
496 SkDEBUGCODE(int childCombination = desiredCombination % this->numChildCombinations();)
497 SkASSERT(intrinsicCombination < kNumStopVariants);
498 SkASSERT(childCombination == 0);
499
500 bool useStorageBuffer = keyContext.caps()->storageBufferSupport() &&
501 keyContext.caps()->storageBufferPreferred();
502
503 GradientShaderBlocks::GradientData gradData(fType,
504 kStopVariants[intrinsicCombination],
505 useStorageBuffer);
506
507 constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
508 ColorSpaceTransformBlock::ColorSpaceTransformData csData(sk_srgb_singleton(), kAlphaType,
509 sk_srgb_singleton(), kAlphaType);
510
511 Compose(keyContext, builder, gatherer,
512 /* addInnerToKey= */ [&]() -> void {
513 GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
514 },
515 /* addOuterToKey= */ [&]() -> void {
516 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
517 });
518 }
519
521};
522
525 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kLinear);
526 return PrecompileShaders::LocalMatrix({ std::move(s) });
527}
528
531 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kRadial);
532 return PrecompileShaders::LocalMatrix({ std::move(s) });
533}
534
537 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kSweep);
538 return PrecompileShaders::LocalMatrix({ std::move(s) });
539}
540
543 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kConical);
544 return PrecompileShaders::LocalMatrix({ std::move(s) });
545}
546
547//--------------------------------------------------------------------------------------------------
548// The PictureShader ultimately turns into an SkImageShader optionally wrapped in a
549// LocalMatrixShader.
550// Note that this means each precompile PictureShader will add 12 combinations:
551// 2 (pictureshader LM) x 6 (imageShader variations)
553 // Note: We don't need to consider the PrecompileYUVImageShader since the image
554 // being drawn was created internally by Skia (as non-YUV).
556}
557
560 if (withLM) {
561 return PrecompileShaders::LocalMatrix({ std::move(s) });
562 }
563 return s;
564}
565
566//--------------------------------------------------------------------------------------------------
567// In the main Skia API the SkLocalMatrixShader is optimized away when the LM is the identity
568// or omitted. The PrecompileLocalMatrixShader captures this by adding two intrinsic options.
569// One with the LMShader wrapping the child and one without the LMShader.
571public:
572 enum class Flags {
573 kNone,
574 kIncludeWithOutVariant,
575 };
576
579 : fWrapped(wrapped.begin(), wrapped.end())
580 , fFlags(flags) {
581 fNumWrappedCombos = 0;
582 for (const auto& s : fWrapped) {
583 fNumWrappedCombos += s->priv().numCombinations();
584 }
585 }
586
587 bool isConstant(int desiredCombination) const override {
588 SkASSERT(desiredCombination < this->numCombinations());
589
590 /*
591 * Regardless of whether the LocalMatrixShader elides itself or not, we always want
592 * the Constant-ness of the wrapped shader.
593 */
594 int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
595 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
596
597 std::pair<sk_sp<PrecompileShader>, int> wrapped =
598 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredWrappedCombination);
599 if (wrapped.first) {
600 return wrapped.first->priv().isConstant(wrapped.second);
601 }
602
603 return false;
604 }
605
606private:
607 // The LocalMatrixShader has two potential variants: with and without the LocalMatrixShader
608 inline static constexpr int kNumIntrinsicCombinations = 2;
609 inline static constexpr int kWithLocalMatrix = 1;
610 inline static constexpr int kWithoutLocalMatrix = 0;
611
612 bool isALocalMatrixShader() const override { return true; }
613
614 int numIntrinsicCombinations() const override {
615 if (fFlags != Flags::kIncludeWithOutVariant) {
616 return 1; // just kWithLocalMatrix
617 }
618 return kNumIntrinsicCombinations;
619 }
620
621 int numChildCombinations() const override { return fNumWrappedCombos; }
622
623 void addToKey(const KeyContext& keyContext,
624 PaintParamsKeyBuilder* builder,
625 PipelineDataGatherer* gatherer,
626 int desiredCombination) const override {
627 SkASSERT(desiredCombination < this->numCombinations());
628
629 int desiredLMCombination, desiredWrappedCombination;
630
631 if (fFlags != Flags::kIncludeWithOutVariant) {
632 desiredLMCombination = kWithLocalMatrix;
633 desiredWrappedCombination = desiredCombination;
634 } else {
635 desiredLMCombination = desiredCombination % kNumIntrinsicCombinations;
636 desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
637 }
638 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
639
640 if (desiredLMCombination == kWithLocalMatrix) {
641 LocalMatrixShaderBlock::LMShaderData kIgnoredLMShaderData(SkMatrix::I());
642
643 LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, kIgnoredLMShaderData);
644 }
645
646 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped,
647 desiredWrappedCombination);
648
649 if (desiredLMCombination == kWithLocalMatrix) {
650 builder->endBlock();
651 }
652 }
653
654 std::vector<sk_sp<PrecompileShader>> fWrapped;
655 int fNumWrappedCombos;
656 Flags fFlags;
657};
658
661 return sk_make_sp<PrecompileLocalMatrixShader>(std::move(wrapped));
662}
663
666 return sk_make_sp<PrecompileLocalMatrixShader>(
667 std::move(wrapped),
669}
670
671//--------------------------------------------------------------------------------------------------
673public:
675 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)
676 : fShaders(shaders.begin(), shaders.end())
677 , fColorFilters(colorFilters.begin(), colorFilters.end()) {
678 fNumShaderCombos = 0;
679 for (const auto& s : fShaders) {
680 fNumShaderCombos += s->priv().numCombinations();
681 }
682 fNumColorFilterCombos = 0;
683 for (const auto& cf : fColorFilters) {
684 fNumColorFilterCombos += cf->priv().numCombinations();
685 }
686 }
687
688private:
689 int numChildCombinations() const override { return fNumShaderCombos * fNumColorFilterCombos; }
690
691 void addToKey(const KeyContext& keyContext,
692 PaintParamsKeyBuilder* builder,
693 PipelineDataGatherer* gatherer,
694 int desiredCombination) const override {
695 SkASSERT(desiredCombination < this->numCombinations());
696
697 int desiredShaderCombination = desiredCombination % fNumShaderCombos;
698 int desiredColorFilterCombination = desiredCombination / fNumShaderCombos;
699 SkASSERT(desiredColorFilterCombination < fNumColorFilterCombos);
700
701 Compose(keyContext, builder, gatherer,
702 /* addInnerToKey= */ [&]() -> void {
703 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
704 desiredShaderCombination);
705 },
706 /* addOuterToKey= */ [&]() -> void {
707 AddToKey<PrecompileColorFilter>(keyContext, builder, gatherer, fColorFilters,
708 desiredColorFilterCombination);
709 });
710 }
711
712 std::vector<sk_sp<PrecompileShader>> fShaders;
713 std::vector<sk_sp<PrecompileColorFilter>> fColorFilters;
714 int fNumShaderCombos;
715 int fNumColorFilterCombos;
716};
717
719 SkSpan<const sk_sp<PrecompileShader>> shaders,
720 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters) {
721 return sk_make_sp<PrecompileColorFilterShader>(std::move(shaders), std::move(colorFilters));
722}
723
724//--------------------------------------------------------------------------------------------------
726public:
728 SkSpan<const sk_sp<SkColorSpace>> colorSpaces)
729 : fShaders(shaders.begin(), shaders.end())
730 , fColorSpaces(colorSpaces.begin(), colorSpaces.end()) {
731 fNumShaderCombos = 0;
732 for (const auto& s : fShaders) {
733 fNumShaderCombos += s->priv().numCombinations();
734 }
735 }
736
737private:
738 int numChildCombinations() const override { return fNumShaderCombos * fColorSpaces.size(); }
739
740 void addToKey(const KeyContext& keyContext,
741 PaintParamsKeyBuilder* builder,
742 PipelineDataGatherer* gatherer,
743 int desiredCombination) const override {
744 SkASSERT(desiredCombination < this->numCombinations());
745
746 int desiredShaderCombination = desiredCombination % fNumShaderCombos;
747 int desiredColorSpaceCombination = desiredCombination / fNumShaderCombos;
748 SkASSERT(desiredColorSpaceCombination < (int) fColorSpaces.size());
749
750 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
751 const SkAlphaType dstAT = dstInfo.alphaType();
752 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
753 if (!dstCS) {
754 dstCS = SkColorSpace::MakeSRGB();
755 }
756
757 sk_sp<SkColorSpace> workingCS = fColorSpaces[desiredColorSpaceCombination];
758 SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
759 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
760
761 Compose(keyContext, builder, gatherer,
762 /* addInnerToKey= */ [&]() -> void {
763 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
764 desiredShaderCombination);
765 },
766 /* addOuterToKey= */ [&]() -> void {
767 ColorSpaceTransformBlock::ColorSpaceTransformData data(
768 workingCS.get(), dstAT, dstCS.get(), dstAT);
769 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
770 });
771 }
772
773 std::vector<sk_sp<PrecompileShader>> fShaders;
774 std::vector<sk_sp<SkColorSpace>> fColorSpaces;
775 int fNumShaderCombos;
776};
777
779 SkSpan<const sk_sp<PrecompileShader>> shaders,
780 SkSpan<const sk_sp<SkColorSpace>> colorSpaces) {
781 return sk_make_sp<PrecompileWorkingColorSpaceShader>(std::move(shaders),
782 std::move(colorSpaces));
783}
784
785//--------------------------------------------------------------------------------------------------
786// In Graphite this acts as a non-elidable LocalMatrixShader
788public:
790 : fWrapped(wrapped.begin(), wrapped.end()) {
791 fNumWrappedCombos = 0;
792 for (const auto& s : fWrapped) {
793 fNumWrappedCombos += s->priv().numCombinations();
794 }
795 }
796
797 bool isConstant(int desiredCombination) const override {
798 SkASSERT(desiredCombination < fNumWrappedCombos);
799
800 std::pair<sk_sp<PrecompileShader>, int> wrapped =
801 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredCombination);
802 if (wrapped.first) {
803 return wrapped.first->priv().isConstant(wrapped.second);
804 }
805
806 return false;
807 }
808
809private:
810 int numChildCombinations() const override { return fNumWrappedCombos; }
811
812 void addToKey(const KeyContext& keyContext,
813 PaintParamsKeyBuilder* builder,
814 PipelineDataGatherer* gatherer,
815 int desiredCombination) const override {
816 SkASSERT(desiredCombination < fNumWrappedCombos);
817
818 LocalMatrixShaderBlock::LMShaderData kIgnoredLMShaderData(SkMatrix::I());
819
820 LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, kIgnoredLMShaderData);
821
822 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped, desiredCombination);
823
824 builder->endBlock();
825 }
826
827 std::vector<sk_sp<PrecompileShader>> fWrapped;
828 int fNumWrappedCombos;
829};
830
832 return sk_make_sp<PrecompileCTMShader>(std::move(wrapped));
833}
834
835//--------------------------------------------------------------------------------------------------
837public:
839 : fWrapped(std::move(wrapped)) {
840 fNumWrappedCombos = fWrapped->priv().numCombinations();
841 }
842
843private:
844 // 6 known 1D blur effects + 6 known 2D blur effects
845 inline static constexpr int kNumIntrinsicCombinations = 12;
846
847 int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
848
849 int numChildCombinations() const override { return fNumWrappedCombos; }
850
851 void addToKey(const KeyContext& keyContext,
852 PaintParamsKeyBuilder* builder,
853 PipelineDataGatherer* gatherer,
854 int desiredCombination) const override {
855 SkASSERT(desiredCombination < this->numCombinations());
856
857 using namespace SkKnownRuntimeEffects;
858
859 int desiredBlurCombination = desiredCombination % kNumIntrinsicCombinations;
860 int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
861 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
862
863 static const StableKey kIDs[kNumIntrinsicCombinations] = {
864 StableKey::k1DBlur4, StableKey::k1DBlur8, StableKey::k1DBlur12,
865 StableKey::k1DBlur16, StableKey::k1DBlur20, StableKey::k1DBlur28,
866
867 StableKey::k2DBlur4, StableKey::k2DBlur8, StableKey::k2DBlur12,
868 StableKey::k2DBlur16, StableKey::k2DBlur20, StableKey::k2DBlur28,
869 };
870
871 const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(kIDs[desiredBlurCombination]);
872
873 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
874
875 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
876 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
877 builder->endBlock();
878 }
879
881 int fNumWrappedCombos;
882};
883
885 return sk_make_sp<PrecompileBlurShader>(std::move(wrapped));
886}
887
888//--------------------------------------------------------------------------------------------------
890public:
892 : fWrapped(std::move(wrapped)) {
893 fNumWrappedCombos = fWrapped->priv().numCombinations();
894
895 // When the matrix convolution ImageFilter uses a texture we know it will only ever
896 // be SkFilterMode::kNearest and SkTileMode::kClamp.
897 // TODO: add a PrecompileImageShaderFlags to further limit the raw image shader
898 // combinations. Right now we're getting two combinations for the raw shader
899 // (sk_image_shader and sk_hw_image_shader).
900 fRawImageShader =
902 fNumRawImageShaderCombos = fRawImageShader->priv().numCombinations();
903 }
904
905private:
906 int numIntrinsicCombinations() const override {
907 // The uniform version only has one option but the two texture-based versions will
908 // have as many combinations as the raw image shader.
909 return 1 + 2 * fNumRawImageShaderCombos;
910 }
911
912 int numChildCombinations() const override { return fNumWrappedCombos; }
913
914 void addToKey(const KeyContext& keyContext,
915 PaintParamsKeyBuilder* builder,
916 PipelineDataGatherer* gatherer,
917 int desiredCombination) const override {
918
919 int desiredTextureCombination = 0;
920
921 const int desiredWrappedCombination = desiredCombination % fNumWrappedCombos;
922 int remainingCombinations = desiredCombination / fNumWrappedCombos;
923
925 if (remainingCombinations == 0) {
926 stableKey = SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms;
927 } else {
928 static constexpr SkKnownRuntimeEffects::StableKey kTextureBasedStableKeys[] = {
929 SkKnownRuntimeEffects::StableKey::kMatrixConvTexSm,
930 SkKnownRuntimeEffects::StableKey::kMatrixConvTexLg,
931 };
932
933 --remainingCombinations;
934 stableKey = kTextureBasedStableKeys[remainingCombinations % 2];
935 desiredTextureCombination = remainingCombinations / 2;
936 SkASSERT(desiredTextureCombination < fNumRawImageShaderCombos);
937 }
938
939 const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(stableKey);
940
941 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
942
943 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
944 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
945 if (stableKey != SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms) {
946 fRawImageShader->priv().addToKey(childContext, builder, gatherer,
947 desiredTextureCombination);
948 }
949 builder->endBlock();
950 }
951
953 int fNumWrappedCombos;
954 sk_sp<PrecompileShader> fRawImageShader;
955 int fNumRawImageShaderCombos;
956};
957
960 return sk_make_sp<PrecompileMatrixConvolutionShader>(std::move(wrapped));
961}
962
963//--------------------------------------------------------------------------------------------------
965public:
968 : fWrapped(std::move(wrapped))
969 , fStableKey(stableKey) {
970 fNumWrappedCombos = fWrapped->priv().numCombinations();
971 SkASSERT(stableKey == SkKnownRuntimeEffects::StableKey::kLinearMorphology ||
972 stableKey == SkKnownRuntimeEffects::StableKey::kSparseMorphology);
973 }
974
975private:
976 int numChildCombinations() const override { return fNumWrappedCombos; }
977
978 void addToKey(const KeyContext& keyContext,
979 PaintParamsKeyBuilder* builder,
980 PipelineDataGatherer* gatherer,
981 int desiredCombination) const override {
982 SkASSERT(desiredCombination < fNumWrappedCombos);
983
984 const SkRuntimeEffect* effect = GetKnownRuntimeEffect(fStableKey);
985
986 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
987
988 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
989 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
990 builder->endBlock();
991 }
992
994 int fNumWrappedCombos;
996};
997
999 return sk_make_sp<PrecompileMorphologyShader>(
1000 std::move(wrapped),
1001 SkKnownRuntimeEffects::StableKey::kLinearMorphology);
1002}
1003
1005 return sk_make_sp<PrecompileMorphologyShader>(
1006 std::move(wrapped),
1007 SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1008}
1009
1010//--------------------------------------------------------------------------------------------------
1012public:
1015 : fDisplacement(std::move(displacement))
1016 , fColor(std::move(color)) {
1017 fNumDisplacementCombos = fDisplacement->priv().numCombinations();
1018 fNumColorCombos = fColor->priv().numCombinations();
1019 }
1020
1021private:
1022 int numChildCombinations() const override { return fNumDisplacementCombos * fNumColorCombos; }
1023
1024 void addToKey(const KeyContext& keyContext,
1025 PaintParamsKeyBuilder* builder,
1026 PipelineDataGatherer* gatherer,
1027 int desiredCombination) const override {
1028 SkASSERT(desiredCombination < this->numChildCombinations());
1029
1030 const int desiredDisplacementCombination = desiredCombination % fNumDisplacementCombos;
1031 const int desiredColorCombination = desiredCombination / fNumDisplacementCombos;
1032 SkASSERT(desiredColorCombination < fNumColorCombos);
1033
1034 const SkRuntimeEffect* fEffect =
1035 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kDisplacement);
1036
1037 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1038
1039 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
1040 fDisplacement->priv().addToKey(childContext, builder, gatherer,
1041 desiredDisplacementCombination);
1042 fColor->priv().addToKey(childContext, builder, gatherer,
1043 desiredColorCombination);
1044 builder->endBlock();
1045 }
1046
1047 sk_sp<PrecompileShader> fDisplacement;
1048 int fNumDisplacementCombos;
1050 int fNumColorCombos;
1051};
1052
1053//--------------------------------------------------------------------------------------------------
1056 return sk_make_sp<PrecompileDisplacementShader>(std::move(displacement), std::move(color));
1057}
1058
1059//--------------------------------------------------------------------------------------------------
1061public:
1063 : fWrapped(std::move(wrapped)) {
1064 fNumWrappedCombos = fWrapped->priv().numCombinations();
1065 }
1066
1067private:
1068 int numChildCombinations() const override { return fNumWrappedCombos; }
1069
1070 void addToKey(const KeyContext& keyContext,
1071 PaintParamsKeyBuilder* builder,
1072 PipelineDataGatherer* gatherer,
1073 int desiredCombination) const override {
1074 SkASSERT(desiredCombination < fNumWrappedCombos);
1075
1076 const SkRuntimeEffect* normalEffect =
1078 const SkRuntimeEffect* lightingEffect =
1079 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kLighting);
1080
1081 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1082
1083 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1084 { sk_ref_sp(lightingEffect) });
1085 RuntimeEffectBlock::BeginBlock(childContext, builder, gatherer,
1086 { sk_ref_sp(normalEffect) });
1087 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1088 builder->endBlock();
1089 builder->endBlock();
1090 }
1091
1092 sk_sp<PrecompileShader> fWrapped;
1093 int fNumWrappedCombos;
1094};
1095
1097 return sk_make_sp<PrecompileLightingShader>(std::move(wrapped));
1098}
1099
1100//--------------------------------------------------------------------------------------------------
1101
1102} // namespace skgpu::graphite
static const char * srcs[2]
Definition: EncodeBench.cpp:88
SkAlphaType
Definition: SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBlendMode
Definition: SkBlendMode.h:38
@ kDstIn
r = d * sa
@ kOverlay
multiply or screen, depending on destination
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
SkColorSpace * sk_srgb_singleton()
@ kInvalid
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static sk_sp< GrTextureProxy > wrapped(skiatest::Reporter *reporter, GrRecordingContext *rContext, GrProxyProvider *proxyProvider, SkBackingFit fit)
GrSurfaceProxyPriv priv()
SkAlphaType alphaType() const
Definition: SkImageInfo.h:141
sk_sp< SkColorSpace > refColorSpace() const
Definition: SkImageInfo.cpp:67
SkColorType colorType() const
Definition: SkImageInfo.h:140
static sk_sp< SkColorSpace > MakeSRGB()
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
constexpr bool empty() const
Definition: SkSpan_impl.h:96
T * get() const
Definition: SkRefCnt.h:303
virtual int numChildCombinations() const
static std::pair< sk_sp< T >, int > SelectOption(SkSpan< const sk_sp< T > > options, int desiredOption)
PrecompileBlendShader(SkSpan< const sk_sp< PrecompileBlender > > runtimeBlendEffects, SkSpan< const sk_sp< PrecompileShader > > dsts, SkSpan< const sk_sp< PrecompileShader > > srcs, bool needsPorterDuffBased, bool needsSeparableMode)
PrecompileBlurShader(sk_sp< PrecompileShader > wrapped)
bool isConstant(int desiredCombination) const override
PrecompileCTMShader(SkSpan< const sk_sp< PrecompileShader > > wrapped)
PrecompileColorFilterShader(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
PrecompileCoordClampShader(SkSpan< const sk_sp< PrecompileShader > > shaders)
PrecompileDisplacementShader(sk_sp< PrecompileShader > displacement, sk_sp< PrecompileShader > color)
PrecompileGradientShader(SkShaderBase::GradientType type)
PrecompileImageShader(SkEnumBitMask< PrecompileImageShaderFlags > flags)
PrecompileLightingShader(sk_sp< PrecompileShader > wrapped)
PrecompileLocalMatrixShader(SkSpan< const sk_sp< PrecompileShader > > wrapped, Flags flags=Flags::kNone)
bool isConstant(int desiredCombination) const override
PrecompileMatrixConvolutionShader(sk_sp< PrecompileShader > wrapped)
PrecompileMorphologyShader(sk_sp< PrecompileShader > wrapped, SkKnownRuntimeEffects::StableKey stableKey)
virtual bool isALocalMatrixShader() const
sk_sp< PrecompileShader > makeWithColorFilter(sk_sp< PrecompileColorFilter >)
sk_sp< PrecompileShader > makeWithWorkingColorSpace(sk_sp< SkColorSpace >)
sk_sp< PrecompileShader > makeWithLocalMatrix()
PrecompileWorkingColorSpaceShader(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< SkColorSpace > > colorSpaces)
DlColor color
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
@ kNormal
Default priority level.
Definition: embedder.h:262
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
static bool b
struct MyStruct s
FlutterSemanticsFlag flags
glong glong end
const SkRuntimeEffect * GetKnownRuntimeEffect(StableKey stableKey)
static constexpr skcms_TransferFunction kLinear
Definition: SkColorSpace.h:51
sk_sp< PrecompileShader > Lighting(sk_sp< PrecompileShader > wrapped)
sk_sp< PrecompileShader > Image(SkEnumBitMask< PrecompileImageShaderFlags >)
sk_sp< PrecompileShader > CTM(SkSpan< const sk_sp< PrecompileShader > > wrapped)
sk_sp< PrecompileShader > LocalMatrixBothVariants(SkSpan< const sk_sp< PrecompileShader > > wrapped)
sk_sp< PrecompileShader > Displacement(sk_sp< PrecompileShader > displacement, sk_sp< PrecompileShader > color)
sk_sp< PrecompileShader > LinearMorphology(sk_sp< PrecompileShader > wrapped)
sk_sp< PrecompileShader > Picture(bool withLM)
sk_sp< PrecompileShader > RawImage(SkEnumBitMask< PrecompileImageShaderFlags >)
sk_sp< PrecompileShader > MatrixConvolution(sk_sp< PrecompileShader > wrapped)
sk_sp< PrecompileShader > SparseMorphology(sk_sp< PrecompileShader > wrapped)
sk_sp< PrecompileShader > Blur(sk_sp< PrecompileShader > wrapped)
SK_API sk_sp< PrecompileShader > ColorFilter(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
SK_API sk_sp< PrecompileShader > LocalMatrix(SkSpan< const sk_sp< PrecompileShader > > wrapped)
SK_API sk_sp< PrecompileShader > WorkingColorSpace(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< SkColorSpace > > colorSpaces)
SK_API sk_sp< PrecompileShader > LinearGradient()
SK_API sk_sp< PrecompileShader > RadialGradient()
SK_API sk_sp< PrecompileShader > Picture()
SK_API sk_sp< PrecompileShader > CoordClamp(SkSpan< const sk_sp< PrecompileShader > >)
SK_API sk_sp< PrecompileShader > MakeTurbulence()
SK_API sk_sp< PrecompileShader > Image()
Definition: raw_object.h:2042
SK_API sk_sp< PrecompileShader > Empty()
SK_API sk_sp< PrecompileShader > Blend(SkSpan< const SkBlendMode > blendModes, SkSpan< const sk_sp< PrecompileShader > > dsts, SkSpan< const sk_sp< PrecompileShader > > srcs)
SK_API sk_sp< PrecompileShader > MakeFractalNoise()
SK_API sk_sp< PrecompileShader > SweepGradient()
SK_API sk_sp< PrecompileShader > RawImage()
SK_API sk_sp< PrecompileShader > Color()
SK_API sk_sp< PrecompileShader > TwoPointConicalGradient()
void AddKnownModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
void Compose(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addInnerToKey, AddToKeyFn addOuterToKey)
void Blend(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addBlendToKey, AddToKeyFn addSrcToKey, AddToKeyFn addDstToKey)
Definition: PaintParams.cpp:95
SkSpan< const float > GetPorterDuffBlendConstants(SkBlendMode mode)
Definition: Blend.cpp:53
Definition: ref_ptr.h:256
static constexpr SkCubicResampler Mitchell()
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, SkBlendMode)
Definition: KeyHelpers.cpp:936
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
Definition: KeyHelpers.cpp:926
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, SkSpan< const float > coeffs)
Definition: KeyHelpers.cpp:948
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ColorSpaceTransformData &)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const CoordClampData &)
Definition: KeyHelpers.cpp:853
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const GradientData &)
Definition: KeyHelpers.cpp:410
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ImageData &)
Definition: KeyHelpers.cpp:673
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const LMShaderData &)
Definition: KeyHelpers.cpp:498
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const PerlinNoiseData &)
Definition: KeyHelpers.cpp:915
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
Definition: KeyHelpers.cpp:131
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ShaderData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const SkPMColor4f &)
Definition: KeyHelpers.cpp:102
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63