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
8 #include "include/gpu/graphite/precompile/PrecompileShader.h"
9
10 #include "include/core/SkColorSpace.h"
11 #include "include/effects/SkRuntimeEffect.h"
12 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
13 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
14 #include "src/core/SkColorSpacePriv.h"
15 #include "src/core/SkKnownRuntimeEffects.h"
16 #include "src/gpu/Blend.h"
17 #include "src/gpu/graphite/BuiltInCodeSnippetID.h"
18 #include "src/gpu/graphite/KeyContext.h"
19 #include "src/gpu/graphite/KeyHelpers.h"
20 #include "src/gpu/graphite/PaintParams.h"
21 #include "src/gpu/graphite/PaintParamsKey.h"
22 #include "src/gpu/graphite/PrecompileInternal.h"
23 #include "src/gpu/graphite/ReadSwizzle.h"
24 #include "src/gpu/graphite/precompile/PrecompileBaseComplete.h"
25 #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
26 #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
27 #include "src/gpu/graphite/precompile/PrecompileShaderPriv.h"
28 #include "src/gpu/graphite/precompile/PrecompileShadersPriv.h"
29
30 namespace skgpu::graphite {
31
32 PrecompileShader::~PrecompileShader() = default;
33
makeWithColorFilter(sk_sp<PrecompileColorFilter> cf) const34 sk_sp<PrecompileShader> PrecompileShader::makeWithColorFilter(
35 sk_sp<PrecompileColorFilter> cf) const {
36 if (!cf) {
37 return sk_ref_sp(this);
38 }
39
40 return PrecompileShaders::ColorFilter({ sk_ref_sp(this) }, { std::move(cf) });
41 }
42
makeWithWorkingColorSpace(sk_sp<SkColorSpace> cs) const43 sk_sp<PrecompileShader> PrecompileShader::makeWithWorkingColorSpace(sk_sp<SkColorSpace> cs) const {
44 if (!cs) {
45 return sk_ref_sp(this);
46 }
47
48 return PrecompileShaders::WorkingColorSpace({ sk_ref_sp(this) }, { std::move(cs) });
49 }
50
51 //--------------------------------------------------------------------------------------------------
52 class PrecompileEmptyShader final : public PrecompileShader {
53 private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const54 void addToKey(const KeyContext& keyContext,
55 PaintParamsKeyBuilder* builder,
56 PipelineDataGatherer* gatherer,
57 int desiredCombination) const override {
58
59 SkASSERT(desiredCombination == 0); // The empty shader only ever has one combination
60
61 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
62 }
63 };
64
Empty()65 sk_sp<PrecompileShader> PrecompileShaders::Empty() {
66 return sk_make_sp<PrecompileEmptyShader>();
67 }
68
69 //--------------------------------------------------------------------------------------------------
70 class PrecompileColorShader final : public PrecompileShader {
71 private:
isConstant(int desiredCombination) const72 bool isConstant(int desiredCombination) const override {
73 SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
74 return true;
75 }
76
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const77 void addToKey(const KeyContext& keyContext,
78 PaintParamsKeyBuilder* builder,
79 PipelineDataGatherer* gatherer,
80 int desiredCombination) const override {
81
82 SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
83
84 // The white PMColor is just a placeholder for the actual paint params color
85 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, SK_PMColor4fWHITE);
86 }
87 };
88
Color()89 sk_sp<PrecompileShader> PrecompileShaders::Color() {
90 return sk_make_sp<PrecompileColorShader>();
91 }
92
93 // The colorSpace is safe to ignore - it is just applied to the color and doesn't modify the
94 // generated program.
Color(sk_sp<SkColorSpace>)95 sk_sp<PrecompileShader> PrecompileShaders::Color(sk_sp<SkColorSpace>) {
96 return sk_make_sp<PrecompileColorShader>();
97 }
98
99 //--------------------------------------------------------------------------------------------------
100 class PrecompileBlendShader final : public PrecompileShader {
101 public:
PrecompileBlendShader(PrecompileBlenderList && blenders,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)102 PrecompileBlendShader(PrecompileBlenderList&& blenders,
103 SkSpan<const sk_sp<PrecompileShader>> dsts,
104 SkSpan<const sk_sp<PrecompileShader>> srcs)
105 : fBlenderOptions(std::move(blenders))
106 , fDstOptions(dsts.begin(), dsts.end())
107 , fSrcOptions(srcs.begin(), srcs.end()) {
108 fNumDstCombos = 0;
109 for (const auto& d : fDstOptions) {
110 fNumDstCombos += d->priv().numCombinations();
111 }
112
113 fNumSrcCombos = 0;
114 for (const auto& s : fSrcOptions) {
115 fNumSrcCombos += s->priv().numCombinations();
116 }
117 }
118
119 private:
numChildCombinations() const120 int numChildCombinations() const override {
121 return fBlenderOptions.numCombinations() * fNumDstCombos * fNumSrcCombos;
122 }
123
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const124 void addToKey(const KeyContext& keyContext,
125 PaintParamsKeyBuilder* builder,
126 PipelineDataGatherer* gatherer,
127 int desiredCombination) const override {
128 SkASSERT(desiredCombination < this->numCombinations());
129
130 const int desiredDstCombination = desiredCombination % fNumDstCombos;
131 int remainingCombinations = desiredCombination / fNumDstCombos;
132
133 const int desiredSrcCombination = remainingCombinations % fNumSrcCombos;
134 remainingCombinations /= fNumSrcCombos;
135
136 int desiredBlendCombination = remainingCombinations;
137 SkASSERT(desiredBlendCombination < fBlenderOptions.numCombinations());
138
139 auto [blender, blenderCombination] = fBlenderOptions.selectOption(desiredBlendCombination);
140 if (blender->priv().asBlendMode()) {
141 // Coefficient and HSLC blends, and other fixed SkBlendMode blenders use the
142 // BlendCompose block to organize the children.
143 BlendComposeBlock::BeginBlock(keyContext, builder, gatherer);
144 } else {
145 // Runtime blenders are wrapped in the kBlend runtime shader, although functionally
146 // it is identical to the BlendCompose snippet.
147 const SkRuntimeEffect* blendEffect =
148 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kBlend);
149
150 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
151 { sk_ref_sp(blendEffect) });
152 }
153
154 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fSrcOptions,
155 desiredSrcCombination);
156 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fDstOptions,
157 desiredDstCombination);
158
159 if (blender->priv().asBlendMode()) {
160 SkASSERT(blenderCombination == 0);
161 AddBlendMode(keyContext, builder, gatherer, *blender->priv().asBlendMode());
162 } else {
163 blender->priv().addToKey(keyContext, builder, gatherer, blenderCombination);
164 }
165
166 builder->endBlock(); // BlendComposeBlock or RuntimeEffectBlock
167 }
168
169 PrecompileBlenderList fBlenderOptions;
170 std::vector<sk_sp<PrecompileShader>> fDstOptions;
171 std::vector<sk_sp<PrecompileShader>> fSrcOptions;
172
173 int fNumDstCombos;
174 int fNumSrcCombos;
175 };
176
Blend(SkSpan<const sk_sp<PrecompileBlender>> blenders,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)177 sk_sp<PrecompileShader> PrecompileShaders::Blend(
178 SkSpan<const sk_sp<PrecompileBlender>> blenders,
179 SkSpan<const sk_sp<PrecompileShader>> dsts,
180 SkSpan<const sk_sp<PrecompileShader>> srcs) {
181 return sk_make_sp<PrecompileBlendShader>(PrecompileBlenderList(blenders), dsts, srcs);
182 }
183
Blend(SkSpan<const SkBlendMode> blendModes,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)184 sk_sp<PrecompileShader> PrecompileShaders::Blend(
185 SkSpan<const SkBlendMode> blendModes,
186 SkSpan<const sk_sp<PrecompileShader>> dsts,
187 SkSpan<const sk_sp<PrecompileShader>> srcs) {
188 return sk_make_sp<PrecompileBlendShader>(PrecompileBlenderList(blendModes), dsts, srcs);
189 }
190
191 //--------------------------------------------------------------------------------------------------
192 class PrecompileCoordClampShader final : public PrecompileShader {
193 public:
PrecompileCoordClampShader(SkSpan<const sk_sp<PrecompileShader>> shaders)194 PrecompileCoordClampShader(SkSpan<const sk_sp<PrecompileShader>> shaders)
195 : fShaders(shaders.begin(), shaders.end()) {
196 fNumShaderCombos = 0;
197 for (const auto& s : fShaders) {
198 fNumShaderCombos += s->priv().numCombinations();
199 }
200 }
201
202 private:
numChildCombinations() const203 int numChildCombinations() const override {
204 return fNumShaderCombos;
205 }
206
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const207 void addToKey(const KeyContext& keyContext,
208 PaintParamsKeyBuilder* builder,
209 PipelineDataGatherer* gatherer,
210 int desiredCombination) const override {
211 SkASSERT(desiredCombination < fNumShaderCombos);
212
213 constexpr SkRect kIgnored { 0, 0, 256, 256 }; // ignored bc we're precompiling
214
215 // TODO: update CoordClampShaderBlock so this is optional
216 CoordClampShaderBlock::CoordClampData data(kIgnored);
217
218 CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
219 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders, desiredCombination);
220 builder->endBlock();
221 }
222
223 std::vector<sk_sp<PrecompileShader>> fShaders;
224 int fNumShaderCombos;
225 };
226
CoordClamp(SkSpan<const sk_sp<PrecompileShader>> input)227 sk_sp<PrecompileShader> PrecompileShaders::CoordClamp(SkSpan<const sk_sp<PrecompileShader>> input) {
228 return sk_make_sp<PrecompileCoordClampShader>(input);
229 }
230
231 //--------------------------------------------------------------------------------------------------
232 class PrecompileImageShader final : public PrecompileShader {
233 public:
PrecompileImageShader(SkEnumBitMask<PrecompileImageShaderFlags> flags)234 PrecompileImageShader(SkEnumBitMask<PrecompileImageShaderFlags> flags) : fFlags(flags) {}
235
236 private:
237 // The ImageShader has 3 potential sampling/tiling variants: hardware-tiled, shader-tiled and
238 // cubic sampling (which always uses shader-tiling)
239 inline static constexpr int kNumSamplingTilingCombos = 3;
240 inline static constexpr int kCubicSampled = 2;
241 inline static constexpr int kHWTiled = 1;
242 inline static constexpr int kShaderTiled = 0;
243
244 // There are also 2 potential alpha combinations: alpha-only and not-alpha-only
245 inline static constexpr int kNumAlphaCombinations = 2;
246 inline static constexpr int kAlphaOnly = 1;
247 inline static constexpr int kNonAlphaOnly = 0;
248
numIntrinsicCombinations() const249 int numIntrinsicCombinations() const override {
250 int numSamplingTilingCombos =
251 (fFlags & PrecompileImageShaderFlags::kExcludeCubic) ? 2 : kNumSamplingTilingCombos;
252
253 if (fFlags & PrecompileImageShaderFlags::kExcludeAlpha) {
254 // RawImageShaders don't blend alpha-only images w/ the paint color
255 return numSamplingTilingCombos;
256 }
257 return numSamplingTilingCombos * kNumAlphaCombinations;
258 }
259
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const260 void addToKey(const KeyContext& keyContext,
261 PaintParamsKeyBuilder* builder,
262 PipelineDataGatherer* gatherer,
263 int desiredCombination) const override {
264 SkASSERT(desiredCombination < this->numIntrinsicCombinations());
265
266 int desiredAlphaCombo, desiredSamplingTilingCombo;
267
268 if (fFlags & PrecompileImageShaderFlags::kExcludeAlpha) {
269 desiredAlphaCombo = kNonAlphaOnly;
270 desiredSamplingTilingCombo = desiredCombination;
271 } else {
272 desiredAlphaCombo = desiredCombination % kNumAlphaCombinations;
273 desiredSamplingTilingCombo = desiredCombination / kNumAlphaCombinations;
274 }
275 SkDEBUGCODE(int numSamplingTilingCombos =
276 (fFlags & PrecompileImageShaderFlags::kExcludeCubic) ? 2 : kNumSamplingTilingCombos;)
277 SkASSERT(desiredSamplingTilingCombo < numSamplingTilingCombos);
278
279 static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
280 static constexpr SkSamplingOptions kDefaultSampling;
281 constexpr ReadSwizzle kIgnoredSwizzle = ReadSwizzle::kRGBA;
282
283 // ImageShaderBlock will use hardware tiling when the subset covers the entire image, so we
284 // create subset + image size combinations where subset == imgSize (for a shader that uses
285 // hardware tiling) and subset < imgSize (for a shader that does shader-based tiling).
286 static constexpr SkRect kSubset = SkRect::MakeWH(1.0f, 1.0f);
287 static constexpr SkISize kHWTileableSize = SkISize::Make(1, 1);
288 static constexpr SkISize kShaderTileableSize = SkISize::Make(2, 2);
289
290 ImageShaderBlock::ImageData imgData(
291 desiredSamplingTilingCombo == kCubicSampled ? kDefaultCubicSampling
292 : kDefaultSampling,
293 SkTileMode::kClamp, SkTileMode::kClamp,
294 desiredSamplingTilingCombo == kHWTiled ? kHWTileableSize : kShaderTileableSize,
295 kSubset);
296 ColorSpaceTransformBlock::ColorSpaceTransformData colorXformData(kIgnoredSwizzle);
297
298 if (desiredAlphaCombo == kAlphaOnly) {
299 SkASSERT(!(fFlags & PrecompileImageShaderFlags::kExcludeAlpha));
300
301 Blend(keyContext, builder, gatherer,
302 /* addBlendToKey= */ [&] () -> void {
303
304 AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kDstIn);
305 },
306 /* addSrcToKey= */ [&] () -> void {
307 Compose(keyContext, builder, gatherer,
308 /* addInnerToKey= */ [&]() -> void {
309 ImageShaderBlock::AddBlock(keyContext, builder, gatherer,
310 imgData);
311 },
312 /* addOuterToKey= */ [&]() -> void {
313 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
314 colorXformData);
315 });
316 },
317 /* addDstToKey= */ [&]() -> void {
318 RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
319 });
320 } else {
321 Compose(keyContext, builder, gatherer,
322 /* addInnerToKey= */ [&]() -> void {
323 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
324 },
325 /* addOuterToKey= */ [&]() -> void {
326 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
327 colorXformData);
328 });
329 }
330 }
331
332 SkEnumBitMask<PrecompileImageShaderFlags> fFlags;
333 };
334
Image()335 sk_sp<PrecompileShader> PrecompileShaders::Image() {
336 return PrecompileShaders::LocalMatrix(
337 { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kNone) });
338 }
339
RawImage()340 sk_sp<PrecompileShader> PrecompileShaders::RawImage() {
341 // Raw images do not perform color space conversion, but in Graphite, this is represented as
342 // an identity color space xform, not as a distinct shader
343 return PrecompileShaders::LocalMatrix(
344 { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kExcludeAlpha) });
345 }
346
Image(SkEnumBitMask<PrecompileImageShaderFlags> flags)347 sk_sp<PrecompileShader> PrecompileShadersPriv::Image(
348 SkEnumBitMask<PrecompileImageShaderFlags> flags) {
349 return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileImageShader>(flags) });
350 }
351
RawImage(SkEnumBitMask<PrecompileImageShaderFlags> flags)352 sk_sp<PrecompileShader> PrecompileShadersPriv::RawImage(
353 SkEnumBitMask<PrecompileImageShaderFlags> flags) {
354 return PrecompileShaders::LocalMatrix(
355 { sk_make_sp<PrecompileImageShader>(flags |
356 PrecompileImageShaderFlags::kExcludeAlpha) });
357 }
358
359 //--------------------------------------------------------------------------------------------------
360 class PrecompileYUVImageShader : public PrecompileShader {
361 public:
PrecompileYUVImageShader()362 PrecompileYUVImageShader() {}
363
364 private:
365 // There are 8 intrinsic YUV shaders:
366 // 4 tiling modes
367 // HW tiling w/o swizzle
368 // HW tiling w/ swizzle
369 // cubic shader tiling
370 // non-cubic shader tiling
371 // crossed with two postambles:
372 // just premul
373 // full-blown colorSpace transform
374 inline static constexpr int kNumTilingModes = 4;
375 inline static constexpr int kHWTiledNoSwizzle = 3;
376 inline static constexpr int kHWTiledWithSwizzle = 2;
377 inline static constexpr int kCubicShaderTiled = 1;
378 inline static constexpr int kShaderTiled = 0;
379
380 inline static constexpr int kNumPostambles = 2;
381 inline static constexpr int kWithColorSpaceXform = 1;
382 inline static constexpr int kJustPremul = 0;
383
384 inline static constexpr int kNumIntrinsicCombinations = kNumTilingModes * kNumPostambles;
385
numIntrinsicCombinations() const386 int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
387
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const388 void addToKey(const KeyContext& keyContext,
389 PaintParamsKeyBuilder* builder,
390 PipelineDataGatherer* gatherer,
391 int desiredCombination) const override {
392 SkASSERT(desiredCombination < kNumIntrinsicCombinations);
393
394 int desiredPostamble = desiredCombination % kNumPostambles;
395 int desiredTiling = desiredCombination / kNumPostambles;
396 SkASSERT(desiredTiling < kNumTilingModes);
397
398 static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
399 static constexpr SkSamplingOptions kDefaultSampling;
400
401 YUVImageShaderBlock::ImageData imgData(desiredTiling == kCubicShaderTiled
402 ? kDefaultCubicSampling
403 : kDefaultSampling,
404 SkTileMode::kClamp, SkTileMode::kClamp,
405 /* imgSize= */ { 1, 1 },
406 /* subset= */ desiredTiling == kShaderTiled
407 ? SkRect::MakeEmpty()
408 : SkRect::MakeWH(1, 1));
409
410 static constexpr SkV4 kRedChannel{ 1.f, 0.f, 0.f, 0.f };
411 imgData.fChannelSelect[0] = kRedChannel;
412 imgData.fChannelSelect[1] = kRedChannel;
413 if (desiredTiling == kHWTiledNoSwizzle) {
414 imgData.fChannelSelect[2] = kRedChannel;
415 } else {
416 // Having a non-red channel selector forces a swizzle
417 imgData.fChannelSelect[2] = { 0.f, 1.f, 0.f, 0.f};
418 }
419 imgData.fChannelSelect[3] = kRedChannel;
420
421 imgData.fYUVtoRGBMatrix.setAll(1, 0, 0, 0, 1, 0, 0, 0, 0);
422 imgData.fYUVtoRGBTranslate = { 0, 0, 0 };
423
424 ColorSpaceTransformBlock::ColorSpaceTransformData colorXformData(
425 skgpu::graphite::ReadSwizzle::kRGBA);
426
427 if (desiredPostamble == kJustPremul) {
428 Compose(keyContext, builder, gatherer,
429 /* addInnerToKey= */ [&]() -> void {
430 YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
431 },
432 /* addOuterToKey= */ [&]() -> void {
433 builder->addBlock(BuiltInCodeSnippetID::kPremulAlphaColorFilter);
434 });
435 } else {
436 Compose(keyContext, builder, gatherer,
437 /* addInnerToKey= */ [&]() -> void {
438 YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
439 },
440 /* addOuterToKey= */ [&]() -> void {
441 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
442 colorXformData);
443 });
444 }
445
446 }
447 };
448
YUVImage()449 sk_sp<PrecompileShader> PrecompileShaders::YUVImage() {
450 return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileYUVImageShader>() });
451 }
452
453 //--------------------------------------------------------------------------------------------------
454 class PrecompilePerlinNoiseShader final : public PrecompileShader {
455 public:
PrecompilePerlinNoiseShader()456 PrecompilePerlinNoiseShader() {}
457
458 private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const459 void addToKey(const KeyContext& keyContext,
460 PaintParamsKeyBuilder* builder,
461 PipelineDataGatherer* gatherer,
462 int desiredCombination) const override {
463
464 SkASSERT(desiredCombination == 0); // The Perlin noise shader only ever has one combination
465
466 // TODO: update PerlinNoiseShaderBlock so the NoiseData is optional
467 static const PerlinNoiseShaderBlock::PerlinNoiseData kIgnoredNoiseData(
468 PerlinNoiseShaderBlock::Type::kFractalNoise, { 0.0f, 0.0f }, 2, {1, 1});
469
470 PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, kIgnoredNoiseData);
471 }
472
473 };
474
MakeFractalNoise()475 sk_sp<PrecompileShader> PrecompileShaders::MakeFractalNoise() {
476 return sk_make_sp<PrecompilePerlinNoiseShader>();
477 }
478
MakeTurbulence()479 sk_sp<PrecompileShader> PrecompileShaders::MakeTurbulence() {
480 return sk_make_sp<PrecompilePerlinNoiseShader>();
481 }
482
483 //--------------------------------------------------------------------------------------------------
484 class PrecompileGradientShader final : public PrecompileShader {
485 public:
PrecompileGradientShader(SkShaderBase::GradientType type)486 PrecompileGradientShader(SkShaderBase::GradientType type) : fType(type) {}
487
488 private:
489 /*
490 * The gradients currently have three specializations based on the number of stops.
491 */
492 inline static constexpr int kNumStopVariants = 3;
493 inline static constexpr int kStopVariants[kNumStopVariants] =
494 { 4, 8, GradientShaderBlocks::GradientData::kNumInternalStorageStops+1 };
495
numIntrinsicCombinations() const496 int numIntrinsicCombinations() const override {
497 return kNumStopVariants;
498 }
499
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const500 void addToKey(const KeyContext& keyContext,
501 PaintParamsKeyBuilder* builder,
502 PipelineDataGatherer* gatherer,
503 int desiredCombination) const override {
504 const int intrinsicCombination = desiredCombination / this->numChildCombinations();
505 SkDEBUGCODE(int childCombination = desiredCombination % this->numChildCombinations();)
506 SkASSERT(intrinsicCombination < kNumStopVariants);
507 SkASSERT(childCombination == 0);
508
509 bool useStorageBuffer = keyContext.caps()->gradientBufferSupport();
510
511 GradientShaderBlocks::GradientData gradData(fType,
512 kStopVariants[intrinsicCombination],
513 useStorageBuffer);
514
515 constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
516 ColorSpaceTransformBlock::ColorSpaceTransformData csData(sk_srgb_singleton(), kAlphaType,
517 sk_srgb_singleton(), kAlphaType);
518
519 Compose(keyContext, builder, gatherer,
520 /* addInnerToKey= */ [&]() -> void {
521 GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
522 },
523 /* addOuterToKey= */ [&]() -> void {
524 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
525 });
526 }
527
528 SkShaderBase::GradientType fType;
529 };
530
LinearGradient()531 sk_sp<PrecompileShader> PrecompileShaders::LinearGradient() {
532 sk_sp<PrecompileShader> s =
533 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kLinear);
534 return PrecompileShaders::LocalMatrix({ std::move(s) });
535 }
536
RadialGradient()537 sk_sp<PrecompileShader> PrecompileShaders::RadialGradient() {
538 sk_sp<PrecompileShader> s =
539 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kRadial);
540 return PrecompileShaders::LocalMatrix({ std::move(s) });
541 }
542
SweepGradient()543 sk_sp<PrecompileShader> PrecompileShaders::SweepGradient() {
544 sk_sp<PrecompileShader> s =
545 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kSweep);
546 return PrecompileShaders::LocalMatrix({ std::move(s) });
547 }
548
TwoPointConicalGradient()549 sk_sp<PrecompileShader> PrecompileShaders::TwoPointConicalGradient() {
550 sk_sp<PrecompileShader> s =
551 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kConical);
552 return PrecompileShaders::LocalMatrix({ std::move(s) });
553 }
554
555 //--------------------------------------------------------------------------------------------------
556 // The PictureShader ultimately turns into an SkImageShader optionally wrapped in a
557 // LocalMatrixShader.
558 // Note that this means each precompile PictureShader will add 12 combinations:
559 // 2 (pictureshader LM) x 6 (imageShader variations)
Picture()560 sk_sp<PrecompileShader> PrecompileShaders::Picture() {
561 // Note: We don't need to consider the PrecompileYUVImageShader since the image
562 // being drawn was created internally by Skia (as non-YUV).
563 return PrecompileShadersPriv::LocalMatrixBothVariants({ PrecompileShaders::Image() });
564 }
565
Picture(bool withLM)566 sk_sp<PrecompileShader> PrecompileShadersPriv::Picture(bool withLM) {
567 sk_sp<PrecompileShader> s = PrecompileShaders::Image();
568 if (withLM) {
569 return PrecompileShaders::LocalMatrix({ std::move(s) });
570 }
571 return s;
572 }
573
574 //--------------------------------------------------------------------------------------------------
575 // In the main Skia API the SkLocalMatrixShader is optimized away when the LM is the identity
576 // or omitted. The PrecompileLocalMatrixShader captures this by adding two intrinsic options.
577 // One with the LMShader wrapping the child and one without the LMShader.
578 class PrecompileLocalMatrixShader final : public PrecompileShader {
579 public:
580 enum class Flags {
581 kNone = 0b00,
582 kIsPerspective = 0b01,
583 kIncludeWithOutVariant = 0b10,
584 };
585
PrecompileLocalMatrixShader(SkSpan<const sk_sp<PrecompileShader>> wrapped,SkEnumBitMask<Flags> flags=Flags::kNone)586 PrecompileLocalMatrixShader(SkSpan<const sk_sp<PrecompileShader>> wrapped,
587 SkEnumBitMask<Flags> flags = Flags::kNone)
588 : fWrapped(wrapped.begin(), wrapped.end())
589 , fFlags(flags) {
590 fNumWrappedCombos = 0;
591 for (const auto& s : fWrapped) {
592 fNumWrappedCombos += s->priv().numCombinations();
593 }
594 }
595
isConstant(int desiredCombination) const596 bool isConstant(int desiredCombination) const override {
597 SkASSERT(desiredCombination < this->numCombinations());
598
599 /*
600 * Regardless of whether the LocalMatrixShader elides itself or not, we always want
601 * the Constant-ness of the wrapped shader.
602 */
603 int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
604 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
605
606 std::pair<sk_sp<PrecompileShader>, int> wrapped =
607 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredWrappedCombination);
608 if (wrapped.first) {
609 return wrapped.first->priv().isConstant(wrapped.second);
610 }
611
612 return false;
613 }
614
getWrapped() const615 SkSpan<const sk_sp<PrecompileShader>> getWrapped() const {
616 return fWrapped;
617 }
618
getFlags() const619 SkEnumBitMask<Flags> getFlags() const { return fFlags; }
620
621 private:
622 // The LocalMatrixShader has two potential variants: with and without the LocalMatrixShader
623 // In the "with" variant, the kIsPerspective flag will determine if the shader performs
624 // the perspective division or not.
625 inline static constexpr int kNumIntrinsicCombinations = 2;
626 inline static constexpr int kWithLocalMatrix = 1;
627 inline static constexpr int kWithoutLocalMatrix = 0;
628
isALocalMatrixShader() const629 bool isALocalMatrixShader() const override { return true; }
630
numIntrinsicCombinations() const631 int numIntrinsicCombinations() const override {
632 if (!(fFlags & Flags::kIncludeWithOutVariant)) {
633 return 1; // just kWithLocalMatrix
634 }
635 return kNumIntrinsicCombinations;
636 }
637
numChildCombinations() const638 int numChildCombinations() const override { return fNumWrappedCombos; }
639
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const640 void addToKey(const KeyContext& keyContext,
641 PaintParamsKeyBuilder* builder,
642 PipelineDataGatherer* gatherer,
643 int desiredCombination) const override {
644 SkASSERT(desiredCombination < this->numCombinations());
645
646 int desiredLMCombination, desiredWrappedCombination;
647
648 if (!(fFlags & Flags::kIncludeWithOutVariant)) {
649 desiredLMCombination = kWithLocalMatrix;
650 desiredWrappedCombination = desiredCombination;
651 } else {
652 desiredLMCombination = desiredCombination % kNumIntrinsicCombinations;
653 desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
654 }
655 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
656
657 if (desiredLMCombination == kWithLocalMatrix) {
658 SkMatrix matrix = SkMatrix::I();
659 if (fFlags & Flags::kIsPerspective) {
660 matrix.setPerspX(0.1f);
661 }
662 LocalMatrixShaderBlock::LMShaderData lmShaderData(matrix);
663
664 LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, matrix);
665 }
666
667 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped,
668 desiredWrappedCombination);
669
670 if (desiredLMCombination == kWithLocalMatrix) {
671 builder->endBlock();
672 }
673 }
674
675 std::vector<sk_sp<PrecompileShader>> fWrapped;
676 int fNumWrappedCombos;
677 SkEnumBitMask<Flags> fFlags;
678 };
679
LocalMatrix(SkSpan<const sk_sp<PrecompileShader>> wrapped,bool isPerspective)680 sk_sp<PrecompileShader> PrecompileShaders::LocalMatrix(
681 SkSpan<const sk_sp<PrecompileShader>> wrapped,
682 bool isPerspective) {
683 return sk_make_sp<PrecompileLocalMatrixShader>(
684 std::move(wrapped),
685 isPerspective ? PrecompileLocalMatrixShader::Flags::kIsPerspective
686 : PrecompileLocalMatrixShader::Flags::kNone);
687 }
688
LocalMatrixBothVariants(SkSpan<const sk_sp<PrecompileShader>> wrapped)689 sk_sp<PrecompileShader> PrecompileShadersPriv::LocalMatrixBothVariants(
690 SkSpan<const sk_sp<PrecompileShader>> wrapped) {
691 return sk_make_sp<PrecompileLocalMatrixShader>(
692 std::move(wrapped),
693 PrecompileLocalMatrixShader::Flags::kIncludeWithOutVariant);
694 }
695
makeWithLocalMatrix(bool isPerspective) const696 sk_sp<PrecompileShader> PrecompileShader::makeWithLocalMatrix(bool isPerspective) const {
697 if (this->priv().isALocalMatrixShader()) {
698 // SkShader::makeWithLocalMatrix collapses chains of localMatrix shaders so we need to
699 // follow suit here, folding in any new perspective flag if needed.
700 auto thisAsLMShader = static_cast<const PrecompileLocalMatrixShader*>(this);
701 if (isPerspective && !(thisAsLMShader->getFlags() &
702 PrecompileLocalMatrixShader::Flags::kIsPerspective)) {
703 return sk_make_sp<PrecompileLocalMatrixShader>(
704 thisAsLMShader->getWrapped(),
705 thisAsLMShader->getFlags() | PrecompileLocalMatrixShader::Flags::kIsPerspective);
706 }
707
708 return sk_ref_sp(this);
709 }
710
711 return PrecompileShaders::LocalMatrix({ sk_ref_sp(this) }, isPerspective);
712 }
713
714 //--------------------------------------------------------------------------------------------------
715 class PrecompileColorFilterShader final : public PrecompileShader {
716 public:
PrecompileColorFilterShader(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)717 PrecompileColorFilterShader(SkSpan<const sk_sp<PrecompileShader>> shaders,
718 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)
719 : fShaders(shaders.begin(), shaders.end())
720 , fColorFilters(colorFilters.begin(), colorFilters.end()) {
721 fNumShaderCombos = 0;
722 for (const auto& s : fShaders) {
723 fNumShaderCombos += s->priv().numCombinations();
724 }
725 fNumColorFilterCombos = 0;
726 for (const auto& cf : fColorFilters) {
727 fNumColorFilterCombos += cf->priv().numCombinations();
728 }
729 }
730
731 private:
numChildCombinations() const732 int numChildCombinations() const override { return fNumShaderCombos * fNumColorFilterCombos; }
733
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const734 void addToKey(const KeyContext& keyContext,
735 PaintParamsKeyBuilder* builder,
736 PipelineDataGatherer* gatherer,
737 int desiredCombination) const override {
738 SkASSERT(desiredCombination < this->numCombinations());
739
740 int desiredShaderCombination = desiredCombination % fNumShaderCombos;
741 int desiredColorFilterCombination = desiredCombination / fNumShaderCombos;
742 SkASSERT(desiredColorFilterCombination < fNumColorFilterCombos);
743
744 Compose(keyContext, builder, gatherer,
745 /* addInnerToKey= */ [&]() -> void {
746 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
747 desiredShaderCombination);
748 },
749 /* addOuterToKey= */ [&]() -> void {
750 AddToKey<PrecompileColorFilter>(keyContext, builder, gatherer, fColorFilters,
751 desiredColorFilterCombination);
752 });
753 }
754
755 std::vector<sk_sp<PrecompileShader>> fShaders;
756 std::vector<sk_sp<PrecompileColorFilter>> fColorFilters;
757 int fNumShaderCombos;
758 int fNumColorFilterCombos;
759 };
760
ColorFilter(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)761 sk_sp<PrecompileShader> PrecompileShaders::ColorFilter(
762 SkSpan<const sk_sp<PrecompileShader>> shaders,
763 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters) {
764 return sk_make_sp<PrecompileColorFilterShader>(std::move(shaders), std::move(colorFilters));
765 }
766
767 //--------------------------------------------------------------------------------------------------
768 class PrecompileWorkingColorSpaceShader final : public PrecompileShader {
769 public:
PrecompileWorkingColorSpaceShader(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<SkColorSpace>> colorSpaces)770 PrecompileWorkingColorSpaceShader(SkSpan<const sk_sp<PrecompileShader>> shaders,
771 SkSpan<const sk_sp<SkColorSpace>> colorSpaces)
772 : fShaders(shaders.begin(), shaders.end())
773 , fColorSpaces(colorSpaces.begin(), colorSpaces.end()) {
774 fNumShaderCombos = 0;
775 for (const auto& s : fShaders) {
776 fNumShaderCombos += s->priv().numCombinations();
777 }
778 }
779
780 private:
numChildCombinations() const781 int numChildCombinations() const override { return fNumShaderCombos * fColorSpaces.size(); }
782
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const783 void addToKey(const KeyContext& keyContext,
784 PaintParamsKeyBuilder* builder,
785 PipelineDataGatherer* gatherer,
786 int desiredCombination) const override {
787 SkASSERT(desiredCombination < this->numCombinations());
788
789 int desiredShaderCombination = desiredCombination % fNumShaderCombos;
790 int desiredColorSpaceCombination = desiredCombination / fNumShaderCombos;
791 SkASSERT(desiredColorSpaceCombination < (int) fColorSpaces.size());
792
793 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
794 const SkAlphaType dstAT = dstInfo.alphaType();
795 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
796 if (!dstCS) {
797 dstCS = SkColorSpace::MakeSRGB();
798 }
799
800 sk_sp<SkColorSpace> workingCS = fColorSpaces[desiredColorSpaceCombination];
801 SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
802 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
803
804 Compose(keyContext, builder, gatherer,
805 /* addInnerToKey= */ [&]() -> void {
806 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
807 desiredShaderCombination);
808 },
809 /* addOuterToKey= */ [&]() -> void {
810 ColorSpaceTransformBlock::ColorSpaceTransformData data(
811 workingCS.get(), dstAT, dstCS.get(), dstAT);
812 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
813 });
814 }
815
816 std::vector<sk_sp<PrecompileShader>> fShaders;
817 std::vector<sk_sp<SkColorSpace>> fColorSpaces;
818 int fNumShaderCombos;
819 };
820
WorkingColorSpace(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<SkColorSpace>> colorSpaces)821 sk_sp<PrecompileShader> PrecompileShaders::WorkingColorSpace(
822 SkSpan<const sk_sp<PrecompileShader>> shaders,
823 SkSpan<const sk_sp<SkColorSpace>> colorSpaces) {
824 return sk_make_sp<PrecompileWorkingColorSpaceShader>(std::move(shaders),
825 std::move(colorSpaces));
826 }
827
828 //--------------------------------------------------------------------------------------------------
829 // In Graphite this acts as a non-elidable LocalMatrixShader
830 class PrecompileCTMShader final : public PrecompileShader {
831 public:
PrecompileCTMShader(SkSpan<const sk_sp<PrecompileShader>> wrapped)832 PrecompileCTMShader(SkSpan<const sk_sp<PrecompileShader>> wrapped)
833 : fWrapped(wrapped.begin(), wrapped.end()) {
834 fNumWrappedCombos = 0;
835 for (const auto& s : fWrapped) {
836 fNumWrappedCombos += s->priv().numCombinations();
837 }
838 }
839
isConstant(int desiredCombination) const840 bool isConstant(int desiredCombination) const override {
841 SkASSERT(desiredCombination < fNumWrappedCombos);
842
843 std::pair<sk_sp<PrecompileShader>, int> wrapped =
844 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredCombination);
845 if (wrapped.first) {
846 return wrapped.first->priv().isConstant(wrapped.second);
847 }
848
849 return false;
850 }
851
852 private:
numChildCombinations() const853 int numChildCombinations() const override { return fNumWrappedCombos; }
854
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const855 void addToKey(const KeyContext& keyContext,
856 PaintParamsKeyBuilder* builder,
857 PipelineDataGatherer* gatherer,
858 int desiredCombination) const override {
859 SkASSERT(desiredCombination < fNumWrappedCombos);
860
861 LocalMatrixShaderBlock::LMShaderData kIgnoredLMShaderData(SkMatrix::I());
862
863 LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, kIgnoredLMShaderData);
864
865 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped, desiredCombination);
866
867 builder->endBlock();
868 }
869
870 std::vector<sk_sp<PrecompileShader>> fWrapped;
871 int fNumWrappedCombos;
872 };
873
CTM(SkSpan<const sk_sp<PrecompileShader>> wrapped)874 sk_sp<PrecompileShader> PrecompileShadersPriv::CTM(SkSpan<const sk_sp<PrecompileShader>> wrapped) {
875 return sk_make_sp<PrecompileCTMShader>(std::move(wrapped));
876 }
877
878 //--------------------------------------------------------------------------------------------------
879 class PrecompileBlurShader final : public PrecompileShader {
880 public:
PrecompileBlurShader(sk_sp<PrecompileShader> wrapped)881 PrecompileBlurShader(sk_sp<PrecompileShader> wrapped)
882 : fWrapped(std::move(wrapped)) {
883 fNumWrappedCombos = fWrapped->priv().numCombinations();
884 }
885
886 private:
887 // 6 known 1D blur effects + 6 known 2D blur effects
888 inline static constexpr int kNumIntrinsicCombinations = 12;
889
numIntrinsicCombinations() const890 int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
891
numChildCombinations() const892 int numChildCombinations() const override { return fNumWrappedCombos; }
893
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const894 void addToKey(const KeyContext& keyContext,
895 PaintParamsKeyBuilder* builder,
896 PipelineDataGatherer* gatherer,
897 int desiredCombination) const override {
898 SkASSERT(desiredCombination < this->numCombinations());
899
900 using namespace SkKnownRuntimeEffects;
901
902 int desiredBlurCombination = desiredCombination % kNumIntrinsicCombinations;
903 int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
904 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
905
906 static const StableKey kIDs[kNumIntrinsicCombinations] = {
907 StableKey::k1DBlur4, StableKey::k1DBlur8, StableKey::k1DBlur12,
908 StableKey::k1DBlur16, StableKey::k1DBlur20, StableKey::k1DBlur28,
909
910 StableKey::k2DBlur4, StableKey::k2DBlur8, StableKey::k2DBlur12,
911 StableKey::k2DBlur16, StableKey::k2DBlur20, StableKey::k2DBlur28,
912 };
913
914 const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(kIDs[desiredBlurCombination]);
915
916 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
917
918 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
919 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
920 builder->endBlock();
921 }
922
923 sk_sp<PrecompileShader> fWrapped;
924 int fNumWrappedCombos;
925 };
926
Blur(sk_sp<PrecompileShader> wrapped)927 sk_sp<PrecompileShader> PrecompileShadersPriv::Blur(sk_sp<PrecompileShader> wrapped) {
928 return sk_make_sp<PrecompileBlurShader>(std::move(wrapped));
929 }
930
931 //--------------------------------------------------------------------------------------------------
932 class PrecompileMatrixConvolutionShader final : public PrecompileShader {
933 public:
PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)934 PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)
935 : fWrapped(std::move(wrapped)) {
936 fNumWrappedCombos = fWrapped->priv().numCombinations();
937
938 // When the matrix convolution ImageFilter uses a texture we know it will only ever
939 // be SkFilterMode::kNearest and SkTileMode::kClamp.
940 // TODO: add a PrecompileImageShaderFlags to further limit the raw image shader
941 // combinations. Right now we're getting two combinations for the raw shader
942 // (sk_image_shader and sk_hw_image_shader).
943 fRawImageShader =
944 PrecompileShadersPriv::RawImage(PrecompileImageShaderFlags::kExcludeCubic);
945 fNumRawImageShaderCombos = fRawImageShader->priv().numCombinations();
946 }
947
948 private:
numIntrinsicCombinations() const949 int numIntrinsicCombinations() const override {
950 // The uniform version only has one option but the two texture-based versions will
951 // have as many combinations as the raw image shader.
952 return 1 + 2 * fNumRawImageShaderCombos;
953 }
954
numChildCombinations() const955 int numChildCombinations() const override { return fNumWrappedCombos; }
956
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const957 void addToKey(const KeyContext& keyContext,
958 PaintParamsKeyBuilder* builder,
959 PipelineDataGatherer* gatherer,
960 int desiredCombination) const override {
961
962 int desiredTextureCombination = 0;
963
964 const int desiredWrappedCombination = desiredCombination % fNumWrappedCombos;
965 int remainingCombinations = desiredCombination / fNumWrappedCombos;
966
967 SkKnownRuntimeEffects::StableKey stableKey = SkKnownRuntimeEffects::StableKey::kInvalid;
968 if (remainingCombinations == 0) {
969 stableKey = SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms;
970 } else {
971 static constexpr SkKnownRuntimeEffects::StableKey kTextureBasedStableKeys[] = {
972 SkKnownRuntimeEffects::StableKey::kMatrixConvTexSm,
973 SkKnownRuntimeEffects::StableKey::kMatrixConvTexLg,
974 };
975
976 --remainingCombinations;
977 stableKey = kTextureBasedStableKeys[remainingCombinations % 2];
978 desiredTextureCombination = remainingCombinations / 2;
979 SkASSERT(desiredTextureCombination < fNumRawImageShaderCombos);
980 }
981
982 const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(stableKey);
983
984 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
985
986 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
987 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
988 if (stableKey != SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms) {
989 fRawImageShader->priv().addToKey(childContext, builder, gatherer,
990 desiredTextureCombination);
991 }
992 builder->endBlock();
993 }
994
995 sk_sp<PrecompileShader> fWrapped;
996 int fNumWrappedCombos;
997 sk_sp<PrecompileShader> fRawImageShader;
998 int fNumRawImageShaderCombos;
999 };
1000
MatrixConvolution(sk_sp<skgpu::graphite::PrecompileShader> wrapped)1001 sk_sp<PrecompileShader> PrecompileShadersPriv::MatrixConvolution(
1002 sk_sp<skgpu::graphite::PrecompileShader> wrapped) {
1003 return sk_make_sp<PrecompileMatrixConvolutionShader>(std::move(wrapped));
1004 }
1005
1006 //--------------------------------------------------------------------------------------------------
1007 class PrecompileMorphologyShader final : public PrecompileShader {
1008 public:
PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,SkKnownRuntimeEffects::StableKey stableKey)1009 PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,
1010 SkKnownRuntimeEffects::StableKey stableKey)
1011 : fWrapped(std::move(wrapped))
1012 , fStableKey(stableKey) {
1013 fNumWrappedCombos = fWrapped->priv().numCombinations();
1014 SkASSERT(stableKey == SkKnownRuntimeEffects::StableKey::kLinearMorphology ||
1015 stableKey == SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1016 }
1017
1018 private:
numChildCombinations() const1019 int numChildCombinations() const override { return fNumWrappedCombos; }
1020
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1021 void addToKey(const KeyContext& keyContext,
1022 PaintParamsKeyBuilder* builder,
1023 PipelineDataGatherer* gatherer,
1024 int desiredCombination) const override {
1025 SkASSERT(desiredCombination < fNumWrappedCombos);
1026
1027 const SkRuntimeEffect* effect = GetKnownRuntimeEffect(fStableKey);
1028
1029 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1030
1031 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
1032 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1033 builder->endBlock();
1034 }
1035
1036 sk_sp<PrecompileShader> fWrapped;
1037 int fNumWrappedCombos;
1038 SkKnownRuntimeEffects::StableKey fStableKey;
1039 };
1040
LinearMorphology(sk_sp<PrecompileShader> wrapped)1041 sk_sp<PrecompileShader> PrecompileShadersPriv::LinearMorphology(sk_sp<PrecompileShader> wrapped) {
1042 return sk_make_sp<PrecompileMorphologyShader>(
1043 std::move(wrapped),
1044 SkKnownRuntimeEffects::StableKey::kLinearMorphology);
1045 }
1046
SparseMorphology(sk_sp<PrecompileShader> wrapped)1047 sk_sp<PrecompileShader> PrecompileShadersPriv::SparseMorphology(sk_sp<PrecompileShader> wrapped) {
1048 return sk_make_sp<PrecompileMorphologyShader>(
1049 std::move(wrapped),
1050 SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1051 }
1052
1053 //--------------------------------------------------------------------------------------------------
1054 class PrecompileDisplacementShader final : public PrecompileShader {
1055 public:
PrecompileDisplacementShader(sk_sp<PrecompileShader> displacement,sk_sp<PrecompileShader> color)1056 PrecompileDisplacementShader(sk_sp<PrecompileShader> displacement,
1057 sk_sp<PrecompileShader> color)
1058 : fDisplacement(std::move(displacement))
1059 , fColor(std::move(color)) {
1060 fNumDisplacementCombos = fDisplacement->priv().numCombinations();
1061 fNumColorCombos = fColor->priv().numCombinations();
1062 }
1063
1064 private:
numChildCombinations() const1065 int numChildCombinations() const override { return fNumDisplacementCombos * fNumColorCombos; }
1066
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1067 void addToKey(const KeyContext& keyContext,
1068 PaintParamsKeyBuilder* builder,
1069 PipelineDataGatherer* gatherer,
1070 int desiredCombination) const override {
1071 SkASSERT(desiredCombination < this->numChildCombinations());
1072
1073 const int desiredDisplacementCombination = desiredCombination % fNumDisplacementCombos;
1074 const int desiredColorCombination = desiredCombination / fNumDisplacementCombos;
1075 SkASSERT(desiredColorCombination < fNumColorCombos);
1076
1077 const SkRuntimeEffect* fEffect =
1078 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kDisplacement);
1079
1080 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1081
1082 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
1083 fDisplacement->priv().addToKey(childContext, builder, gatherer,
1084 desiredDisplacementCombination);
1085 fColor->priv().addToKey(childContext, builder, gatherer,
1086 desiredColorCombination);
1087 builder->endBlock();
1088 }
1089
1090 sk_sp<PrecompileShader> fDisplacement;
1091 int fNumDisplacementCombos;
1092 sk_sp<PrecompileShader> fColor;
1093 int fNumColorCombos;
1094 };
1095
1096 //--------------------------------------------------------------------------------------------------
Displacement(sk_sp<PrecompileShader> displacement,sk_sp<PrecompileShader> color)1097 sk_sp<PrecompileShader> PrecompileShadersPriv::Displacement(sk_sp<PrecompileShader> displacement,
1098 sk_sp<PrecompileShader> color) {
1099 return sk_make_sp<PrecompileDisplacementShader>(std::move(displacement), std::move(color));
1100 }
1101
1102 //--------------------------------------------------------------------------------------------------
1103 class PrecompileLightingShader final : public PrecompileShader {
1104 public:
PrecompileLightingShader(sk_sp<PrecompileShader> wrapped)1105 PrecompileLightingShader(sk_sp<PrecompileShader> wrapped)
1106 : fWrapped(std::move(wrapped)) {
1107 fNumWrappedCombos = fWrapped->priv().numCombinations();
1108 }
1109
1110 private:
numChildCombinations() const1111 int numChildCombinations() const override { return fNumWrappedCombos; }
1112
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1113 void addToKey(const KeyContext& keyContext,
1114 PaintParamsKeyBuilder* builder,
1115 PipelineDataGatherer* gatherer,
1116 int desiredCombination) const override {
1117 SkASSERT(desiredCombination < fNumWrappedCombos);
1118
1119 const SkRuntimeEffect* normalEffect =
1120 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kNormal);
1121 const SkRuntimeEffect* lightingEffect =
1122 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kLighting);
1123
1124 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1125
1126 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1127 { sk_ref_sp(lightingEffect) });
1128 RuntimeEffectBlock::BeginBlock(childContext, builder, gatherer,
1129 { sk_ref_sp(normalEffect) });
1130 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1131 builder->endBlock();
1132 builder->endBlock();
1133 }
1134
1135 sk_sp<PrecompileShader> fWrapped;
1136 int fNumWrappedCombos;
1137 };
1138
Lighting(sk_sp<PrecompileShader> wrapped)1139 sk_sp<PrecompileShader> PrecompileShadersPriv::Lighting(sk_sp<PrecompileShader> wrapped) {
1140 return sk_make_sp<PrecompileLightingShader>(std::move(wrapped));
1141 }
1142
1143 //--------------------------------------------------------------------------------------------------
1144
1145 } // namespace skgpu::graphite
1146