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/SkImageInfoPriv.h"
16 #include "src/core/SkKnownRuntimeEffects.h"
17 #include "src/gpu/Blend.h"
18 #include "src/gpu/graphite/BuiltInCodeSnippetID.h"
19 #include "src/gpu/graphite/KeyContext.h"
20 #include "src/gpu/graphite/KeyHelpers.h"
21 #include "src/gpu/graphite/PaintParams.h"
22 #include "src/gpu/graphite/PaintParamsKey.h"
23 #include "src/gpu/graphite/PrecompileInternal.h"
24 #include "src/gpu/graphite/ReadSwizzle.h"
25 #include "src/gpu/graphite/RecorderPriv.h"
26 #include "src/gpu/graphite/precompile/PrecompileBaseComplete.h"
27 #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
28 #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
29 #include "src/gpu/graphite/precompile/PrecompileShaderPriv.h"
30 #include "src/gpu/graphite/precompile/PrecompileShadersPriv.h"
31 #include "src/shaders/gradients/SkLinearGradient.h"
32
33 namespace skgpu::graphite {
34
35 PrecompileShader::~PrecompileShader() = default;
36
makeWithColorFilter(sk_sp<PrecompileColorFilter> cf) const37 sk_sp<PrecompileShader> PrecompileShader::makeWithColorFilter(
38 sk_sp<PrecompileColorFilter> cf) const {
39 if (!cf) {
40 return sk_ref_sp(this);
41 }
42
43 return PrecompileShaders::ColorFilter({ sk_ref_sp(this) }, { std::move(cf) });
44 }
45
makeWithWorkingColorSpace(sk_sp<SkColorSpace> cs) const46 sk_sp<PrecompileShader> PrecompileShader::makeWithWorkingColorSpace(sk_sp<SkColorSpace> cs) const {
47 if (!cs) {
48 return sk_ref_sp(this);
49 }
50
51 return PrecompileShaders::WorkingColorSpace({ sk_ref_sp(this) }, { std::move(cs) });
52 }
53
54 //--------------------------------------------------------------------------------------------------
55 class PrecompileEmptyShader final : public PrecompileShader {
56 private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const57 void addToKey(const KeyContext& keyContext,
58 PaintParamsKeyBuilder* builder,
59 PipelineDataGatherer* gatherer,
60 int desiredCombination) const override {
61
62 SkASSERT(desiredCombination == 0); // The empty shader only ever has one combination
63
64 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
65 }
66 };
67
Empty()68 sk_sp<PrecompileShader> PrecompileShaders::Empty() {
69 return sk_make_sp<PrecompileEmptyShader>();
70 }
71
72 //--------------------------------------------------------------------------------------------------
73 class PrecompileColorShader final : public PrecompileShader {
74 private:
isConstant(int desiredCombination) const75 bool isConstant(int desiredCombination) const override {
76 SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
77 return true;
78 }
79
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const80 void addToKey(const KeyContext& keyContext,
81 PaintParamsKeyBuilder* builder,
82 PipelineDataGatherer* gatherer,
83 int desiredCombination) const override {
84
85 SkASSERT(desiredCombination == 0); // The color shader only ever has one combination
86
87 // The white PMColor is just a placeholder for the actual paint params color
88 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, SK_PMColor4fWHITE);
89 }
90 };
91
Color()92 sk_sp<PrecompileShader> PrecompileShaders::Color() {
93 return sk_make_sp<PrecompileColorShader>();
94 }
95
96 // The colorSpace is safe to ignore - it is just applied to the color and doesn't modify the
97 // generated program.
Color(sk_sp<SkColorSpace>)98 sk_sp<PrecompileShader> PrecompileShaders::Color(sk_sp<SkColorSpace>) {
99 return sk_make_sp<PrecompileColorShader>();
100 }
101
102 //--------------------------------------------------------------------------------------------------
103 class PrecompileBlendShader final : public PrecompileShader {
104 public:
PrecompileBlendShader(PrecompileBlenderList && blenders,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)105 PrecompileBlendShader(PrecompileBlenderList&& blenders,
106 SkSpan<const sk_sp<PrecompileShader>> dsts,
107 SkSpan<const sk_sp<PrecompileShader>> srcs)
108 : fBlenderOptions(std::move(blenders))
109 , fDstOptions(dsts.begin(), dsts.end())
110 , fSrcOptions(srcs.begin(), srcs.end()) {
111 fNumDstCombos = 0;
112 for (const auto& d : fDstOptions) {
113 fNumDstCombos += d->priv().numCombinations();
114 }
115
116 fNumSrcCombos = 0;
117 for (const auto& s : fSrcOptions) {
118 fNumSrcCombos += s->priv().numCombinations();
119 }
120 }
121
122 private:
numChildCombinations() const123 int numChildCombinations() const override {
124 return fBlenderOptions.numCombinations() * fNumDstCombos * fNumSrcCombos;
125 }
126
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const127 void addToKey(const KeyContext& keyContext,
128 PaintParamsKeyBuilder* builder,
129 PipelineDataGatherer* gatherer,
130 int desiredCombination) const override {
131 SkASSERT(desiredCombination < this->numCombinations());
132
133 const int desiredDstCombination = desiredCombination % fNumDstCombos;
134 int remainingCombinations = desiredCombination / fNumDstCombos;
135
136 const int desiredSrcCombination = remainingCombinations % fNumSrcCombos;
137 remainingCombinations /= fNumSrcCombos;
138
139 int desiredBlendCombination = remainingCombinations;
140 SkASSERT(desiredBlendCombination < fBlenderOptions.numCombinations());
141
142 auto [blender, blenderCombination] = fBlenderOptions.selectOption(desiredBlendCombination);
143 if (blender->priv().asBlendMode()) {
144 // Coefficient and HSLC blends, and other fixed SkBlendMode blenders use the
145 // BlendCompose block to organize the children.
146 BlendComposeBlock::BeginBlock(keyContext, builder, gatherer);
147 } else {
148 // Runtime blenders are wrapped in the kBlend runtime shader, although functionally
149 // it is identical to the BlendCompose snippet.
150 const SkRuntimeEffect* blendEffect =
151 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kBlend);
152
153 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
154 { sk_ref_sp(blendEffect) });
155 }
156
157 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fSrcOptions,
158 desiredSrcCombination);
159 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fDstOptions,
160 desiredDstCombination);
161
162 if (blender->priv().asBlendMode()) {
163 SkASSERT(blenderCombination == 0);
164 AddBlendMode(keyContext, builder, gatherer, *blender->priv().asBlendMode());
165 } else {
166 blender->priv().addToKey(keyContext, builder, gatherer, blenderCombination);
167 }
168
169 builder->endBlock(); // BlendComposeBlock or RuntimeEffectBlock
170 }
171
172 PrecompileBlenderList fBlenderOptions;
173 std::vector<sk_sp<PrecompileShader>> fDstOptions;
174 std::vector<sk_sp<PrecompileShader>> fSrcOptions;
175
176 int fNumDstCombos;
177 int fNumSrcCombos;
178 };
179
Blend(SkSpan<const sk_sp<PrecompileBlender>> blenders,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)180 sk_sp<PrecompileShader> PrecompileShaders::Blend(
181 SkSpan<const sk_sp<PrecompileBlender>> blenders,
182 SkSpan<const sk_sp<PrecompileShader>> dsts,
183 SkSpan<const sk_sp<PrecompileShader>> srcs) {
184 return sk_make_sp<PrecompileBlendShader>(PrecompileBlenderList(blenders), dsts, srcs);
185 }
186
Blend(SkSpan<const SkBlendMode> blendModes,SkSpan<const sk_sp<PrecompileShader>> dsts,SkSpan<const sk_sp<PrecompileShader>> srcs)187 sk_sp<PrecompileShader> PrecompileShaders::Blend(
188 SkSpan<const SkBlendMode> blendModes,
189 SkSpan<const sk_sp<PrecompileShader>> dsts,
190 SkSpan<const sk_sp<PrecompileShader>> srcs) {
191 return sk_make_sp<PrecompileBlendShader>(PrecompileBlenderList(blendModes), dsts, srcs);
192 }
193
194 //--------------------------------------------------------------------------------------------------
195 class PrecompileCoordClampShader final : public PrecompileShader {
196 public:
PrecompileCoordClampShader(SkSpan<const sk_sp<PrecompileShader>> shaders)197 PrecompileCoordClampShader(SkSpan<const sk_sp<PrecompileShader>> shaders)
198 : fShaders(shaders.begin(), shaders.end()) {
199 fNumShaderCombos = 0;
200 for (const auto& s : fShaders) {
201 fNumShaderCombos += s->priv().numCombinations();
202 }
203 }
204
205 private:
numChildCombinations() const206 int numChildCombinations() const override {
207 return fNumShaderCombos;
208 }
209
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const210 void addToKey(const KeyContext& keyContext,
211 PaintParamsKeyBuilder* builder,
212 PipelineDataGatherer* gatherer,
213 int desiredCombination) const override {
214 SkASSERT(desiredCombination < fNumShaderCombos);
215
216 constexpr SkRect kIgnored { 0, 0, 256, 256 }; // ignored bc we're precompiling
217
218 // TODO: update CoordClampShaderBlock so this is optional
219 CoordClampShaderBlock::CoordClampData data(kIgnored);
220
221 CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
222 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders, desiredCombination);
223 builder->endBlock();
224 }
225
226 std::vector<sk_sp<PrecompileShader>> fShaders;
227 int fNumShaderCombos;
228 };
229
CoordClamp(SkSpan<const sk_sp<PrecompileShader>> input)230 sk_sp<PrecompileShader> PrecompileShaders::CoordClamp(SkSpan<const sk_sp<PrecompileShader>> input) {
231 return sk_make_sp<PrecompileCoordClampShader>(input);
232 }
233
234 //--------------------------------------------------------------------------------------------------
235 class PrecompileImageShader final : public PrecompileShader {
236 public:
PrecompileImageShader(SkEnumBitMask<PrecompileImageShaderFlags> flags,SkSpan<const SkColorInfo> colorInfos,SkSpan<const SkTileMode> tileModes,bool raw)237 PrecompileImageShader(SkEnumBitMask<PrecompileImageShaderFlags> flags,
238 SkSpan<const SkColorInfo> colorInfos,
239 SkSpan<const SkTileMode> tileModes,
240 bool raw)
241 : fNumExtraSamplingTilingCombos((flags & PrecompileImageShaderFlags::kExcludeCubic)
242 ? 1 // Just kHWTiled
243 : kExtraNumSamplingTilingCombos)
244 , fColorInfos(!colorInfos.empty()
245 ? std::vector<SkColorInfo>(colorInfos.begin(), colorInfos.end())
246 : raw ? RawImageDefaultColorInfos()
247 : (flags & PrecompileImageShaderFlags::kExcludeAlpha)
248 ? NonAlphaOnlyDefaultColorInfos()
249 : DefaultColorInfos())
250 , fTileModes(!tileModes.empty()
251 ? std::vector<SkTileMode>(tileModes.begin(), tileModes.end())
252 : DefaultTileModes())
253 , fUseDstColorSpace(!colorInfos.empty())
254 , fRaw(raw) {}
255
256 private:
257 // In addition to the tile mode options provided by the client, we can precompile two additional
258 // sampling/tiling variants: hardware-tiled and cubic sampling (which always uses the most
259 // generic tiling shader).
260 inline static constexpr int kExtraNumSamplingTilingCombos = 2;
261 inline static constexpr int kCubicSampled = 1;
262 inline static constexpr int kHWTiled = 0;
263
264 // These color info objects are defined assuming an sRGB destination.
265 // Most specialized color space transform shader, no actual color space handling.
DefaultColorInfoPremul()266 static SkColorInfo DefaultColorInfoPremul() {
267 return { kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB() };
268 }
269 // sRGB-to-sRGB specialized color space transform shader.
DefaultColorInfoSRGB()270 static SkColorInfo DefaultColorInfoSRGB() {
271 return { kRGBA_8888_SkColorType, kPremul_SkAlphaType,
272 sk_srgb_singleton()->makeColorSpin() };
273 }
274 // Most general color space transform shader.
DefaultColorInfoGeneral()275 static SkColorInfo DefaultColorInfoGeneral() {
276 return { kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear() };
277 }
278 // Alpha-only, most general color space transform shader.
DefaultColorInfoAlphaOnly()279 static SkColorInfo DefaultColorInfoAlphaOnly() {
280 return { kAlpha_8_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear() };
281 }
282
283 // A fixed list of SkColorInfos that will trigger each possible combination of alpha-only
284 // handling and color space transform variants, when drawn to an sRGB destination.
DefaultColorInfos()285 static std::vector<SkColorInfo> DefaultColorInfos() {
286 return { DefaultColorInfoPremul(), DefaultColorInfoSRGB(), DefaultColorInfoGeneral(),
287 DefaultColorInfoAlphaOnly() };
288 }
289 // A fixed list of SkColorInfos that will trigger each color space transform shader variant when
290 // drawn to an sRGB destination.
NonAlphaOnlyDefaultColorInfos()291 static std::vector<SkColorInfo> NonAlphaOnlyDefaultColorInfos() {
292 return { DefaultColorInfoPremul(), DefaultColorInfoSRGB(), DefaultColorInfoGeneral() };
293 }
294 // A fixed list of SkColorInfos that will trigger each color space transform shader variant
295 // possible from a raw image draw. The general shader is still required if the image is
296 // alpha-only, because the read swizzle is implemented as a gamut transformation.
RawImageDefaultColorInfos()297 static std::vector<SkColorInfo> RawImageDefaultColorInfos() {
298 return { DefaultColorInfoPremul(), DefaultColorInfoAlphaOnly() };
299 }
300
301 // A fixed list of SkTileModes that will trigger each tiling shader variant.
DefaultTileModes()302 static std::vector<SkTileMode> DefaultTileModes() {
303 return { SkTileMode::kClamp, SkTileMode::kRepeat };
304 }
305
306 const int fNumExtraSamplingTilingCombos;
307
308 const std::vector<SkColorInfo> fColorInfos;
309 const std::vector<SkTileMode> fTileModes;
310
311 // If true, use the destination color space from the KeyContext provided to addToKey.
312 // This is true if and only if the client has provided a list of color infos. Otherwise, we
313 // always use an sRGB destination per the default SkColorInfo lists defined above.
314 const bool fUseDstColorSpace;
315
316 // Whether this precompiles raw image shaders.
317 const bool fRaw;
318
numIntrinsicCombinations() const319 int numIntrinsicCombinations() const override {
320 // TODO(b/400682634) If color infos were provided by the client, and we're using the
321 // destination color space to determine what color space transform shaders to use, we can
322 // end up generating duplicate shaders, and the actual number of unique shaders generated
323 // will be less than the number calculated here.
324 return fColorInfos.size() * (fTileModes.size() + fNumExtraSamplingTilingCombos);
325 }
326
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const327 void addToKey(const KeyContext& keyContext,
328 PaintParamsKeyBuilder* builder,
329 PipelineDataGatherer* gatherer,
330 int desiredCombination) const override {
331 SkASSERT(this->numChildCombinations() == 1);
332 SkASSERT(desiredCombination < this->numIntrinsicCombinations());
333
334 const int numSamplingTilingCombos = fTileModes.size() + fNumExtraSamplingTilingCombos;
335 const int desiredSamplingTilingCombo = desiredCombination % numSamplingTilingCombos;
336 desiredCombination /= numSamplingTilingCombos;
337
338 const int desiredColorInfo = desiredCombination;
339 SkASSERT(desiredColorInfo < static_cast<int>(fColorInfos.size()));
340
341 static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
342 static constexpr SkSamplingOptions kDefaultSampling;
343
344 // ImageShaderBlock will use hardware tiling when the subset covers the entire image, so we
345 // create subset + image size combinations where subset == imgSize (for a shader that uses
346 // hardware tiling) and subset < imgSize (for a shader that does shader-based tiling).
347 static constexpr SkRect kSubset = SkRect::MakeWH(1.0f, 1.0f);
348 static constexpr SkISize kHWTileableSize = SkISize::Make(1, 1);
349 static constexpr SkISize kShaderTileableSize = SkISize::Make(2, 2);
350
351 const int numTileModes = fTileModes.size();
352 const SkTileMode tileMode = (desiredSamplingTilingCombo < numTileModes)
353 ? fTileModes[desiredSamplingTilingCombo]
354 : SkTileMode::kClamp;
355 const SkISize imgSize = (desiredSamplingTilingCombo >= numTileModes &&
356 desiredSamplingTilingCombo - numTileModes == kHWTiled)
357 ? kHWTileableSize
358 : kShaderTileableSize;
359 const SkSamplingOptions sampling =
360 (desiredSamplingTilingCombo >= numTileModes &&
361 desiredSamplingTilingCombo - numTileModes == kCubicSampled)
362 ? kDefaultCubicSampling
363 : kDefaultSampling;
364
365 const ImageShaderBlock::ImageData imgData(sampling, tileMode, tileMode, imgSize, kSubset);
366
367 const SkColorInfo& colorInfo = fColorInfos[desiredColorInfo];
368 const bool alphaOnly = SkColorTypeIsAlphaOnly(colorInfo.colorType());
369
370 const Caps* caps = keyContext.caps();
371 Swizzle readSwizzle = caps->getReadSwizzle(
372 colorInfo.colorType(),
373 caps->getDefaultSampledTextureInfo(
374 colorInfo.colorType(), Mipmapped::kNo, Protected::kNo, Renderable::kNo));
375 if (alphaOnly) {
376 readSwizzle = Swizzle::Concat(readSwizzle, Swizzle("000a"));
377 }
378
379 ColorSpaceTransformBlock::ColorSpaceTransformData colorXformData(
380 SwizzleClassToReadEnum(readSwizzle));
381
382 if (!fRaw) {
383 const SkColorSpace* dstColorSpace = fUseDstColorSpace
384 ? keyContext.dstColorInfo().colorSpace()
385 : sk_srgb_singleton();
386 colorXformData.fSteps = SkColorSpaceXformSteps(
387 colorInfo.colorSpace(), colorInfo.alphaType(),
388 dstColorSpace, colorInfo.alphaType());
389
390 if (alphaOnly) {
391 Blend(keyContext, builder, gatherer,
392 /* addBlendToKey= */ [&] () -> void {
393 AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kDstIn);
394 },
395 /* addSrcToKey= */ [&] () -> void {
396 Compose(keyContext, builder, gatherer,
397 /* addInnerToKey= */ [&]() -> void {
398 ImageShaderBlock::AddBlock(keyContext, builder, gatherer,
399 imgData);
400 },
401 /* addOuterToKey= */ [&]() -> void {
402 ColorSpaceTransformBlock::AddBlock(keyContext, builder,
403 gatherer, colorXformData);
404 });
405 },
406 /* addDstToKey= */ [&]() -> void {
407 RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
408 });
409 return;
410 }
411 }
412
413 Compose(keyContext, builder, gatherer,
414 /* addInnerToKey= */ [&]() -> void {
415 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
416 },
417 /* addOuterToKey= */ [&]() -> void {
418 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
419 colorXformData);
420 });
421 }
422 };
423
Image(SkSpan<const SkColorInfo> colorInfos,SkSpan<const SkTileMode> tileModes)424 sk_sp<PrecompileShader> PrecompileShaders::Image(SkSpan<const SkColorInfo> colorInfos,
425 SkSpan<const SkTileMode> tileModes) {
426 return PrecompileShaders::LocalMatrix(
427 { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kNone,
428 colorInfos, tileModes,
429 /* raw= */false) });
430 }
431
RawImage(SkSpan<const SkColorInfo> colorInfos,SkSpan<const SkTileMode> tileModes)432 sk_sp<PrecompileShader> PrecompileShaders::RawImage(SkSpan<const SkColorInfo> colorInfos,
433 SkSpan<const SkTileMode> tileModes) {
434 return PrecompileShaders::LocalMatrix(
435 { sk_make_sp<PrecompileImageShader>(PrecompileImageShaderFlags::kExcludeCubic,
436 colorInfos, tileModes,
437 /* raw= */true) });
438 }
439
Image(SkEnumBitMask<PrecompileImageShaderFlags> flags)440 sk_sp<PrecompileShader> PrecompileShadersPriv::Image(
441 SkEnumBitMask<PrecompileImageShaderFlags> flags) {
442 return PrecompileShaders::LocalMatrix(
443 { sk_make_sp<PrecompileImageShader>(flags,
444 SkSpan<const SkColorInfo>(),
445 SkSpan<const SkTileMode>(),
446 /* raw= */ false) });
447 }
448
RawImage(SkEnumBitMask<PrecompileImageShaderFlags> flags)449 sk_sp<PrecompileShader> PrecompileShadersPriv::RawImage(
450 SkEnumBitMask<PrecompileImageShaderFlags> flags) {
451 return PrecompileShaders::LocalMatrix(
452 { sk_make_sp<PrecompileImageShader>(flags | PrecompileImageShaderFlags::kExcludeCubic,
453 SkSpan<const SkColorInfo>(),
454 SkSpan<const SkTileMode>(),
455 /* raw= */ true) });
456 }
457
458 //--------------------------------------------------------------------------------------------------
459 class PrecompileYUVImageShader : public PrecompileShader {
460 public:
PrecompileYUVImageShader()461 PrecompileYUVImageShader() {}
462
463 private:
464 // There are 12 intrinsic YUV shaders:
465 // 4 tiling modes
466 // HW tiling w/o swizzle
467 // HW tiling w/ swizzle
468 // cubic shader tiling
469 // non-cubic shader tiling
470 // crossed with 3 color space transforms:
471 // premul/alpha-swizzle only
472 // srgb-to-srgb
473 // general transform
474 inline static constexpr int kNumTilingModes = 4;
475 inline static constexpr int kHWTiledNoSwizzle = 3;
476 inline static constexpr int kHWTiledWithSwizzle = 2;
477 inline static constexpr int kCubicShaderTiled = 1;
478 inline static constexpr int kShaderTiled = 0;
479
480 inline static constexpr int kNumColorSpaceCombinations = 3;
481 inline static constexpr int kColorSpacePremul = 2;
482 inline static constexpr int kColorSpaceSRGB = 1;
483 inline static constexpr int kColorSpaceGeneral = 0;
484
485 inline static constexpr int kNumIntrinsicCombinations =
486 kNumTilingModes * kNumColorSpaceCombinations;
487
numIntrinsicCombinations() const488 int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
489
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const490 void addToKey(const KeyContext& keyContext,
491 PaintParamsKeyBuilder* builder,
492 PipelineDataGatherer* gatherer,
493 int desiredCombination) const override {
494 SkASSERT(desiredCombination < kNumIntrinsicCombinations);
495
496 int desiredColorSpaceCombo = desiredCombination % kNumColorSpaceCombinations;
497 int desiredTiling = desiredCombination / kNumColorSpaceCombinations;
498 SkASSERT(desiredTiling < kNumTilingModes);
499
500 static constexpr SkSamplingOptions kDefaultCubicSampling(SkCubicResampler::Mitchell());
501 static constexpr SkSamplingOptions kDefaultSampling;
502
503 YUVImageShaderBlock::ImageData imgData(desiredTiling == kCubicShaderTiled
504 ? kDefaultCubicSampling
505 : kDefaultSampling,
506 SkTileMode::kClamp, SkTileMode::kClamp,
507 /* imgSize= */ { 1, 1 },
508 /* subset= */ desiredTiling == kShaderTiled
509 ? SkRect::MakeEmpty()
510 : SkRect::MakeWH(1, 1));
511
512 static constexpr SkV4 kRedChannel{ 1.f, 0.f, 0.f, 0.f };
513 imgData.fChannelSelect[0] = kRedChannel;
514 imgData.fChannelSelect[1] = kRedChannel;
515 if (desiredTiling == kHWTiledNoSwizzle) {
516 imgData.fChannelSelect[2] = kRedChannel;
517 } else {
518 // Having a non-red channel selector forces a swizzle
519 imgData.fChannelSelect[2] = { 0.f, 1.f, 0.f, 0.f};
520 }
521 imgData.fChannelSelect[3] = kRedChannel;
522
523 imgData.fYUVtoRGBMatrix.setAll(1, 0, 0, 0, 1, 0, 0, 0, 0);
524 imgData.fYUVtoRGBTranslate = { 0, 0, 0 };
525
526 static sk_sp<SkColorSpace> srgbSpinColorSpace = sk_srgb_singleton()->makeColorSpin();
527 const ColorSpaceTransformBlock::ColorSpaceTransformData colorXformData =
528 desiredColorSpaceCombo == kColorSpacePremul
529 ? ColorSpaceTransformBlock::ColorSpaceTransformData(
530 skgpu::graphite::ReadSwizzle::kRGB1) :
531 desiredColorSpaceCombo == kColorSpaceSRGB
532 ? ColorSpaceTransformBlock::ColorSpaceTransformData(
533 sk_srgb_singleton(), kPremul_SkAlphaType,
534 srgbSpinColorSpace.get(), kPremul_SkAlphaType)
535 : ColorSpaceTransformBlock::ColorSpaceTransformData(
536 sk_srgb_singleton(), kPremul_SkAlphaType,
537 sk_srgb_linear_singleton(), kPremul_SkAlphaType);
538 Compose(keyContext, builder, gatherer,
539 /* addInnerToKey= */ [&]() -> void {
540 YUVImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
541 },
542 /* addOuterToKey= */ [&]() -> void {
543 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
544 colorXformData);
545 });
546 }
547 };
548
YUVImage()549 sk_sp<PrecompileShader> PrecompileShaders::YUVImage() {
550 return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileYUVImageShader>() });
551 }
552
553 //--------------------------------------------------------------------------------------------------
554 class PrecompilePerlinNoiseShader final : public PrecompileShader {
555 public:
PrecompilePerlinNoiseShader()556 PrecompilePerlinNoiseShader() {}
557
558 private:
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const559 void addToKey(const KeyContext& keyContext,
560 PaintParamsKeyBuilder* builder,
561 PipelineDataGatherer* gatherer,
562 int desiredCombination) const override {
563
564 SkASSERT(desiredCombination == 0); // The Perlin noise shader only ever has one combination
565
566 // TODO: update PerlinNoiseShaderBlock so the NoiseData is optional
567 static const PerlinNoiseShaderBlock::PerlinNoiseData kIgnoredNoiseData(
568 PerlinNoiseShaderBlock::Type::kFractalNoise, { 0.0f, 0.0f }, 2, {1, 1});
569
570 PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, kIgnoredNoiseData);
571 }
572
573 };
574
MakeFractalNoise()575 sk_sp<PrecompileShader> PrecompileShaders::MakeFractalNoise() {
576 return sk_make_sp<PrecompilePerlinNoiseShader>();
577 }
578
MakeTurbulence()579 sk_sp<PrecompileShader> PrecompileShaders::MakeTurbulence() {
580 return sk_make_sp<PrecompilePerlinNoiseShader>();
581 }
582
583 namespace {
584
get_gradient_intermediate_cs(SkColorSpace * dstColorSpace,SkGradientShader::Interpolation interpolation)585 sk_sp<SkColorSpace> get_gradient_intermediate_cs(SkColorSpace* dstColorSpace,
586 SkGradientShader::Interpolation interpolation) {
587 // Any gradient shader will do, as long as it has the correct interpolation settings.
588 constexpr SkPoint pts[2] = {{0.f, 0.f}, {1.f, 0.f}};
589 constexpr SkColor4f colors[2] = {SkColors::kBlack, SkColors::kWhite};
590 constexpr float pos[2] = {0.f, 1.f};
591 SkLinearGradient shader(pts, {colors, nullptr, pos, 2, SkTileMode::kClamp, interpolation});
592
593 SkColor4fXformer xformedColors(&shader, dstColorSpace);
594 return xformedColors.fIntermediateColorSpace;
595 }
596
597 } // anonymous namespace
598
599 //--------------------------------------------------------------------------------------------------
600 class PrecompileGradientShader final : public PrecompileShader {
601 public:
PrecompileGradientShader(SkShaderBase::GradientType type,const SkGradientShader::Interpolation & interpolation)602 PrecompileGradientShader(SkShaderBase::GradientType type,
603 const SkGradientShader::Interpolation& interpolation)
604 : fType(type), fInterpolation(interpolation) {}
605
606 private:
607 /*
608 * The gradients currently have three specializations based on the number of stops.
609 */
610 inline static constexpr int kNumStopVariants = 3;
611 inline static constexpr int kStopVariants[kNumStopVariants] =
612 { 4, 8, GradientShaderBlocks::GradientData::kNumInternalStorageStops+1 };
613
numIntrinsicCombinations() const614 int numIntrinsicCombinations() const override { return kNumStopVariants; }
615
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const616 void addToKey(const KeyContext& keyContext,
617 PaintParamsKeyBuilder* builder,
618 PipelineDataGatherer* gatherer,
619 int desiredCombination) const override {
620 SkASSERT(this->numChildCombinations() == 1);
621 SkASSERT(desiredCombination < kNumStopVariants);
622
623 bool useStorageBuffer = keyContext.caps()->gradientBufferSupport();
624
625 GradientShaderBlocks::GradientData gradData(fType,
626 kStopVariants[desiredCombination],
627 useStorageBuffer);
628
629 // The logic for setting up color spaces here should match that in the "add_gradient_to_key"
630 // functions from src/gpu/graphite/KeyHelpers.cpp.
631 sk_sp<SkColorSpace> intermediateCS = get_gradient_intermediate_cs(
632 keyContext.dstColorInfo().colorSpace(), fInterpolation);
633 const SkColorSpace* dstCS = keyContext.dstColorInfo().colorSpace()
634 ? keyContext.dstColorInfo().colorSpace()
635 : sk_srgb_singleton();
636
637 ColorSpaceTransformBlock::ColorSpaceTransformData csData(
638 intermediateCS.get(), kPremul_SkAlphaType,
639 dstCS, kPremul_SkAlphaType);
640
641 Compose(keyContext, builder, gatherer,
642 /* addInnerToKey= */ [&]() -> void {
643 GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
644 },
645 /* addOuterToKey= */ [&]() -> void {
646 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
647 });
648 }
649
650 const SkShaderBase::GradientType fType;
651 const SkGradientShader::Interpolation fInterpolation;
652 };
653
LinearGradient(SkGradientShader::Interpolation interpolation)654 sk_sp<PrecompileShader> PrecompileShaders::LinearGradient(
655 SkGradientShader::Interpolation interpolation) {
656 sk_sp<PrecompileShader> s = sk_make_sp<PrecompileGradientShader>(
657 SkShaderBase::GradientType::kLinear, interpolation);
658 return PrecompileShaders::LocalMatrix({ std::move(s) });
659 }
660
RadialGradient(SkGradientShader::Interpolation interpolation)661 sk_sp<PrecompileShader> PrecompileShaders::RadialGradient(
662 SkGradientShader::Interpolation interpolation) {
663 sk_sp<PrecompileShader> s = sk_make_sp<PrecompileGradientShader>(
664 SkShaderBase::GradientType::kRadial, interpolation);
665 return PrecompileShaders::LocalMatrix({ std::move(s) });
666 }
667
SweepGradient(SkGradientShader::Interpolation interpolation)668 sk_sp<PrecompileShader> PrecompileShaders::SweepGradient(
669 SkGradientShader::Interpolation interpolation) {
670 sk_sp<PrecompileShader> s =
671 sk_make_sp<PrecompileGradientShader>(SkShaderBase::GradientType::kSweep, interpolation);
672 return PrecompileShaders::LocalMatrix({ std::move(s) });
673 }
674
TwoPointConicalGradient(SkGradientShader::Interpolation interpolation)675 sk_sp<PrecompileShader> PrecompileShaders::TwoPointConicalGradient(
676 SkGradientShader::Interpolation interpolation) {
677 sk_sp<PrecompileShader> s = sk_make_sp<PrecompileGradientShader>(
678 SkShaderBase::GradientType::kConical, interpolation);
679 return PrecompileShaders::LocalMatrix({ std::move(s) });
680 }
681
682 //--------------------------------------------------------------------------------------------------
683 // The PictureShader ultimately turns into an SkImageShader optionally wrapped in a
684 // LocalMatrixShader.
685 // Note that this means each precompile PictureShader will add 24 combinations:
686 // 2 (pictureshader LM) x 12 (imageShader variations)
Picture()687 sk_sp<PrecompileShader> PrecompileShaders::Picture() {
688 // Note: We don't need to consider the PrecompileYUVImageShader since the image
689 // being drawn was created internally by Skia (as non-YUV).
690 return PrecompileShadersPriv::LocalMatrixBothVariants({ PrecompileShaders::Image() });
691 }
692
Picture(bool withLM)693 sk_sp<PrecompileShader> PrecompileShadersPriv::Picture(bool withLM) {
694 sk_sp<PrecompileShader> s = PrecompileShaders::Image();
695 if (withLM) {
696 return PrecompileShaders::LocalMatrix({ std::move(s) });
697 }
698 return s;
699 }
700
701 //--------------------------------------------------------------------------------------------------
702 // In the main Skia API the SkLocalMatrixShader is optimized away when the LM is the identity
703 // or omitted. The PrecompileLocalMatrixShader captures this by adding two intrinsic options.
704 // One with the LMShader wrapping the child and one without the LMShader.
705 class PrecompileLocalMatrixShader final : public PrecompileShader {
706 public:
707 enum class Flags {
708 kNone = 0b00,
709 kIsPerspective = 0b01,
710 kIncludeWithOutVariant = 0b10,
711 };
712
PrecompileLocalMatrixShader(SkSpan<const sk_sp<PrecompileShader>> wrapped,SkEnumBitMask<Flags> flags=Flags::kNone)713 PrecompileLocalMatrixShader(SkSpan<const sk_sp<PrecompileShader>> wrapped,
714 SkEnumBitMask<Flags> flags = Flags::kNone)
715 : fWrapped(wrapped.begin(), wrapped.end())
716 , fFlags(flags) {
717 fNumWrappedCombos = 0;
718 for (const auto& s : fWrapped) {
719 fNumWrappedCombos += s->priv().numCombinations();
720 }
721 }
722
isConstant(int desiredCombination) const723 bool isConstant(int desiredCombination) const override {
724 SkASSERT(desiredCombination < this->numCombinations());
725
726 /*
727 * Regardless of whether the LocalMatrixShader elides itself or not, we always want
728 * the Constant-ness of the wrapped shader.
729 */
730 int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
731 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
732
733 std::pair<sk_sp<PrecompileShader>, int> wrapped =
734 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredWrappedCombination);
735 if (wrapped.first) {
736 return wrapped.first->priv().isConstant(wrapped.second);
737 }
738
739 return false;
740 }
741
getWrapped() const742 SkSpan<const sk_sp<PrecompileShader>> getWrapped() const {
743 return fWrapped;
744 }
745
getFlags() const746 SkEnumBitMask<Flags> getFlags() const { return fFlags; }
747
748 private:
749 // The LocalMatrixShader has two potential variants: with and without the LocalMatrixShader
750 // In the "with" variant, the kIsPerspective flag will determine if the shader performs
751 // the perspective division or not.
752 inline static constexpr int kNumIntrinsicCombinations = 2;
753 inline static constexpr int kWithLocalMatrix = 1;
754 inline static constexpr int kWithoutLocalMatrix = 0;
755
isALocalMatrixShader() const756 bool isALocalMatrixShader() const override { return true; }
757
numIntrinsicCombinations() const758 int numIntrinsicCombinations() const override {
759 if (!(fFlags & Flags::kIncludeWithOutVariant)) {
760 return 1; // just kWithLocalMatrix
761 }
762 return kNumIntrinsicCombinations;
763 }
764
numChildCombinations() const765 int numChildCombinations() const override { return fNumWrappedCombos; }
766
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const767 void addToKey(const KeyContext& keyContext,
768 PaintParamsKeyBuilder* builder,
769 PipelineDataGatherer* gatherer,
770 int desiredCombination) const override {
771 SkASSERT(desiredCombination < this->numCombinations());
772
773 int desiredLMCombination, desiredWrappedCombination;
774
775 if (!(fFlags & Flags::kIncludeWithOutVariant)) {
776 desiredLMCombination = kWithLocalMatrix;
777 desiredWrappedCombination = desiredCombination;
778 } else {
779 desiredLMCombination = desiredCombination % kNumIntrinsicCombinations;
780 desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
781 }
782 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
783
784 if (desiredLMCombination == kWithLocalMatrix) {
785 SkMatrix matrix = SkMatrix::I();
786 if (fFlags & Flags::kIsPerspective) {
787 matrix.setPerspX(0.1f);
788 }
789 LocalMatrixShaderBlock::LMShaderData lmShaderData(matrix);
790
791 LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, matrix);
792 }
793
794 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped,
795 desiredWrappedCombination);
796
797 if (desiredLMCombination == kWithLocalMatrix) {
798 builder->endBlock();
799 }
800 }
801
802 std::vector<sk_sp<PrecompileShader>> fWrapped;
803 int fNumWrappedCombos;
804 SkEnumBitMask<Flags> fFlags;
805 };
806
LocalMatrix(SkSpan<const sk_sp<PrecompileShader>> wrapped,bool isPerspective)807 sk_sp<PrecompileShader> PrecompileShaders::LocalMatrix(
808 SkSpan<const sk_sp<PrecompileShader>> wrapped,
809 bool isPerspective) {
810 return sk_make_sp<PrecompileLocalMatrixShader>(
811 std::move(wrapped),
812 isPerspective ? PrecompileLocalMatrixShader::Flags::kIsPerspective
813 : PrecompileLocalMatrixShader::Flags::kNone);
814 }
815
LocalMatrixBothVariants(SkSpan<const sk_sp<PrecompileShader>> wrapped)816 sk_sp<PrecompileShader> PrecompileShadersPriv::LocalMatrixBothVariants(
817 SkSpan<const sk_sp<PrecompileShader>> wrapped) {
818 return sk_make_sp<PrecompileLocalMatrixShader>(
819 std::move(wrapped),
820 PrecompileLocalMatrixShader::Flags::kIncludeWithOutVariant);
821 }
822
makeWithLocalMatrix(bool isPerspective) const823 sk_sp<PrecompileShader> PrecompileShader::makeWithLocalMatrix(bool isPerspective) const {
824 if (this->priv().isALocalMatrixShader()) {
825 // SkShader::makeWithLocalMatrix collapses chains of localMatrix shaders so we need to
826 // follow suit here, folding in any new perspective flag if needed.
827 auto thisAsLMShader = static_cast<const PrecompileLocalMatrixShader*>(this);
828 if (isPerspective && !(thisAsLMShader->getFlags() &
829 PrecompileLocalMatrixShader::Flags::kIsPerspective)) {
830 return sk_make_sp<PrecompileLocalMatrixShader>(
831 thisAsLMShader->getWrapped(),
832 thisAsLMShader->getFlags() | PrecompileLocalMatrixShader::Flags::kIsPerspective);
833 }
834
835 return sk_ref_sp(this);
836 }
837
838 return PrecompileShaders::LocalMatrix({ sk_ref_sp(this) }, isPerspective);
839 }
840
841 //--------------------------------------------------------------------------------------------------
842 class PrecompileColorFilterShader final : public PrecompileShader {
843 public:
PrecompileColorFilterShader(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)844 PrecompileColorFilterShader(SkSpan<const sk_sp<PrecompileShader>> shaders,
845 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)
846 : fShaders(shaders.begin(), shaders.end())
847 , fColorFilters(colorFilters.begin(), colorFilters.end()) {
848 fNumShaderCombos = 0;
849 for (const auto& s : fShaders) {
850 fNumShaderCombos += s->priv().numCombinations();
851 }
852 fNumColorFilterCombos = 0;
853 for (const auto& cf : fColorFilters) {
854 fNumColorFilterCombos += cf->priv().numCombinations();
855 }
856 }
857
858 private:
numChildCombinations() const859 int numChildCombinations() const override { return fNumShaderCombos * fNumColorFilterCombos; }
860
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const861 void addToKey(const KeyContext& keyContext,
862 PaintParamsKeyBuilder* builder,
863 PipelineDataGatherer* gatherer,
864 int desiredCombination) const override {
865 SkASSERT(desiredCombination < this->numCombinations());
866
867 int desiredShaderCombination = desiredCombination % fNumShaderCombos;
868 int desiredColorFilterCombination = desiredCombination / fNumShaderCombos;
869 SkASSERT(desiredColorFilterCombination < fNumColorFilterCombos);
870
871 Compose(keyContext, builder, gatherer,
872 /* addInnerToKey= */ [&]() -> void {
873 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
874 desiredShaderCombination);
875 },
876 /* addOuterToKey= */ [&]() -> void {
877 AddToKey<PrecompileColorFilter>(keyContext, builder, gatherer, fColorFilters,
878 desiredColorFilterCombination);
879 });
880 }
881
882 std::vector<sk_sp<PrecompileShader>> fShaders;
883 std::vector<sk_sp<PrecompileColorFilter>> fColorFilters;
884 int fNumShaderCombos;
885 int fNumColorFilterCombos;
886 };
887
ColorFilter(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters)888 sk_sp<PrecompileShader> PrecompileShaders::ColorFilter(
889 SkSpan<const sk_sp<PrecompileShader>> shaders,
890 SkSpan<const sk_sp<PrecompileColorFilter>> colorFilters) {
891 return sk_make_sp<PrecompileColorFilterShader>(std::move(shaders), std::move(colorFilters));
892 }
893
894 //--------------------------------------------------------------------------------------------------
895 class PrecompileWorkingColorSpaceShader final : public PrecompileShader {
896 public:
PrecompileWorkingColorSpaceShader(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<SkColorSpace>> colorSpaces)897 PrecompileWorkingColorSpaceShader(SkSpan<const sk_sp<PrecompileShader>> shaders,
898 SkSpan<const sk_sp<SkColorSpace>> colorSpaces)
899 : fShaders(shaders.begin(), shaders.end())
900 , fColorSpaces(colorSpaces.begin(), colorSpaces.end()) {
901 fNumShaderCombos = 0;
902 for (const auto& s : fShaders) {
903 fNumShaderCombos += s->priv().numCombinations();
904 }
905 }
906
907 private:
numChildCombinations() const908 int numChildCombinations() const override { return fNumShaderCombos * fColorSpaces.size(); }
909
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const910 void addToKey(const KeyContext& keyContext,
911 PaintParamsKeyBuilder* builder,
912 PipelineDataGatherer* gatherer,
913 int desiredCombination) const override {
914 SkASSERT(desiredCombination < this->numCombinations());
915
916 int desiredShaderCombination = desiredCombination % fNumShaderCombos;
917 int desiredColorSpaceCombination = desiredCombination / fNumShaderCombos;
918 SkASSERT(desiredColorSpaceCombination < (int) fColorSpaces.size());
919
920 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
921 const SkAlphaType dstAT = dstInfo.alphaType();
922 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
923 if (!dstCS) {
924 dstCS = SkColorSpace::MakeSRGB();
925 }
926
927 sk_sp<SkColorSpace> workingCS = fColorSpaces[desiredColorSpaceCombination];
928 SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
929 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
930
931 Compose(keyContext, builder, gatherer,
932 /* addInnerToKey= */ [&]() -> void {
933 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fShaders,
934 desiredShaderCombination);
935 },
936 /* addOuterToKey= */ [&]() -> void {
937 ColorSpaceTransformBlock::ColorSpaceTransformData data(
938 workingCS.get(), dstAT, dstCS.get(), dstAT);
939 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
940 });
941 }
942
943 std::vector<sk_sp<PrecompileShader>> fShaders;
944 std::vector<sk_sp<SkColorSpace>> fColorSpaces;
945 int fNumShaderCombos;
946 };
947
WorkingColorSpace(SkSpan<const sk_sp<PrecompileShader>> shaders,SkSpan<const sk_sp<SkColorSpace>> colorSpaces)948 sk_sp<PrecompileShader> PrecompileShaders::WorkingColorSpace(
949 SkSpan<const sk_sp<PrecompileShader>> shaders,
950 SkSpan<const sk_sp<SkColorSpace>> colorSpaces) {
951 return sk_make_sp<PrecompileWorkingColorSpaceShader>(std::move(shaders),
952 std::move(colorSpaces));
953 }
954
955 //--------------------------------------------------------------------------------------------------
956 // In Graphite this acts as a non-elidable LocalMatrixShader
957 class PrecompileCTMShader final : public PrecompileShader {
958 public:
PrecompileCTMShader(SkSpan<const sk_sp<PrecompileShader>> wrapped)959 PrecompileCTMShader(SkSpan<const sk_sp<PrecompileShader>> wrapped)
960 : fWrapped(wrapped.begin(), wrapped.end()) {
961 fNumWrappedCombos = 0;
962 for (const auto& s : fWrapped) {
963 fNumWrappedCombos += s->priv().numCombinations();
964 }
965 }
966
isConstant(int desiredCombination) const967 bool isConstant(int desiredCombination) const override {
968 SkASSERT(desiredCombination < fNumWrappedCombos);
969
970 std::pair<sk_sp<PrecompileShader>, int> wrapped =
971 PrecompileBase::SelectOption(SkSpan(fWrapped), desiredCombination);
972 if (wrapped.first) {
973 return wrapped.first->priv().isConstant(wrapped.second);
974 }
975
976 return false;
977 }
978
979 private:
numChildCombinations() const980 int numChildCombinations() const override { return fNumWrappedCombos; }
981
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const982 void addToKey(const KeyContext& keyContext,
983 PaintParamsKeyBuilder* builder,
984 PipelineDataGatherer* gatherer,
985 int desiredCombination) const override {
986 SkASSERT(desiredCombination < fNumWrappedCombos);
987
988 LocalMatrixShaderBlock::LMShaderData kIgnoredLMShaderData(SkMatrix::I());
989
990 LocalMatrixShaderBlock::BeginBlock(keyContext, builder, gatherer, kIgnoredLMShaderData);
991
992 AddToKey<PrecompileShader>(keyContext, builder, gatherer, fWrapped, desiredCombination);
993
994 builder->endBlock();
995 }
996
997 std::vector<sk_sp<PrecompileShader>> fWrapped;
998 int fNumWrappedCombos;
999 };
1000
CTM(SkSpan<const sk_sp<PrecompileShader>> wrapped)1001 sk_sp<PrecompileShader> PrecompileShadersPriv::CTM(SkSpan<const sk_sp<PrecompileShader>> wrapped) {
1002 return sk_make_sp<PrecompileCTMShader>(std::move(wrapped));
1003 }
1004
1005 //--------------------------------------------------------------------------------------------------
1006 class PrecompileBlurShader final : public PrecompileShader {
1007 public:
PrecompileBlurShader(sk_sp<PrecompileShader> wrapped)1008 PrecompileBlurShader(sk_sp<PrecompileShader> wrapped)
1009 : fWrapped(std::move(wrapped)) {
1010 fNumWrappedCombos = fWrapped->priv().numCombinations();
1011 }
1012
1013 private:
1014 // 6 known 1D blur effects + 6 known 2D blur effects
1015 inline static constexpr int kNumIntrinsicCombinations = 12;
1016
numIntrinsicCombinations() const1017 int numIntrinsicCombinations() const override { return kNumIntrinsicCombinations; }
1018
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 < this->numCombinations());
1026
1027 using namespace SkKnownRuntimeEffects;
1028
1029 int desiredBlurCombination = desiredCombination % kNumIntrinsicCombinations;
1030 int desiredWrappedCombination = desiredCombination / kNumIntrinsicCombinations;
1031 SkASSERT(desiredWrappedCombination < fNumWrappedCombos);
1032
1033 static const StableKey kIDs[kNumIntrinsicCombinations] = {
1034 StableKey::k1DBlur4, StableKey::k1DBlur8, StableKey::k1DBlur12,
1035 StableKey::k1DBlur16, StableKey::k1DBlur20, StableKey::k1DBlur28,
1036
1037 StableKey::k2DBlur4, StableKey::k2DBlur8, StableKey::k2DBlur12,
1038 StableKey::k2DBlur16, StableKey::k2DBlur20, StableKey::k2DBlur28,
1039 };
1040
1041 const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(kIDs[desiredBlurCombination]);
1042
1043 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1044
1045 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
1046 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
1047 builder->endBlock();
1048 }
1049
1050 sk_sp<PrecompileShader> fWrapped;
1051 int fNumWrappedCombos;
1052 };
1053
Blur(sk_sp<PrecompileShader> wrapped)1054 sk_sp<PrecompileShader> PrecompileShadersPriv::Blur(sk_sp<PrecompileShader> wrapped) {
1055 return sk_make_sp<PrecompileBlurShader>(std::move(wrapped));
1056 }
1057
1058 //--------------------------------------------------------------------------------------------------
1059 class PrecompileMatrixConvolutionShader final : public PrecompileShader {
1060 public:
PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)1061 PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)
1062 : fWrapped(std::move(wrapped)) {
1063 fNumWrappedCombos = fWrapped->priv().numCombinations();
1064
1065 // When the matrix convolution ImageFilter uses a texture we know it will only ever
1066 // be SkFilterMode::kNearest and SkTileMode::kClamp.
1067 // TODO: add a PrecompileImageShaderFlags to further limit the raw image shader
1068 // combinations. Right now we're getting two combinations for the raw shader
1069 // (sk_image_shader and sk_hw_image_shader).
1070 fRawImageShader =
1071 PrecompileShadersPriv::RawImage(PrecompileImageShaderFlags::kExcludeCubic);
1072 fNumRawImageShaderCombos = fRawImageShader->priv().numCombinations();
1073 }
1074
1075 private:
numIntrinsicCombinations() const1076 int numIntrinsicCombinations() const override {
1077 // The uniform version only has one option but the two texture-based versions will
1078 // have as many combinations as the raw image shader.
1079 return 1 + 2 * fNumRawImageShaderCombos;
1080 }
1081
numChildCombinations() const1082 int numChildCombinations() const override { return fNumWrappedCombos; }
1083
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1084 void addToKey(const KeyContext& keyContext,
1085 PaintParamsKeyBuilder* builder,
1086 PipelineDataGatherer* gatherer,
1087 int desiredCombination) const override {
1088
1089 int desiredTextureCombination = 0;
1090
1091 const int desiredWrappedCombination = desiredCombination % fNumWrappedCombos;
1092 int remainingCombinations = desiredCombination / fNumWrappedCombos;
1093
1094 SkKnownRuntimeEffects::StableKey stableKey = SkKnownRuntimeEffects::StableKey::kInvalid;
1095 if (remainingCombinations == 0) {
1096 stableKey = SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms;
1097 } else {
1098 static constexpr SkKnownRuntimeEffects::StableKey kTextureBasedStableKeys[] = {
1099 SkKnownRuntimeEffects::StableKey::kMatrixConvTexSm,
1100 SkKnownRuntimeEffects::StableKey::kMatrixConvTexLg,
1101 };
1102
1103 --remainingCombinations;
1104 stableKey = kTextureBasedStableKeys[remainingCombinations % 2];
1105 desiredTextureCombination = remainingCombinations / 2;
1106 SkASSERT(desiredTextureCombination < fNumRawImageShaderCombos);
1107 }
1108
1109 const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(stableKey);
1110
1111 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1112
1113 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
1114 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
1115 if (stableKey != SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms) {
1116 fRawImageShader->priv().addToKey(childContext, builder, gatherer,
1117 desiredTextureCombination);
1118 }
1119 builder->endBlock();
1120 }
1121
1122 sk_sp<PrecompileShader> fWrapped;
1123 int fNumWrappedCombos;
1124 sk_sp<PrecompileShader> fRawImageShader;
1125 int fNumRawImageShaderCombos;
1126 };
1127
MatrixConvolution(sk_sp<skgpu::graphite::PrecompileShader> wrapped)1128 sk_sp<PrecompileShader> PrecompileShadersPriv::MatrixConvolution(
1129 sk_sp<skgpu::graphite::PrecompileShader> wrapped) {
1130 return sk_make_sp<PrecompileMatrixConvolutionShader>(std::move(wrapped));
1131 }
1132
1133 //--------------------------------------------------------------------------------------------------
1134 class PrecompileMorphologyShader final : public PrecompileShader {
1135 public:
PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,SkKnownRuntimeEffects::StableKey stableKey)1136 PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,
1137 SkKnownRuntimeEffects::StableKey stableKey)
1138 : fWrapped(std::move(wrapped))
1139 , fStableKey(stableKey) {
1140 fNumWrappedCombos = fWrapped->priv().numCombinations();
1141 SkASSERT(stableKey == SkKnownRuntimeEffects::StableKey::kLinearMorphology ||
1142 stableKey == SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1143 }
1144
1145 private:
numChildCombinations() const1146 int numChildCombinations() const override { return fNumWrappedCombos; }
1147
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1148 void addToKey(const KeyContext& keyContext,
1149 PaintParamsKeyBuilder* builder,
1150 PipelineDataGatherer* gatherer,
1151 int desiredCombination) const override {
1152 SkASSERT(desiredCombination < fNumWrappedCombos);
1153
1154 const SkRuntimeEffect* effect = GetKnownRuntimeEffect(fStableKey);
1155
1156 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1157
1158 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(effect) });
1159 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1160 builder->endBlock();
1161 }
1162
1163 sk_sp<PrecompileShader> fWrapped;
1164 int fNumWrappedCombos;
1165 SkKnownRuntimeEffects::StableKey fStableKey;
1166 };
1167
LinearMorphology(sk_sp<PrecompileShader> wrapped)1168 sk_sp<PrecompileShader> PrecompileShadersPriv::LinearMorphology(sk_sp<PrecompileShader> wrapped) {
1169 return sk_make_sp<PrecompileMorphologyShader>(
1170 std::move(wrapped),
1171 SkKnownRuntimeEffects::StableKey::kLinearMorphology);
1172 }
1173
SparseMorphology(sk_sp<PrecompileShader> wrapped)1174 sk_sp<PrecompileShader> PrecompileShadersPriv::SparseMorphology(sk_sp<PrecompileShader> wrapped) {
1175 return sk_make_sp<PrecompileMorphologyShader>(
1176 std::move(wrapped),
1177 SkKnownRuntimeEffects::StableKey::kSparseMorphology);
1178 }
1179
1180 //--------------------------------------------------------------------------------------------------
1181 class PrecompileDisplacementShader final : public PrecompileShader {
1182 public:
PrecompileDisplacementShader(sk_sp<PrecompileShader> displacement,sk_sp<PrecompileShader> color)1183 PrecompileDisplacementShader(sk_sp<PrecompileShader> displacement,
1184 sk_sp<PrecompileShader> color)
1185 : fDisplacement(std::move(displacement))
1186 , fColor(std::move(color)) {
1187 fNumDisplacementCombos = fDisplacement->priv().numCombinations();
1188 fNumColorCombos = fColor->priv().numCombinations();
1189 }
1190
1191 private:
numChildCombinations() const1192 int numChildCombinations() const override { return fNumDisplacementCombos * fNumColorCombos; }
1193
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1194 void addToKey(const KeyContext& keyContext,
1195 PaintParamsKeyBuilder* builder,
1196 PipelineDataGatherer* gatherer,
1197 int desiredCombination) const override {
1198 SkASSERT(desiredCombination < this->numChildCombinations());
1199
1200 const int desiredDisplacementCombination = desiredCombination % fNumDisplacementCombos;
1201 const int desiredColorCombination = desiredCombination / fNumDisplacementCombos;
1202 SkASSERT(desiredColorCombination < fNumColorCombos);
1203
1204 const SkRuntimeEffect* fEffect =
1205 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kDisplacement);
1206
1207 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1208
1209 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
1210 fDisplacement->priv().addToKey(childContext, builder, gatherer,
1211 desiredDisplacementCombination);
1212 fColor->priv().addToKey(childContext, builder, gatherer,
1213 desiredColorCombination);
1214 builder->endBlock();
1215 }
1216
1217 sk_sp<PrecompileShader> fDisplacement;
1218 int fNumDisplacementCombos;
1219 sk_sp<PrecompileShader> fColor;
1220 int fNumColorCombos;
1221 };
1222
1223 //--------------------------------------------------------------------------------------------------
Displacement(sk_sp<PrecompileShader> displacement,sk_sp<PrecompileShader> color)1224 sk_sp<PrecompileShader> PrecompileShadersPriv::Displacement(sk_sp<PrecompileShader> displacement,
1225 sk_sp<PrecompileShader> color) {
1226 return sk_make_sp<PrecompileDisplacementShader>(std::move(displacement), std::move(color));
1227 }
1228
1229 //--------------------------------------------------------------------------------------------------
1230 class PrecompileLightingShader final : public PrecompileShader {
1231 public:
PrecompileLightingShader(sk_sp<PrecompileShader> wrapped)1232 PrecompileLightingShader(sk_sp<PrecompileShader> wrapped)
1233 : fWrapped(std::move(wrapped)) {
1234 fNumWrappedCombos = fWrapped->priv().numCombinations();
1235 }
1236
1237 private:
numChildCombinations() const1238 int numChildCombinations() const override { return fNumWrappedCombos; }
1239
addToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,int desiredCombination) const1240 void addToKey(const KeyContext& keyContext,
1241 PaintParamsKeyBuilder* builder,
1242 PipelineDataGatherer* gatherer,
1243 int desiredCombination) const override {
1244 SkASSERT(desiredCombination < fNumWrappedCombos);
1245
1246 const SkRuntimeEffect* normalEffect =
1247 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kNormal);
1248 const SkRuntimeEffect* lightingEffect =
1249 GetKnownRuntimeEffect(SkKnownRuntimeEffects::StableKey::kLighting);
1250
1251 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1252
1253 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1254 { sk_ref_sp(lightingEffect) });
1255 RuntimeEffectBlock::BeginBlock(childContext, builder, gatherer,
1256 { sk_ref_sp(normalEffect) });
1257 fWrapped->priv().addToKey(childContext, builder, gatherer, desiredCombination);
1258 builder->endBlock();
1259 builder->endBlock();
1260 }
1261
1262 sk_sp<PrecompileShader> fWrapped;
1263 int fNumWrappedCombos;
1264 };
1265
Lighting(sk_sp<PrecompileShader> wrapped)1266 sk_sp<PrecompileShader> PrecompileShadersPriv::Lighting(sk_sp<PrecompileShader> wrapped) {
1267 return sk_make_sp<PrecompileLightingShader>(std::move(wrapped));
1268 }
1269
1270 //--------------------------------------------------------------------------------------------------
1271
1272 } // namespace skgpu::graphite
1273