Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
KeyHelpers.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
12#include "include/core/SkData.h"
16#include "src/base/SkHalf.h"
23#include "src/core/SkYUVMath.h"
33#include "src/gpu/Blend.h"
34#include "src/gpu/DitherUtils.h"
35#include "src/gpu/Swizzle.h"
78
79#define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID) \
80 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, dict->getUniforms(codeSnippetID));)
81
82namespace skgpu::graphite {
83
84//--------------------------------------------------------------------------------------------------
85
86namespace {
87
88void add_solid_uniform_data(const ShaderCodeDictionary* dict,
89 const SkPMColor4f& premulColor,
90 PipelineDataGatherer* gatherer) {
92 gatherer->write(premulColor);
93}
94
95} // anonymous namespace
96
98 PaintParamsKeyBuilder* builder,
99 PipelineDataGatherer* gatherer,
100 const SkPMColor4f& premulColor) {
101 add_solid_uniform_data(keyContext.dict(), premulColor, gatherer);
102
104}
105
106//--------------------------------------------------------------------------------------------------
107
108namespace {
109
110void add_rgb_paint_color_uniform_data(const ShaderCodeDictionary* dict,
111 const SkPMColor4f& premulColor,
112 PipelineDataGatherer* gatherer) {
114 gatherer->writePaintColor(premulColor);
115}
116
117void add_alpha_only_paint_color_uniform_data(const ShaderCodeDictionary* dict,
118 const SkPMColor4f& premulColor,
119 PipelineDataGatherer* gatherer) {
121 gatherer->writePaintColor(premulColor);
122}
123
124} // anonymous namespace
125
127 PaintParamsKeyBuilder* builder,
128 PipelineDataGatherer* gatherer) {
129 add_rgb_paint_color_uniform_data(keyContext.dict(), keyContext.paintColor(), gatherer);
130
131 builder->addBlock(BuiltInCodeSnippetID::kRGBPaintColor);
132}
133
135 PaintParamsKeyBuilder* builder,
136 PipelineDataGatherer* gatherer) {
137 add_alpha_only_paint_color_uniform_data(keyContext.dict(), keyContext.paintColor(), gatherer);
138
140}
141
142//--------------------------------------------------------------------------------------------------
143
144namespace {
145
146void add_dst_read_sample_uniform_data(const ShaderCodeDictionary* dict,
147 PipelineDataGatherer* gatherer,
148 sk_sp<TextureProxy> dstTexture,
149 SkIPoint dstOffset) {
150 static const SkTileMode kTileModes[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
151 gatherer->add(SkSamplingOptions(), kTileModes, dstTexture);
152
154
155 SkV4 coords{static_cast<float>(dstOffset.x()),
156 static_cast<float>(dstOffset.y()),
157 dstTexture ? 1.0f / dstTexture->dimensions().width() : 1.0f,
158 dstTexture ? 1.0f / dstTexture->dimensions().height() : 1.0f };
159 gatherer->write(coords);
160}
161
162} // anonymous namespace
163
165 PaintParamsKeyBuilder* builder,
166 PipelineDataGatherer* gatherer,
167 sk_sp<TextureProxy> dstTexture,
168 SkIPoint dstOffset) {
169 add_dst_read_sample_uniform_data(keyContext.dict(), gatherer, std::move(dstTexture), dstOffset);
170
171 builder->addBlock(BuiltInCodeSnippetID::kDstReadSample);
172}
173
174//--------------------------------------------------------------------------------------------------
175
176namespace {
177
178void add_gradient_preamble(const GradientShaderBlocks::GradientData& gradData,
179 PipelineDataGatherer* gatherer) {
180 constexpr int kInternalStopLimit = GradientShaderBlocks::GradientData::kNumInternalStorageStops;
181
182 if (gradData.fNumStops <= kInternalStopLimit) {
183 if (gradData.fNumStops <= 4) {
184 // Round up to 4 stops.
185 gatherer->writeArray(SkSpan{gradData.fColors, 4});
186 gatherer->write(gradData.fOffsets[0]);
187 } else if (gradData.fNumStops <= 8) {
188 // Round up to 8 stops.
189 gatherer->writeArray(SkSpan{gradData.fColors, 8});
190 gatherer->writeArray(SkSpan{gradData.fOffsets, 2});
191 } else {
192 // Did kNumInternalStorageStops change?
194 }
195 }
196}
197
198// All the gradients share a common postamble of:
199// numStops - for texture-based gradients
200// tilemode
201// colorSpace
202// doUnPremul
203void add_gradient_postamble(const GradientShaderBlocks::GradientData& gradData,
204 PipelineDataGatherer* gatherer) {
206
207 constexpr int kInternalStopLimit = GradientShaderBlocks::GradientData::kNumInternalStorageStops;
208
209 static_assert(static_cast<int>(ColorSpace::kLab) == 2);
210 static_assert(static_cast<int>(ColorSpace::kOKLab) == 3);
211 static_assert(static_cast<int>(ColorSpace::kOKLabGamutMap) == 4);
212 static_assert(static_cast<int>(ColorSpace::kLCH) == 5);
213 static_assert(static_cast<int>(ColorSpace::kOKLCH) == 6);
214 static_assert(static_cast<int>(ColorSpace::kOKLCHGamutMap) == 7);
215 static_assert(static_cast<int>(ColorSpace::kHSL) == 9);
216 static_assert(static_cast<int>(ColorSpace::kHWB) == 10);
217
218 bool inputPremul = static_cast<bool>(gradData.fInterpolation.fInPremul);
219
220 if (gradData.fNumStops > kInternalStopLimit) {
221 gatherer->write(gradData.fNumStops);
222 }
223
224 gatherer->write(static_cast<int>(gradData.fTM));
225 gatherer->write(static_cast<int>(gradData.fInterpolation.fColorSpace));
226 gatherer->write(static_cast<int>(inputPremul));
227}
228
229void add_linear_gradient_uniform_data(const ShaderCodeDictionary* dict,
230 BuiltInCodeSnippetID codeSnippetID,
231 const GradientShaderBlocks::GradientData& gradData,
232 PipelineDataGatherer* gatherer) {
233 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
234
235 add_gradient_preamble(gradData, gatherer);
236 gatherer->write(gradData.fPoints[0]);
237 gatherer->write(gradData.fPoints[1]);
238 add_gradient_postamble(gradData, gatherer);
239};
240
241void add_radial_gradient_uniform_data(const ShaderCodeDictionary* dict,
242 BuiltInCodeSnippetID codeSnippetID,
243 const GradientShaderBlocks::GradientData& gradData,
244 PipelineDataGatherer* gatherer) {
245 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
246
247 add_gradient_preamble(gradData, gatherer);
248 gatherer->write(gradData.fPoints[0]);
249 gatherer->write(gradData.fRadii[0]);
250 add_gradient_postamble(gradData, gatherer);
251};
252
253void add_sweep_gradient_uniform_data(const ShaderCodeDictionary* dict,
254 BuiltInCodeSnippetID codeSnippetID,
255 const GradientShaderBlocks::GradientData& gradData,
256 PipelineDataGatherer* gatherer) {
257 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
258
259 add_gradient_preamble(gradData, gatherer);
260 gatherer->write(gradData.fPoints[0]);
261 gatherer->write(gradData.fBias);
262 gatherer->write(gradData.fScale);
263 add_gradient_postamble(gradData, gatherer);
264};
265
266void add_conical_gradient_uniform_data(const ShaderCodeDictionary* dict,
267 BuiltInCodeSnippetID codeSnippetID,
268 const GradientShaderBlocks::GradientData& gradData,
269 PipelineDataGatherer* gatherer) {
270 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
271
272 add_gradient_preamble(gradData, gatherer);
273 gatherer->write(gradData.fPoints[0]);
274 gatherer->write(gradData.fPoints[1]);
275 gatherer->write(gradData.fRadii[0]);
276 gatherer->write(gradData.fRadii[1]);
277 add_gradient_postamble(gradData, gatherer);
278};
279
280} // anonymous namespace
281
283 : fType(type)
284 , fPoints{{0.0f, 0.0f}, {0.0f, 0.0f}}
285 , fRadii{0.0f, 0.0f}
286 , fBias(0.0f)
287 , fScale(0.0f)
288 , fTM(SkTileMode::kClamp)
289 , fNumStops(numStops) {
290 sk_bzero(fColors, sizeof(fColors));
291 sk_bzero(fOffsets, sizeof(fOffsets));
292}
293
295 SkPoint point0, SkPoint point1,
296 float radius0, float radius1,
297 float bias, float scale,
298 SkTileMode tm,
299 int numStops,
300 const SkPMColor4f* colors,
301 const float* offsets,
302 sk_sp<TextureProxy> colorsAndOffsetsProxy,
304 : fType(type)
305 , fBias(bias)
306 , fScale(scale)
307 , fTM(tm)
308 , fNumStops(numStops)
309 , fInterpolation(interp) {
310 SkASSERT(fNumStops >= 1);
311
312 fPoints[0] = point0;
313 fPoints[1] = point1;
314 fRadii[0] = radius0;
315 fRadii[1] = radius1;
316
318 memcpy(fColors, colors, fNumStops * sizeof(SkColor4f));
319 float* rawOffsets = fOffsets[0].ptr();
320 if (offsets) {
321 memcpy(rawOffsets, offsets, fNumStops * sizeof(float));
322 } else {
323 for (int i = 0; i < fNumStops; ++i) {
324 rawOffsets[i] = SkIntToFloat(i) / (fNumStops-1);
325 }
326 }
327
328 // Extend the colors and offset, if necessary, to fill out the arrays.
329 // The unrolled binary search implementation assumes excess stops match the last real value.
330 for (int i = fNumStops; i < kNumInternalStorageStops; ++i) {
331 fColors[i] = fColors[fNumStops-1];
332 rawOffsets[i] = rawOffsets[fNumStops-1];
333 }
334 } else {
335 fColorsAndOffsetsProxy = std::move(colorsAndOffsetsProxy);
337 }
338}
339
341 PaintParamsKeyBuilder* builder,
342 PipelineDataGatherer* gatherer,
343 const GradientData& gradData) {
344 auto dict = keyContext.dict();
345
346 if (gradData.fNumStops > GradientData::kNumInternalStorageStops && gatherer) {
348
350 static constexpr SkTileMode kClampTiling[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
351 gatherer->add(kNearest, kClampTiling, gradData.fColorsAndOffsetsProxy);
352 }
353
355 switch (gradData.fType) {
356 case SkShaderBase::GradientType::kLinear:
357 codeSnippetID =
361 add_linear_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
362 break;
363 case SkShaderBase::GradientType::kRadial:
364 codeSnippetID =
368 add_radial_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
369 break;
370 case SkShaderBase::GradientType::kSweep:
371 codeSnippetID =
375 add_sweep_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
376 break;
377 case SkShaderBase::GradientType::kConical:
378 codeSnippetID =
382 add_conical_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
383 break;
385 default:
386 SkDEBUGFAIL("Expected a gradient shader, but it wasn't one.");
387 break;
388 }
389
390 builder->addBlock(codeSnippetID);
391}
392
393//--------------------------------------------------------------------------------------------------
394
395namespace {
396
397void add_localmatrixshader_uniform_data(const ShaderCodeDictionary* dict,
398 const SkM44& localMatrix,
399 PipelineDataGatherer* gatherer) {
401
402 SkM44 lmInverse;
403 bool wasInverted = localMatrix.invert(&lmInverse); // TODO: handle failure up stack
404 if (!wasInverted) {
405 lmInverse.setIdentity();
406 }
407
408 gatherer->write(lmInverse);
409}
410
411} // anonymous namespace
412
414 PaintParamsKeyBuilder* builder,
415 PipelineDataGatherer* gatherer,
416 const LMShaderData& lmShaderData) {
417
418 add_localmatrixshader_uniform_data(keyContext.dict(), lmShaderData.fLocalMatrix, gatherer);
419
420 builder->beginBlock(BuiltInCodeSnippetID::kLocalMatrixShader);
421}
422
423//--------------------------------------------------------------------------------------------------
424
425namespace {
426
427static constexpr int kColorSpaceXformFlagAlphaSwizzle = 0x20;
428
429void add_color_space_uniforms(const SkColorSpaceXformSteps& steps,
430 ReadSwizzle readSwizzle,
431 PipelineDataGatherer* gatherer) {
432 // We have 7 source coefficients and 7 destination coefficients. We pass them via a 4x4 matrix;
433 // the first two columns hold the source values, and the second two hold the destination.
434 // (The final value of each 8-element group is ignored.)
435 // In std140, this arrangement is much more efficient than a simple array of scalars.
436 SkM44 coeffs;
437
438 int colorXformFlags = SkTo<int>(steps.flags.mask());
439 if (readSwizzle != ReadSwizzle::kRGBA) {
440 // Ensure that we do the gamut step
441 SkColorSpaceXformSteps gamutSteps;
442 gamutSteps.flags.gamut_transform = true;
443 colorXformFlags |= SkTo<int>(gamutSteps.flags.mask());
444 if (readSwizzle != ReadSwizzle::kBGRA) {
445 // TODO: Maybe add a fullMask() method to XformSteps?
446 SkASSERT(colorXformFlags < kColorSpaceXformFlagAlphaSwizzle);
447 colorXformFlags |= kColorSpaceXformFlagAlphaSwizzle;
448 }
449 }
450 gatherer->write(colorXformFlags);
451
452 if (steps.flags.linearize) {
453 gatherer->write(SkTo<int>(skcms_TransferFunction_getType(&steps.srcTF)));
454 coeffs.setCol(0, {steps.srcTF.g, steps.srcTF.a, steps.srcTF.b, steps.srcTF.c});
455 coeffs.setCol(1, {steps.srcTF.d, steps.srcTF.e, steps.srcTF.f, 0.0f});
456 } else {
457 gatherer->write(SkTo<int>(skcms_TFType::skcms_TFType_Invalid));
458 }
459
460 SkMatrix gamutTransform;
461 const float identity[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
462 // TODO: it seems odd to copy this into an SkMatrix just to write it to the gatherer
463 // src_to_dst_matrix is column-major, SkMatrix is row-major.
464 const float* m = steps.flags.gamut_transform ? steps.src_to_dst_matrix : identity;
465 if (readSwizzle == ReadSwizzle::kRRR1) {
466 gamutTransform.setAll(m[0] + m[3] + m[6], 0, 0,
467 m[1] + m[4] + m[7], 0, 0,
468 m[2] + m[5] + m[8], 0, 0);
469 } else if (readSwizzle == ReadSwizzle::kBGRA) {
470 gamutTransform.setAll(m[6], m[3], m[0],
471 m[7], m[4], m[1],
472 m[8], m[5], m[2]);
473 } else if (readSwizzle == ReadSwizzle::k000R) {
474 gamutTransform.setAll(0, 0, 0,
475 0, 0, 0,
476 0, 0, 0);
477 } else if (steps.flags.gamut_transform) {
478 gamutTransform.setAll(m[0], m[3], m[6],
479 m[1], m[4], m[7],
480 m[2], m[5], m[8]);
481 }
482 gatherer->writeHalf(gamutTransform);
483
484 if (steps.flags.encode) {
485 gatherer->write(SkTo<int>(skcms_TransferFunction_getType(&steps.dstTFInv)));
486 coeffs.setCol(2, {steps.dstTFInv.g, steps.dstTFInv.a, steps.dstTFInv.b, steps.dstTFInv.c});
487 coeffs.setCol(3, {steps.dstTFInv.d, steps.dstTFInv.e, steps.dstTFInv.f, 0.0f});
488 } else {
489 gatherer->write(SkTo<int>(skcms_TFType::skcms_TFType_Invalid));
490 }
491
492 // Pack alpha swizzle in the unused coeff entries.
493 switch (readSwizzle) {
495 coeffs.setRC(3, 1, 1.f);
496 coeffs.setRC(3, 3, 0.f);
497 break;
500 coeffs.setRC(3, 1, 0.f);
501 coeffs.setRC(3, 3, 1.f);
502 break;
503 default:
504 coeffs.setRC(3, 1, 0.f);
505 coeffs.setRC(3, 3, 0.f);
506 break;
507 }
508
509 gatherer->writeHalf(coeffs);
510}
511
512void add_image_uniform_data(const ShaderCodeDictionary* dict,
513 const ImageShaderBlock::ImageData& imgData,
514 PipelineDataGatherer* gatherer) {
515 SkASSERT(!imgData.fSampling.useCubic);
517
518 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
519 gatherer->write(imgData.fSubset);
520 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
521 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
522 gatherer->write(SkTo<int>(imgData.fSampling.filter));
523
524 add_color_space_uniforms(imgData.fSteps, imgData.fReadSwizzle, gatherer);
525}
526
527void add_cubic_image_uniform_data(const ShaderCodeDictionary* dict,
528 const ImageShaderBlock::ImageData& imgData,
529 PipelineDataGatherer* gatherer) {
530 SkASSERT(imgData.fSampling.useCubic);
532
533 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
534 gatherer->write(imgData.fSubset);
535 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
536 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
537 const SkCubicResampler& cubic = imgData.fSampling.cubic;
538 gatherer->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
539
540 add_color_space_uniforms(imgData.fSteps, imgData.fReadSwizzle, gatherer);
541}
542
543void add_hw_image_uniform_data(const ShaderCodeDictionary* dict,
544 const ImageShaderBlock::ImageData& imgData,
545 PipelineDataGatherer* gatherer) {
546 SkASSERT(!imgData.fSampling.useCubic);
548
549 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
550
551 add_color_space_uniforms(imgData.fSteps, imgData.fReadSwizzle, gatherer);
552}
553
554} // anonymous namespace
555
557 SkTileMode tileModeX,
558 SkTileMode tileModeY,
559 SkISize imgSize,
560 SkRect subset,
561 ReadSwizzle readSwizzle)
562 : fSampling(sampling)
563 , fTileModes{tileModeX, tileModeY}
564 , fImgSize(imgSize)
565 , fSubset(subset)
566 , fReadSwizzle(readSwizzle) {
567 SkASSERT(fSteps.flags.mask() == 0); // By default, the colorspace should have no effect
568}
569
570static bool can_do_tiling_in_hw(const Caps* caps, const ImageShaderBlock::ImageData& imgData) {
571 if (!caps->clampToBorderSupport() && (imgData.fTileModes[0] == SkTileMode::kDecal ||
572 imgData.fTileModes[1] == SkTileMode::kDecal)) {
573 return false;
574 }
575 return imgData.fSubset.contains(SkRect::Make(imgData.fImgSize));
576}
577
579 PaintParamsKeyBuilder* builder,
580 PipelineDataGatherer* gatherer,
581 const ImageData& imgData) {
582
583 if (keyContext.recorder() && !imgData.fTextureProxy) {
584 builder->addBlock(BuiltInCodeSnippetID::kError);
585 return;
586 }
587
588 const Caps* caps = keyContext.caps();
589 const bool doTilingInHw = !imgData.fSampling.useCubic && can_do_tiling_in_hw(caps, imgData);
590
591 static constexpr SkTileMode kDefaultTileModes[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
592 gatherer->add(imgData.fSampling,
593 doTilingInHw ? imgData.fTileModes : kDefaultTileModes,
594 imgData.fTextureProxy);
595
596 if (doTilingInHw) {
597 add_hw_image_uniform_data(keyContext.dict(), imgData, gatherer);
598 builder->addBlock(BuiltInCodeSnippetID::kHWImageShader);
599 } else if (imgData.fSampling.useCubic) {
600 add_cubic_image_uniform_data(keyContext.dict(), imgData, gatherer);
602 } else {
603 add_image_uniform_data(keyContext.dict(), imgData, gatherer);
604 builder->addBlock(BuiltInCodeSnippetID::kImageShader);
605 }
606}
607
608//--------------------------------------------------------------------------------------------------
609
610// makes use of ImageShader functions, above
611namespace {
612
613void add_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
614 const YUVImageShaderBlock::ImageData& imgData,
615 PipelineDataGatherer* gatherer) {
617
618 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
619 gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
620 gatherer->write(imgData.fSubset);
621 gatherer->write(imgData.fLinearFilterUVInset);
622 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
623 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
624 gatherer->write(SkTo<int>(imgData.fSampling.filter));
625 gatherer->write(SkTo<int>(imgData.fSamplingUV.filter));
626
627 for (int i = 0; i < 4; ++i) {
628 gatherer->writeHalf(imgData.fChannelSelect[i]);
629 }
630 gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
631 gatherer->write(imgData.fYUVtoRGBTranslate);
632}
633
634void add_cubic_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
635 const YUVImageShaderBlock::ImageData& imgData,
636 PipelineDataGatherer* gatherer) {
638
639 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
640 gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
641 gatherer->write(imgData.fSubset);
642 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
643 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
644 const SkCubicResampler& cubic = imgData.fSampling.cubic;
645 gatherer->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
646
647 for (int i = 0; i < 4; ++i) {
648 gatherer->writeHalf(imgData.fChannelSelect[i]);
649 }
650 gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
651 gatherer->write(imgData.fYUVtoRGBTranslate);
652}
653
654} // anonymous namespace
655
657 SkTileMode tileModeX,
658 SkTileMode tileModeY,
659 SkISize imgSize,
660 SkRect subset)
661 : fSampling(sampling)
662 , fSamplingUV(sampling)
663 , fTileModes{tileModeX, tileModeY}
664 , fImgSize(imgSize)
665 , fImgSizeUV(imgSize)
666 , fSubset(subset) {
667}
668
670 PaintParamsKeyBuilder* builder,
671 PipelineDataGatherer* gatherer,
672 const ImageData& imgData) {
673 if (keyContext.recorder() &&
674 (!imgData.fTextureProxies[0] || !imgData.fTextureProxies[1] ||
675 !imgData.fTextureProxies[2] || !imgData.fTextureProxies[3])) {
676 builder->addBlock(BuiltInCodeSnippetID::kError);
677 return;
678 }
679
680 SkTileMode uvTileModes[2] = { imgData.fTileModes[0] == SkTileMode::kDecal
681 ? SkTileMode::kClamp : imgData.fTileModes[0],
682 imgData.fTileModes[1] == SkTileMode::kDecal
683 ? SkTileMode::kClamp : imgData.fTileModes[1] };
684 gatherer->add(imgData.fSampling, imgData.fTileModes, imgData.fTextureProxies[0]);
685 gatherer->add(imgData.fSamplingUV, uvTileModes, imgData.fTextureProxies[1]);
686 gatherer->add(imgData.fSamplingUV, uvTileModes, imgData.fTextureProxies[2]);
687 gatherer->add(imgData.fSampling, imgData.fTileModes, imgData.fTextureProxies[3]);
688
689 if (imgData.fSampling.useCubic) {
690 add_cubic_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
692 } else {
693 add_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
694 builder->addBlock(BuiltInCodeSnippetID::kYUVImageShader);
695 }
696}
697
698//--------------------------------------------------------------------------------------------------
699
700namespace {
701
702void add_coordclamp_uniform_data(const ShaderCodeDictionary* dict,
704 PipelineDataGatherer* gatherer) {
706
707 gatherer->write(clampData.fSubset);
708}
709
710} // anonymous namespace
711
713 PaintParamsKeyBuilder* builder,
714 PipelineDataGatherer* gatherer,
715 const CoordClampData& clampData) {
716 add_coordclamp_uniform_data(keyContext.dict(), clampData, gatherer);
717
718 builder->beginBlock(BuiltInCodeSnippetID::kCoordClampShader);
719}
720
721//--------------------------------------------------------------------------------------------------
722
723namespace {
724
725void add_dither_uniform_data(const ShaderCodeDictionary* dict,
726 const DitherShaderBlock::DitherData& ditherData,
727 PipelineDataGatherer* gatherer) {
729
730 gatherer->writeHalf(ditherData.fRange);
731}
732
733} // anonymous namespace
734
736 PaintParamsKeyBuilder* builder,
737 PipelineDataGatherer* gatherer,
738 const DitherData& data) {
739 add_dither_uniform_data(keyContext.dict(), data, gatherer);
740
742 static constexpr SkTileMode kRepeatTiling[2] = { SkTileMode::kRepeat, SkTileMode::kRepeat };
743
744 SkASSERT(data.fLUTProxy || !keyContext.recorder());
745 gatherer->add(kNearest, kRepeatTiling, data.fLUTProxy);
746
747 builder->addBlock(BuiltInCodeSnippetID::kDitherShader);
748}
749
750//--------------------------------------------------------------------------------------------------
751
752namespace {
753
754void add_perlin_noise_uniform_data(const ShaderCodeDictionary* dict,
756 PipelineDataGatherer* gatherer) {
758
759 gatherer->write(noiseData.fBaseFrequency);
760 gatherer->write(noiseData.fStitchData);
761 gatherer->write(static_cast<int>(noiseData.fType));
762 gatherer->write(noiseData.fNumOctaves);
763 gatherer->write(static_cast<int>(noiseData.stitching()));
764
765 static const SkTileMode kRepeatXTileModes[2] = { SkTileMode::kRepeat, SkTileMode::kClamp };
766 static const SkSamplingOptions kNearestSampling { SkFilterMode::kNearest };
767
768 gatherer->add(kNearestSampling, kRepeatXTileModes, noiseData.fPermutationsProxy);
769 gatherer->add(kNearestSampling, kRepeatXTileModes, noiseData.fNoiseProxy);
770}
771
772} // anonymous namespace
773
775 PaintParamsKeyBuilder* builder,
776 PipelineDataGatherer* gatherer,
777 const PerlinNoiseData& noiseData) {
778 add_perlin_noise_uniform_data(keyContext.dict(), noiseData, gatherer);
779
781}
782
783//--------------------------------------------------------------------------------------------------
784
786 PaintParamsKeyBuilder* builder,
787 PipelineDataGatherer* gatherer) {
789
790 builder->beginBlock(BuiltInCodeSnippetID::kBlendShader);
791}
792
793//--------------------------------------------------------------------------------------------------
794
796 PaintParamsKeyBuilder* builder,
797 PipelineDataGatherer* gatherer,
798 SkBlendMode blendMode) {
800 gatherer->write(SkTo<int>(blendMode));
801
803}
804
805//--------------------------------------------------------------------------------------------------
806
808 PaintParamsKeyBuilder* builder,
809 PipelineDataGatherer* gatherer,
810 SkSpan<const float> coeffs) {
812 SkASSERT(coeffs.size() == 4);
813 gatherer->writeHalf(SkV4{coeffs[0], coeffs[1], coeffs[2], coeffs[3]});
814
815 builder->addBlock(BuiltInCodeSnippetID::kCoeffBlender);
816}
817
818//--------------------------------------------------------------------------------------------------
819
821 PaintParamsKeyBuilder* builder,
822 PipelineDataGatherer* gatherer) {
824
825 builder->beginBlock(BuiltInCodeSnippetID::kClipShader);
826}
827
828//--------------------------------------------------------------------------------------------------
829
831 PaintParamsKeyBuilder* builder,
832 PipelineDataGatherer* gatherer) {
833 builder->beginBlock(BuiltInCodeSnippetID::kCompose);
834}
835
836//--------------------------------------------------------------------------------------------------
837
838namespace {
839
840void add_matrix_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
842 PipelineDataGatherer* gatherer) {
844 gatherer->write(data.fMatrix);
845 gatherer->write(data.fTranslate);
846 gatherer->write(static_cast<int>(data.fInHSLA));
847}
848
849} // anonymous namespace
850
852 PaintParamsKeyBuilder* builder,
853 PipelineDataGatherer* gatherer,
854 const MatrixColorFilterData& matrixCFData) {
855
856 add_matrix_colorfilter_uniform_data(keyContext.dict(), matrixCFData, gatherer);
857
859}
860
861//--------------------------------------------------------------------------------------------------
862
863namespace {
864
865void add_table_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
867 PipelineDataGatherer* gatherer) {
869
870 static const SkTileMode kTileModes[2] = { SkTileMode::kClamp, SkTileMode::kClamp };
871 gatherer->add(SkSamplingOptions(), kTileModes, data.fTextureProxy);
872}
873
874} // anonymous namespace
875
877 PaintParamsKeyBuilder* builder,
878 PipelineDataGatherer* gatherer,
879 const TableColorFilterData& data) {
880 SkASSERT(data.fTextureProxy || !keyContext.recorder());
881
882 add_table_colorfilter_uniform_data(keyContext.dict(), data, gatherer);
883
885}
886
887//--------------------------------------------------------------------------------------------------
888namespace {
889
890void add_color_space_xform_uniform_data(
891 const ShaderCodeDictionary* dict,
893 PipelineDataGatherer* gatherer) {
894
896 add_color_space_uniforms(data.fSteps, ReadSwizzle::kRGBA, gatherer);
897}
898
899} // anonymous namespace
900
902 SkAlphaType srcAT,
903 const SkColorSpace* dst,
904 SkAlphaType dstAT)
905 : fSteps(src, srcAT, dst, dstAT) {}
906
908 PaintParamsKeyBuilder* builder,
909 PipelineDataGatherer* gatherer,
910 const ColorSpaceTransformData& data) {
911 add_color_space_xform_uniform_data(keyContext.dict(), data, gatherer);
913}
914
915//--------------------------------------------------------------------------------------------------
916
917void AddBlendModeColorFilter(const KeyContext& keyContext,
918 PaintParamsKeyBuilder* builder,
919 PipelineDataGatherer* gatherer,
920 SkBlendMode bm,
921 const SkPMColor4f& srcColor) {
922 Blend(keyContext, builder, gatherer,
923 /* addBlendToKey= */ [&] () -> void {
924 // Note, we're playing a bit of a game here. By explicitly adding a
925 // BlendModeBlenderBlock we're always forcing the SkSL to call 'sk_blend'
926 // rather than allowing it to sometimes call 'blend_porter_duff'. This reduces
927 // the number of shader combinations and allows the pre-compilation system to more
928 // easily match the rendering path.
929 BlendModeBlenderBlock::AddBlock(keyContext, builder, gatherer, bm);
930 },
931 /* addSrcToKey= */ [&]() -> void {
932 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, srcColor);
933 },
934 /* addDstToKey= */ [&]() -> void {
935 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
936 });
937}
938
941
943 sk_sp<const SkData> uniforms)
944 : fEffect(std::move(effect))
945 , fUniforms(std::move(uniforms)) {}
946
947static bool skdata_matches(const SkData* a, const SkData* b) {
948 // Returns true if both SkData objects hold the same contents, or if they are both null.
949 // (SkData::equals supports passing null, and returns false.)
950 return a ? a->equals(b) : (a == b);
951}
952
954 return fEffect == rhs.fEffect && skdata_matches(fUniforms.get(), rhs.fUniforms.get());
955}
956
957static void gather_runtime_effect_uniforms(const KeyContext& keyContext,
958 const SkRuntimeEffect* effect,
959 SkSpan<const Uniform> graphiteUniforms,
960 const SkData* uniformData,
961 PipelineDataGatherer* gatherer) {
962 if (!uniformData) {
963 return; // precompiling
964 }
965
966 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, graphiteUniforms);)
967
968 SkSpan<const SkRuntimeEffect::Uniform> rtsUniforms = effect->uniforms();
969
970 if (!rtsUniforms.empty() && uniformData) {
971 // Collect all the other uniforms from the provided SkData.
972 const uint8_t* uniformBase = uniformData->bytes();
973 for (size_t index = 0; index < rtsUniforms.size(); ++index) {
974 const Uniform& uniform = graphiteUniforms[index];
975 // Get a pointer to the offset in our data for this uniform.
976 const uint8_t* uniformPtr = uniformBase + rtsUniforms[index].offset;
977 // Pass the uniform data to the gatherer.
978 gatherer->write(uniform, uniformPtr);
979 }
980 }
981
983 SkColorSpace* dstCS = keyContext.dstColorInfo().colorSpace();
984 if (!dstCS) {
985 dstCS = sk_srgb_linear_singleton(); // turn colorspace conversion into a noop
986 }
987
988 // TODO(b/332565302): If the runtime shader only uses one of these
989 // transforms, we could upload only one set of uniforms.
996 dstCS,
998
999 add_color_space_uniforms(dstToLinear.fSteps, ReadSwizzle::kRGBA, gatherer);
1000 add_color_space_uniforms(linearToDst.fSteps, ReadSwizzle::kRGBA, gatherer);
1001 }
1002}
1003
1005 PaintParamsKeyBuilder* builder,
1006 PipelineDataGatherer* gatherer,
1007 const ShaderData& shaderData) {
1008 ShaderCodeDictionary* dict = keyContext.dict();
1009 int codeSnippetID = dict->findOrCreateRuntimeEffectSnippet(shaderData.fEffect.get());
1010
1012 keyContext.rtEffectDict()->set(codeSnippetID, shaderData.fEffect);
1013 }
1014
1015 const ShaderSnippet* entry = dict->getEntry(codeSnippetID);
1016 SkASSERT(entry);
1017
1019 shaderData.fEffect.get(),
1020 entry->fUniforms,
1021 shaderData.fUniforms.get(),
1022 gatherer);
1023
1024 builder->beginBlock(codeSnippetID);
1025}
1026
1027// ==================================================================
1028
1029namespace {
1030
1031void add_to_key(const KeyContext& keyContext,
1032 PaintParamsKeyBuilder* builder,
1033 PipelineDataGatherer* gatherer,
1034 const SkBlendModeBlender* blender) {
1035 SkASSERT(blender);
1036
1037 AddModeBlend(keyContext, builder, gatherer, blender->mode());
1038}
1039
1040// Be sure to keep this function in sync w/ its correlate in FactoryFunctions.cpp
1041void add_children_to_key(const KeyContext& keyContext,
1042 PaintParamsKeyBuilder* builder,
1043 PipelineDataGatherer* gatherer,
1046 SkASSERT(children.size() == childInfo.size());
1047
1049
1050 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1051
1052 for (size_t index = 0; index < children.size(); ++index) {
1053 const SkRuntimeEffect::ChildPtr& child = children[index];
1054 std::optional<ChildType> type = child.type();
1055 if (type == ChildType::kShader) {
1056 AddToKey(childContext, builder, gatherer, child.shader());
1057 } else if (type == ChildType::kColorFilter) {
1058 AddToKey(childContext, builder, gatherer, child.colorFilter());
1059 } else if (type == ChildType::kBlender) {
1060 AddToKey(childContext, builder, gatherer, child.blender());
1061 } else {
1062 // We don't have a child effect. Substitute in a no-op effect.
1063 switch (childInfo[index].type) {
1064 case ChildType::kShader:
1065 // A missing shader returns transparent black
1066 SolidColorShaderBlock::AddBlock(childContext, builder, gatherer,
1068 break;
1069
1070 case ChildType::kColorFilter:
1071 // A "passthrough" color filter returns the input color as-is.
1073 break;
1074
1075 case ChildType::kBlender:
1076 // A "passthrough" blender performs `blend_src_over(src, dest)`.
1077 AddKnownModeBlend(childContext, builder, gatherer, SkBlendMode::kSrcOver);
1078 break;
1079 }
1080 }
1081 }
1082}
1083
1084void add_to_key(const KeyContext& keyContext,
1085 PaintParamsKeyBuilder* builder,
1086 PipelineDataGatherer* gatherer,
1087 const SkRuntimeBlender* blender) {
1088 SkASSERT(blender);
1089 sk_sp<SkRuntimeEffect> effect = blender->effect();
1090 SkASSERT(effect);
1092 effect->uniforms(),
1093 blender->uniforms(),
1094 keyContext.dstColorInfo().colorSpace());
1095 SkASSERT(uniforms);
1096
1097 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1098 { effect, std::move(uniforms) });
1099
1100 add_children_to_key(keyContext, builder, gatherer,
1101 blender->children(), effect->children());
1102
1103 builder->endBlock();
1104}
1105
1106void notify_in_use(Recorder* recorder,
1107 DrawContext* drawContext,
1109 for (const auto& child : children) {
1110 if (child.type().has_value()) {
1111 switch (*child.type()) {
1112 case SkRuntimeEffect::ChildType::kShader:
1113 NotifyImagesInUse(recorder, drawContext, child.shader());
1114 break;
1115 case SkRuntimeEffect::ChildType::kColorFilter:
1116 NotifyImagesInUse(recorder, drawContext, child.colorFilter());
1117 break;
1118 case SkRuntimeEffect::ChildType::kBlender:
1119 NotifyImagesInUse(recorder, drawContext, child.blender());
1120 break;
1121 }
1122 } // else a null child is a no-op, so cannot sample an image
1123 }
1124}
1125
1126} // anonymous namespace
1127
1128void AddToKey(const KeyContext& keyContext,
1129 PaintParamsKeyBuilder* builder,
1130 PipelineDataGatherer* gatherer,
1131 const SkBlender* blender) {
1132 if (!blender) {
1133 return;
1134 }
1135 switch (as_BB(blender)->type()) {
1136#define M(type) \
1137 case SkBlenderBase::BlenderType::k##type: \
1138 add_to_key(keyContext, \
1139 builder, \
1140 gatherer, \
1141 static_cast<const Sk##type##Blender*>(blender)); \
1142 return;
1144#undef M
1145 }
1147}
1148
1149void NotifyImagesInUse(Recorder* recorder, DrawContext* drawContext, const SkBlender* blender) {
1150 if (!blender) {
1151 return;
1152 }
1153 if (as_BB(blender)->type() == SkBlenderBase::BlenderType::kRuntime) {
1154 const auto* rbb = static_cast<const SkRuntimeBlender*>(blender);
1155 notify_in_use(recorder, drawContext, rbb->children());
1156 } // else blend mode doesn't reference images
1157}
1158
1159//--------------------------------------------------------------------------------------------------
1160//--------------------------------------------------------------------------------------------------
1162 SkPMColor4f color = {c.fR, c.fG, c.fB, c.fA};
1164 return color;
1165}
1166static void add_to_key(const KeyContext& keyContext,
1167 PaintParamsKeyBuilder* builder,
1168 PipelineDataGatherer* gatherer,
1169 const SkBlendModeColorFilter* filter) {
1170 SkASSERT(filter);
1171
1173 keyContext.dstColorInfo().colorSpace());
1174
1175 AddBlendModeColorFilter(keyContext, builder, gatherer, filter->mode(), color);
1176}
1177
1178static void add_to_key(const KeyContext& keyContext,
1179 PaintParamsKeyBuilder* builder,
1180 PipelineDataGatherer* gatherer,
1181 const SkColorSpaceXformColorFilter* filter) {
1182 SkASSERT(filter);
1183
1184 constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
1185 ColorSpaceTransformBlock::ColorSpaceTransformData csData(filter->src().get(), kAlphaType,
1186 filter->dst().get(), kAlphaType);
1187 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
1188}
1189
1190static void add_to_key(const KeyContext& keyContext,
1191 PaintParamsKeyBuilder* keyBuilder,
1192 PipelineDataGatherer* gatherer,
1193 const SkComposeColorFilter* filter) {
1194 SkASSERT(filter);
1195
1196 Compose(keyContext, keyBuilder, gatherer,
1197 /* addInnerToKey= */ [&]() -> void {
1198 AddToKey(keyContext, keyBuilder, gatherer, filter->inner().get());
1199 },
1200 /* addOuterToKey= */ [&]() -> void {
1201 AddToKey(keyContext, keyBuilder, gatherer, filter->outer().get());
1202 });
1203}
1204
1205static void add_to_key(const KeyContext& keyContext,
1206 PaintParamsKeyBuilder* builder,
1207 PipelineDataGatherer* gatherer,
1208 const SkGaussianColorFilter*) {
1210}
1211
1212static void add_to_key(const KeyContext& keyContext,
1213 PaintParamsKeyBuilder* builder,
1214 PipelineDataGatherer* gatherer,
1215 const SkMatrixColorFilter* filter) {
1216 SkASSERT(filter);
1217
1218 bool inHSLA = filter->domain() == SkMatrixColorFilter::Domain::kHSLA;
1219 MatrixColorFilterBlock::MatrixColorFilterData matrixCFData(filter->matrix(), inHSLA);
1220
1221 MatrixColorFilterBlock::AddBlock(keyContext, builder, gatherer, matrixCFData);
1222}
1223
1224static void add_to_key(const KeyContext& keyContext,
1225 PaintParamsKeyBuilder* builder,
1226 PipelineDataGatherer* gatherer,
1227 const SkRuntimeColorFilter* filter) {
1228 SkASSERT(filter);
1229
1230 sk_sp<SkRuntimeEffect> effect = filter->effect();
1232 effect->uniforms(), filter->uniforms(), keyContext.dstColorInfo().colorSpace());
1233 SkASSERT(uniforms);
1234
1235 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, {effect, std::move(uniforms)});
1236
1237 add_children_to_key(keyContext, builder, gatherer,
1238 filter->children(), effect->children());
1239
1240 builder->endBlock();
1241}
1242
1243static void add_to_key(const KeyContext& keyContext,
1244 PaintParamsKeyBuilder* builder,
1245 PipelineDataGatherer* gatherer,
1246 const SkTableColorFilter* filter) {
1247 SkASSERT(filter);
1248
1250 filter->bitmap());
1251 if (!proxy) {
1252 SKGPU_LOG_W("Couldn't create TableColorFilter's table");
1253
1254 // Return the input color as-is.
1255 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1256 return;
1257 }
1258
1259 TableColorFilterBlock::TableColorFilterData data(std::move(proxy));
1260
1261 TableColorFilterBlock::AddBlock(keyContext, builder, gatherer, data);
1262}
1263
1264static void add_to_key(const KeyContext& keyContext,
1265 PaintParamsKeyBuilder* builder,
1266 PipelineDataGatherer* gatherer,
1267 const SkWorkingFormatColorFilter* filter) {
1268 SkASSERT(filter);
1269
1270 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
1271 const SkAlphaType dstAT = dstInfo.alphaType();
1272 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
1273 if (!dstCS) {
1274 dstCS = SkColorSpace::MakeSRGB();
1275 }
1276
1277 SkAlphaType workingAT;
1278 sk_sp<SkColorSpace> workingCS = filter->workingFormat(dstCS, &workingAT);
1279 SkColorInfo workingInfo(dstInfo.colorType(), workingAT, workingCS);
1280 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
1281
1282 // Use two nested compose blocks to chain (dst->working), child, and (working->dst) together
1283 // while appearing as one block to the parent node.
1284 Compose(keyContext, builder, gatherer,
1285 /* addInnerToKey= */ [&]() -> void {
1286 // Inner compose
1287 Compose(keyContext, builder, gatherer,
1288 /* addInnerToKey= */ [&]() -> void {
1289 // Innermost (inner of inner compose)
1291 dstCS.get(), dstAT, workingCS.get(), workingAT);
1292 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
1293 data1);
1294 },
1295 /* addOuterToKey= */ [&]() -> void {
1296 // Middle (outer of inner compose)
1297 AddToKey(workingContext, builder, gatherer, filter->child().get());
1298 });
1299 },
1300 /* addOuterToKey= */ [&]() -> void {
1301 // Outermost (outer of outer compose)
1303 workingCS.get(), workingAT, dstCS.get(), dstAT);
1304 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data2);
1305 });
1306}
1307
1308void AddToKey(const KeyContext& keyContext,
1309 PaintParamsKeyBuilder* builder,
1310 PipelineDataGatherer* gatherer,
1311 const SkColorFilter* filter) {
1312 if (!filter) {
1313 return;
1314 }
1315 switch (as_CFB(filter)->type()) {
1317 // Return the input color as-is.
1318 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1319 return;
1320#define M(type) \
1321 case SkColorFilterBase::Type::k##type: \
1322 add_to_key(keyContext, \
1323 builder, \
1324 gatherer, \
1325 static_cast<const Sk##type##ColorFilter*>(filter)); \
1326 return;
1328#undef M
1329 }
1331}
1332
1333void NotifyImagesInUse(Recorder* recorder, DrawContext* drawContext, const SkColorFilter* filter) {
1334 if (!filter) {
1335 return;
1336 }
1337 if (as_CFB(filter)->type() == SkColorFilterBase::Type::kCompose) {
1338 // Recurse to two children
1339 const auto* cf = static_cast<const SkComposeColorFilter*>(filter);
1340 NotifyImagesInUse(recorder, drawContext, cf->inner().get());
1341 NotifyImagesInUse(recorder, drawContext, cf->outer().get());
1342 } else if (as_CFB(filter)->type() == SkColorFilterBase::Type::kWorkingFormat) {
1343 // Recurse to one child
1344 const auto* wfcf = static_cast<const SkWorkingFormatColorFilter*>(filter);
1345 NotifyImagesInUse(recorder, drawContext, wfcf->child().get());
1346 } else if (as_CFB(filter)->type() == SkColorFilterBase::Type::kRuntime) {
1347 // Recurse to all children
1348 const auto* rcf = static_cast<const SkRuntimeColorFilter*>(filter);
1349 notify_in_use(recorder, drawContext, rcf->children());
1350 } // else other color filters do not rely on SkImages
1351}
1352
1353// ==================================================================
1354
1355static void add_to_key(const KeyContext& keyContext,
1356 PaintParamsKeyBuilder* builder,
1357 PipelineDataGatherer* gatherer,
1358 const SkBlendShader* shader) {
1359 SkASSERT(shader);
1360
1361 Blend(keyContext, builder, gatherer,
1362 /* addBlendToKey= */ [&] () -> void {
1363 AddModeBlend(keyContext, builder, gatherer, shader->mode());
1364 },
1365 /* addSrcToKey= */ [&]() -> void {
1366 AddToKey(keyContext, builder, gatherer, shader->src().get());
1367 },
1368 /* addDstToKey= */ [&]() -> void {
1369 AddToKey(keyContext, builder, gatherer, shader->dst().get());
1370 });
1371}
1372static void notify_in_use(Recorder* recorder,
1373 DrawContext* drawContext,
1374 const SkBlendShader* shader) {
1375 // SkBlendShader uses a fixed blend mode, so there's no blender to recurse through
1376 NotifyImagesInUse(recorder, drawContext, shader->src().get());
1377 NotifyImagesInUse(recorder, drawContext, shader->dst().get());
1378}
1379
1380static void add_to_key(const KeyContext& keyContext,
1381 PaintParamsKeyBuilder* builder,
1382 PipelineDataGatherer* gatherer,
1383 const SkCTMShader* shader) {
1384 // CTM shaders are always given device coordinates, so we don't have to modify the CTM itself
1385 // with keyContext's local transform.
1386 LocalMatrixShaderBlock::LMShaderData lmShaderData(shader->ctm());
1387
1388 KeyContextWithLocalMatrix newContext(keyContext, shader->ctm());
1389
1390 LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
1391
1392 AddToKey(newContext, builder, gatherer, shader->proxyShader().get());
1393
1394 builder->endBlock();
1395}
1396static void notify_in_use(Recorder* recorder, DrawContext* drawContext, const SkCTMShader* shader) {
1397 NotifyImagesInUse(recorder, drawContext, shader->proxyShader().get());
1398}
1399
1400static void add_to_key(const KeyContext& keyContext,
1401 PaintParamsKeyBuilder* builder,
1402 PipelineDataGatherer* gatherer,
1403 const SkColorShader* shader) {
1404 SkASSERT(shader);
1405
1406 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer,
1407 SkColor4f::FromColor(shader->color()).premul());
1408}
1410 // No-op
1411}
1412
1413static void add_to_key(const KeyContext& keyContext,
1414 PaintParamsKeyBuilder* builder,
1415 PipelineDataGatherer* gatherer,
1416 const SkColor4Shader* shader) {
1417 SkASSERT(shader);
1418
1419 SkPMColor4f color = map_color(shader->color(), shader->colorSpace().get(),
1420 keyContext.dstColorInfo().colorSpace());
1421
1422 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, color);
1423}
1425 // No-op
1426}
1427
1428static void add_to_key(const KeyContext& keyContext,
1429 PaintParamsKeyBuilder* builder,
1430 PipelineDataGatherer* gatherer,
1431 const SkColorFilterShader* shader) {
1432 SkASSERT(shader);
1433
1434 Compose(keyContext, builder, gatherer,
1435 /* addInnerToKey= */ [&]() -> void {
1436 AddToKey(keyContext, builder, gatherer, shader->shader().get());
1437 },
1438 /* addOuterToKey= */ [&]() -> void {
1439 AddToKey(keyContext, builder, gatherer, shader->filter().get());
1440 });
1441}
1442static void notify_in_use(Recorder* recorder,
1443 DrawContext* drawContext,
1444 const SkColorFilterShader* shader) {
1445 NotifyImagesInUse(recorder, drawContext, shader->shader().get());
1446 NotifyImagesInUse(recorder, drawContext, shader->filter().get());
1447}
1448
1449static void add_to_key(const KeyContext& keyContext,
1450 PaintParamsKeyBuilder* builder,
1451 PipelineDataGatherer* gatherer,
1452 const SkCoordClampShader* shader) {
1453 SkASSERT(shader);
1454
1456
1457 CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
1458 AddToKey(keyContext, builder, gatherer, shader->shader().get());
1459 builder->endBlock();
1460}
1461static void notify_in_use(Recorder* recorder,
1462 DrawContext* drawContext,
1463 const SkCoordClampShader* shader) {
1464 NotifyImagesInUse(recorder, drawContext, shader->shader().get());
1465}
1466
1467static void add_to_key(const KeyContext& keyContext,
1468 PaintParamsKeyBuilder* builder,
1469 PipelineDataGatherer* gatherer,
1470 const SkEmptyShader*) {
1471 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1472}
1474 // No-op
1475}
1476
1477static void add_yuv_image_to_key(const KeyContext& keyContext,
1478 PaintParamsKeyBuilder* builder,
1479 PipelineDataGatherer* gatherer,
1480 const SkImageShader* origShader,
1481 sk_sp<const SkImage> imageToDraw,
1482 SkSamplingOptions sampling) {
1483 SkASSERT(!imageToDraw->isAlphaOnly());
1484
1485 const Image_YUVA* yuvaImage = static_cast<const Image_YUVA*>(imageToDraw.get());
1486 const SkYUVAInfo& yuvaInfo = yuvaImage->yuvaInfo();
1487 // We would want to add a translation to the local matrix to handle other sitings.
1490 YUVImageShaderBlock::ImageData imgData(sampling,
1491 origShader->tileModeX(),
1492 origShader->tileModeY(),
1493 imageToDraw->dimensions(),
1494 origShader->subset());
1495 for (int locIndex = 0; locIndex < SkYUVAInfo::kYUVAChannelCount; ++locIndex) {
1496 const TextureProxyView& view = yuvaImage->proxyView(locIndex);
1497 if (view) {
1498 imgData.fTextureProxies[locIndex] = view.refProxy();
1499 // The view's swizzle has the data channel for the YUVA location in all slots, so read
1500 // the 0th slot to determine fChannelSelect
1501 switch(view.swizzle()[0]) {
1502 case 'r': imgData.fChannelSelect[locIndex] = {1.f, 0.f, 0.f, 0.f}; break;
1503 case 'g': imgData.fChannelSelect[locIndex] = {0.f, 1.f, 0.f, 0.f}; break;
1504 case 'b': imgData.fChannelSelect[locIndex] = {0.f, 0.f, 1.f, 0.f}; break;
1505 case 'a': imgData.fChannelSelect[locIndex] = {0.f, 0.f, 0.f, 1.f}; break;
1506 default:
1507 imgData.fChannelSelect[locIndex] = {0.f, 0.f, 0.f, 0.f};
1508 SkDEBUGFAILF("Unexpected swizzle for YUVA data: %c", view.swizzle()[0]);
1509 break;
1510 }
1511 } else {
1512 // Only the A proxy view should be null, in which case we bind the Y proxy view to
1513 // pass validation and send all 1s for the channel selection to signal opaque alpha.
1514 SkASSERT(locIndex == 3);
1515 imgData.fTextureProxies[locIndex] = yuvaImage->proxyView(SkYUVAInfo::kY).refProxy();
1516 imgData.fChannelSelect[locIndex] = {1.f, 1.f, 1.f, 1.f};
1517 }
1518 }
1519
1520 auto [ssx, ssy] = yuvaImage->uvSubsampleFactors();
1521 if (ssx > 1 || ssy > 1) {
1522 // We need to adjust the image size we use for sampling to reflect the actual image size of
1523 // the UV planes. However, since our coordinates are in Y's texel space we need to scale
1524 // accordingly.
1525 const TextureProxyView& view = yuvaImage->proxyView(SkYUVAInfo::kU);
1526 imgData.fImgSizeUV = {view.dimensions().width()*ssx, view.dimensions().height()*ssy};
1527 // This promotion of nearest to linear filtering for UV planes exists to mimic
1528 // libjpeg[-turbo]'s do_fancy_upsampling option. We will filter the subsampled plane,
1529 // however we want to filter at a fixed point for each logical image pixel to simulate
1530 // nearest neighbor. In the shader we detect that the UV filtermode doesn't match the Y
1531 // filtermode, and snap to Y pixel centers.
1532 if (imgData.fSampling.filter == SkFilterMode::kNearest) {
1534 imgData.fSampling.mipmap);
1535 // Consider a logical image pixel at the edge of the subset. When computing the logical
1536 // pixel color value we should use a blend of two values from the subsampled plane.
1537 // Depending on where the subset edge falls in actual subsampled plane, one of those
1538 // values may come from outside the subset. Hence, we use this custom inset which
1539 // applies the wrap mode to the subset but allows linear filtering to read pixels from
1540 // that are just outside the subset. We only want to apply this offset in non-decal
1541 // modes, or when the image view size is not a multiple of the UV subsampling factor.
1542 if (imgData.fTileModes[0] != SkTileMode::kDecal ||
1543 view.dimensions().width()*ssx > yuvaInfo.width()) {
1544 imgData.fLinearFilterUVInset.fX = 1.f/(2*ssx);
1545 }
1546 if (imgData.fTileModes[1] != SkTileMode::kDecal ||
1547 view.dimensions().height()*ssy > yuvaInfo.height()) {
1548 imgData.fLinearFilterUVInset.fY = 1.f/(2*ssy);
1549 }
1550 }
1551 // Need to scale this just like we scale the image size
1552 imgData.fLinearFilterUVInset = {imgData.fLinearFilterUVInset.fX*ssx,
1553 imgData.fLinearFilterUVInset.fY*ssy};
1554 }
1555
1556 float yuvM[20];
1557 SkColorMatrix_YUV2RGB(yuvaInfo.yuvColorSpace(), yuvM);
1558 // We drop the fourth column entirely since the transformation
1559 // should not depend on alpha. The fifth column is sent as a separate
1560 // vector. The fourth row is also dropped entirely because alpha should
1561 // never be modified.
1562 SkASSERT(yuvM[3] == 0 && yuvM[8] == 0 && yuvM[13] == 0 && yuvM[18] == 1);
1563 SkASSERT(yuvM[15] == 0 && yuvM[16] == 0 && yuvM[17] == 0 && yuvM[19] == 0);
1564 imgData.fYUVtoRGBMatrix.setAll(
1565 yuvM[ 0], yuvM[ 1], yuvM[ 2],
1566 yuvM[ 5], yuvM[ 6], yuvM[ 7],
1567 yuvM[10], yuvM[11], yuvM[12]
1568 );
1569 imgData.fYUVtoRGBTranslate = {yuvM[4], yuvM[9], yuvM[14]};
1570
1571 // The YUV formats can encode their own origin including reflection and rotation,
1572 // so we need to wrap our block in an additional local matrix transform.
1573 SkMatrix originMatrix = yuvaInfo.originMatrix();
1574 LocalMatrixShaderBlock::LMShaderData lmShaderData(originMatrix);
1575
1576 KeyContextWithLocalMatrix newContext(keyContext, originMatrix);
1577
1579 SkASSERT(steps.flags.mask() == 0); // By default, the colorspace should have no effect
1580 if (!origShader->isRaw()) {
1581 steps = SkColorSpaceXformSteps(imageToDraw->colorSpace(),
1582 imageToDraw->alphaType(),
1583 keyContext.dstColorInfo().colorSpace(),
1584 keyContext.dstColorInfo().alphaType());
1585 }
1587
1588 Compose(keyContext, builder, gatherer,
1589 /* addInnerToKey= */ [&]() -> void {
1590 LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
1591 YUVImageShaderBlock::AddBlock(newContext, builder, gatherer, imgData);
1592 builder->endBlock();
1593 },
1594 /* addOuterToKey= */ [&]() -> void {
1595 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
1596 });
1597}
1598
1600 if (swizzle == skgpu::Swizzle::RGBA()) {
1602 } else if (swizzle == skgpu::Swizzle::RGB1()) {
1604 } else if (swizzle == skgpu::Swizzle("rrr1")) {
1606 } else if (swizzle == skgpu::Swizzle::BGRA()) {
1608 } else if (swizzle == skgpu::Swizzle("000r")) {
1610 } else {
1611 SKGPU_LOG_W("%s is an unsupported read swizzle. Defaulting to RGBA.\n",
1612 swizzle.asString().data());
1614 }
1615}
1616
1617static void add_to_key(const KeyContext& keyContext,
1618 PaintParamsKeyBuilder* builder,
1619 PipelineDataGatherer* gatherer,
1620 const SkImageShader* shader) {
1621 SkASSERT(shader);
1622
1623 auto [ imageToDraw, newSampling ] = GetGraphiteBacked(keyContext.recorder(),
1624 shader->image().get(),
1625 shader->sampling());
1626 if (!imageToDraw) {
1627 SKGPU_LOG_W("Couldn't convert ImageShader's image to a Graphite-backed image");
1628 builder->addBlock(BuiltInCodeSnippetID::kError);
1629 return;
1630 }
1631 if (as_IB(imageToDraw)->isYUVA()) {
1632 return add_yuv_image_to_key(keyContext,
1633 builder,
1634 gatherer,
1635 shader,
1636 std::move(imageToDraw),
1637 newSampling);
1638 }
1639
1640 auto view = AsView(imageToDraw.get());
1641 SkASSERT(newSampling.mipmap == SkMipmapMode::kNone || view.mipmapped() == Mipmapped::kYes);
1642
1643 ImageShaderBlock::ImageData imgData(shader->sampling(),
1644 shader->tileModeX(),
1645 shader->tileModeY(),
1646 view.proxy()->dimensions(),
1647 shader->subset(),
1649 imgData.fSampling = newSampling;
1650 imgData.fTextureProxy = view.refProxy();
1651 skgpu::Swizzle readSwizzle = view.swizzle();
1652 // If the color type is alpha-only, propagate the alpha value to the other channels.
1653 if (imageToDraw->isAlphaOnly()) {
1654 readSwizzle = skgpu::Swizzle::Concat(readSwizzle, skgpu::Swizzle("000a"));
1655 }
1656 imgData.fReadSwizzle = swizzle_class_to_read_enum(readSwizzle);
1657
1658 if (!shader->isRaw()) {
1659 imgData.fSteps = SkColorSpaceXformSteps(imageToDraw->colorSpace(),
1660 imageToDraw->alphaType(),
1661 keyContext.dstColorInfo().colorSpace(),
1662 keyContext.dstColorInfo().alphaType());
1663
1664 if (imageToDraw->isAlphaOnly() && keyContext.scope() != KeyContext::Scope::kRuntimeEffect) {
1665 Blend(keyContext, builder, gatherer,
1666 /* addBlendToKey= */ [&] () -> void {
1667 AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kDstIn);
1668 },
1669 /* addSrcToKey= */ [&] () -> void {
1670 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
1671 },
1672 /* addDstToKey= */ [&]() -> void {
1673 RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
1674 });
1675 return;
1676 }
1677 }
1678
1679 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
1680}
1681static void notify_in_use(Recorder* recorder,
1682 DrawContext*,
1683 const SkImageShader* shader) {
1684 auto image = as_IB(shader->image());
1685 if (!image->isGraphiteBacked()) {
1686 // If it's not graphite-backed, there's no pending graphite work.
1687 return;
1688 }
1689
1690 // TODO(b/323887207): Once scratch devices are linked to special images and their use needs to
1691 // be linked to specific draw contexts, that will be passed in here.
1692 static_cast<Image_Base*>(image)->notifyInUse(recorder);
1693}
1694
1695static void add_to_key(const KeyContext& keyContext,
1696 PaintParamsKeyBuilder* builder,
1697 PipelineDataGatherer* gatherer,
1698 const SkLocalMatrixShader* shader) {
1699 SkASSERT(shader);
1700 auto wrappedShader = shader->wrappedShader().get();
1701
1702 // Fold the texture's origin flip into the local matrix so that the image shader doesn't need
1703 // additional state
1704 SkMatrix matrix;
1705 if (as_SB(wrappedShader)->type() == SkShaderBase::ShaderType::kImage) {
1706 auto imgShader = static_cast<const SkImageShader*>(wrappedShader);
1707 // If the image is not graphite backed then we can assume the origin will be TopLeft as we
1708 // require that in the ImageProvider utility. Also Graphite YUV images are assumed to be
1709 // TopLeft origin.
1710 // TODO (b/336788317): Fold YUVAImage's origin into this matrix as well.
1711 auto imgBase = as_IB(imgShader->image());
1712 if (imgBase->isGraphiteBacked() && !imgBase->isYUVA()) {
1713 auto imgGraphite = static_cast<Image*>(imgBase);
1714 SkASSERT(imgGraphite);
1715 const auto& view = imgGraphite->textureProxyView();
1716 if (view.origin() == Origin::kBottomLeft) {
1717 matrix.setScaleY(-1);
1718 matrix.setTranslateY(view.height());
1719 }
1720 }
1721 }
1722
1723 matrix.postConcat(shader->localMatrix());
1724 LocalMatrixShaderBlock::LMShaderData lmShaderData(matrix);
1725
1726 KeyContextWithLocalMatrix newContext(keyContext, matrix);
1727
1728 LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
1729
1730 AddToKey(newContext, builder, gatherer, wrappedShader);
1731
1732 builder->endBlock();
1733}
1734
1735static void notify_in_use(Recorder* recorder,
1736 DrawContext* drawContext,
1737 const SkLocalMatrixShader* shader) {
1738 NotifyImagesInUse(recorder, drawContext, shader->wrappedShader().get());
1739}
1740
1741// If either of these change then the corresponding change must also be made in the SkSL
1742// perlin_noise_shader function.
1747static void add_to_key(const KeyContext& keyContext,
1748 PaintParamsKeyBuilder* builder,
1749 PipelineDataGatherer* gatherer,
1750 const SkPerlinNoiseShader* shader) {
1751 SkASSERT(shader);
1752 SkASSERT(shader->numOctaves());
1753
1754 std::unique_ptr<SkPerlinNoiseShader::PaintingData> paintingData = shader->getPaintingData();
1755 paintingData->generateBitmaps();
1756
1758 keyContext.recorder(), paintingData->getPermutationsBitmap());
1759
1760 sk_sp<TextureProxy> noise =
1761 RecorderPriv::CreateCachedProxy(keyContext.recorder(), paintingData->getNoiseBitmap());
1762
1763 if (!perm || !noise) {
1764 SKGPU_LOG_W("Couldn't create tables for PerlinNoiseShader");
1765 builder->addBlock(BuiltInCodeSnippetID::kError);
1766 return;
1767 }
1768
1770 static_cast<PerlinNoiseShaderBlock::Type>(shader->noiseType()),
1771 paintingData->fBaseFrequency,
1772 shader->numOctaves(),
1773 {paintingData->fStitchDataInit.fWidth, paintingData->fStitchDataInit.fHeight});
1774
1775 perlinData.fPermutationsProxy = std::move(perm);
1776 perlinData.fNoiseProxy = std::move(noise);
1777
1778 PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, perlinData);
1779}
1781 // No-op, perlin noise has no children.
1782}
1783
1784static void add_to_key(const KeyContext& keyContext,
1785 PaintParamsKeyBuilder* builder,
1786 PipelineDataGatherer* gatherer,
1787 const SkPictureShader* shader) {
1788 SkASSERT(shader);
1789
1790 Recorder* recorder = keyContext.recorder();
1791 const Caps* caps = recorder->priv().caps();
1792
1793 // TODO: We'll need additional plumbing to get the correct props from our callers. In
1794 // particular we'll need to expand the keyContext to have the surfaceProps.
1795 SkSurfaceProps props{};
1796
1797 SkMatrix totalM = keyContext.local2Dev().asM33();
1798 if (keyContext.localMatrix()) {
1799 totalM.preConcat(*keyContext.localMatrix());
1800 }
1802 totalM,
1803 keyContext.dstColorInfo().colorType(),
1804 keyContext.dstColorInfo().colorSpace(),
1805 caps->maxTextureSize(),
1806 props);
1807 if (!info.success) {
1808 SKGPU_LOG_W("Couldn't access PictureShaders' Image info");
1809 builder->addBlock(BuiltInCodeSnippetID::kError);
1810 return;
1811 }
1812
1813 // TODO: right now we're explicitly not caching here. We could expand the ImageProvider
1814 // API to include already Graphite-backed images, add a Recorder-local cache or add
1815 // rendered-picture images to the global cache.
1816 sk_sp<SkImage> img = info.makeImage(
1817 SkSurfaces::RenderTarget(recorder, info.imageInfo, skgpu::Mipmapped::kNo, &info.props),
1818 shader->picture().get());
1819 if (!img) {
1820 SKGPU_LOG_W("Couldn't create SkImage for PictureShader");
1821 builder->addBlock(BuiltInCodeSnippetID::kError);
1822 return;
1823 }
1824
1825 const auto shaderLM = SkMatrix::Scale(1.f/info.tileScale.width(), 1.f/info.tileScale.height());
1826 sk_sp<SkShader> imgShader = img->makeShader(shader->tileModeX(), shader->tileModeY(),
1827 SkSamplingOptions(shader->filter()), &shaderLM);
1828 if (!imgShader) {
1829 SKGPU_LOG_W("Couldn't create SkImageShader for PictureShader");
1830 builder->addBlock(BuiltInCodeSnippetID::kError);
1831 return;
1832 }
1833
1834 AddToKey(keyContext, builder, gatherer, imgShader.get());
1835}
1837 // While the SkPicture the shader points to, may have Graphite-backed shaders that need to be
1838 // notified, that will happen when the picture is rendered into an image in add_to_key
1839}
1840
1841static void add_to_key(const KeyContext& keyContext,
1842 PaintParamsKeyBuilder* builder,
1843 PipelineDataGatherer* gatherer,
1844 const SkRuntimeShader* shader) {
1845 SkASSERT(shader);
1846 sk_sp<SkRuntimeEffect> effect = shader->effect();
1848 effect->uniforms(),
1849 shader->uniformData(keyContext.dstColorInfo().colorSpace()),
1850 keyContext.dstColorInfo().colorSpace());
1851 SkASSERT(uniforms);
1852
1853 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1854 {effect, std::move(uniforms)});
1855
1856 add_children_to_key(keyContext, builder, gatherer,
1857 shader->children(), effect->children());
1858
1859 builder->endBlock();
1860}
1861static void notify_in_use(Recorder* recorder,
1862 DrawContext* drawContext,
1863 const SkRuntimeShader* shader) {
1864 notify_in_use(recorder, drawContext, shader->children());
1865}
1866
1867static void add_to_key(const KeyContext& keyContext,
1868 PaintParamsKeyBuilder* builder,
1869 PipelineDataGatherer* gatherer,
1870 const SkTransformShader* shader) {
1871 SKGPU_LOG_W("Raster-only SkShader (SkTransformShader) encountered");
1872 builder->addBlock(BuiltInCodeSnippetID::kError);
1873}
1875 // no-op
1876}
1877
1878static void add_to_key(const KeyContext& keyContext,
1879 PaintParamsKeyBuilder* builder,
1880 PipelineDataGatherer* gatherer,
1881 const SkTriColorShader* shader) {
1882 SKGPU_LOG_W("Raster-only SkShader (SkTriColorShader) encountered");
1883 builder->addBlock(BuiltInCodeSnippetID::kError);
1884}
1886 // no-op
1887}
1888
1889static void add_to_key(const KeyContext& keyContext,
1890 PaintParamsKeyBuilder* builder,
1891 PipelineDataGatherer* gatherer,
1892 const SkWorkingColorSpaceShader* shader) {
1893 SkASSERT(shader);
1894
1895 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
1896 const SkAlphaType dstAT = dstInfo.alphaType();
1897 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
1898 if (!dstCS) {
1899 dstCS = SkColorSpace::MakeSRGB();
1900 }
1901
1902 sk_sp<SkColorSpace> workingCS = shader->workingSpace();
1903 SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
1904 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
1905
1906 // Compose the inner shader (in the working space) with a (working->dst) transform:
1907 Compose(keyContext, builder, gatherer,
1908 /* addInnerToKey= */ [&]() -> void {
1909 AddToKey(workingContext, builder, gatherer, shader->shader().get());
1910 },
1911 /* addOuterToKey= */ [&]() -> void {
1913 workingCS.get(), dstAT, dstCS.get(), dstAT);
1914 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
1915 });
1916}
1917static void notify_in_use(Recorder* recorder,
1918 DrawContext* drawContext,
1919 const SkWorkingColorSpaceShader* shader) {
1920 NotifyImagesInUse(recorder, drawContext, shader->shader().get());
1921}
1922
1924 const SkPMColor4f* colors,
1925 const float* offsets) {
1926 SkBitmap colorsAndOffsetsBitmap;
1927
1928 colorsAndOffsetsBitmap.allocPixels(
1930
1931 for (int i = 0; i < numStops; i++) {
1932 // TODO: there should be a way to directly set a premul pixel in a bitmap with
1933 // a premul color.
1934 SkColor4f unpremulColor = colors[i].unpremul();
1935 colorsAndOffsetsBitmap.erase(unpremulColor, SkIRect::MakeXYWH(i, 0, 1, 1));
1936
1937 float offset = offsets ? offsets[i] : SkIntToFloat(i) / (numStops - 1);
1938 SkASSERT(offset >= 0.0f && offset <= 1.0f);
1939
1940 int exponent;
1941 float mantissa = frexp(offset, &exponent);
1942
1943 SkHalf halfE = SkFloatToHalf(exponent);
1944 if ((int)SkHalfToFloat(halfE) != exponent) {
1945 SKGPU_LOG_W("Encoding gradient to f16 failed");
1946 return {};
1947 }
1948
1949#if defined(SK_DEBUG)
1950 SkHalf halfM = SkFloatToHalf(mantissa);
1951
1952 float restored = ldexp(SkHalfToFloat(halfM), (int)SkHalfToFloat(halfE));
1953 float error = abs(restored - offset);
1954 SkASSERT(error < 0.001f);
1955#endif
1956
1957 // TODO: we're only using 2 of the f16s here. The encoding could be altered to better
1958 // preserve precision. This encoding yields < 0.001f error for 2^20 evenly spaced stops.
1959 colorsAndOffsetsBitmap.erase(SkColor4f{mantissa, (float)exponent, 0, 1},
1960 SkIRect::MakeXYWH(i, 1, 1, 1));
1961 }
1962
1963 return colorsAndOffsetsBitmap;
1964}
1965
1966// Please see GrGradientShader.cpp::make_interpolated_to_dst for substantial comments
1967// as to why this code is structured this way.
1968static void make_interpolated_to_dst(const KeyContext& keyContext,
1969 PaintParamsKeyBuilder* builder,
1970 PipelineDataGatherer* gatherer,
1971 const GradientShaderBlocks::GradientData& gradData,
1973 SkColorSpace* intermediateCS) {
1975
1976 bool inputPremul = static_cast<bool>(interp.fInPremul);
1977
1978 switch (interp.fColorSpace) {
1979 case ColorSpace::kLab:
1980 case ColorSpace::kOKLab:
1981 case ColorSpace::kOKLabGamutMap:
1982 case ColorSpace::kLCH:
1983 case ColorSpace::kOKLCH:
1984 case ColorSpace::kOKLCHGamutMap:
1985 case ColorSpace::kHSL:
1986 case ColorSpace::kHWB:
1987 inputPremul = false;
1988 break;
1989 default:
1990 break;
1991 }
1992
1993 const SkColorInfo& dstColorInfo = keyContext.dstColorInfo();
1994
1995 SkColorSpace* dstColorSpace =
1996 dstColorInfo.colorSpace() ? dstColorInfo.colorSpace() : sk_srgb_singleton();
1997
1998 SkAlphaType intermediateAlphaType = inputPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
1999
2001 intermediateCS, intermediateAlphaType, dstColorSpace, dstColorInfo.alphaType());
2002
2003 // The gradient block and colorSpace conversion block need to be combined
2004 // (via the Compose block) so that the localMatrix block can treat them as
2005 // one child.
2006 Compose(keyContext, builder, gatherer,
2007 /* addInnerToKey= */ [&]() -> void {
2008 GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
2009 },
2010 /* addOuterToKey= */ [&]() -> void {
2011 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
2012 });
2013}
2014
2015static void add_gradient_to_key(const KeyContext& keyContext,
2016 PaintParamsKeyBuilder* builder,
2017 PipelineDataGatherer* gatherer,
2018 const SkGradientBaseShader* shader,
2019 SkPoint point0,
2020 SkPoint point1,
2021 float radius0,
2022 float radius1,
2023 float bias,
2024 float scale) {
2025 SkColor4fXformer xformedColors(shader, keyContext.dstColorInfo().colorSpace());
2026 const SkPMColor4f* colors = xformedColors.fColors.begin();
2027 const float* positions = xformedColors.fPositions;
2028 const int colorCount = xformedColors.fColors.size();
2029
2030 sk_sp<TextureProxy> proxy;
2031
2033 if (shader->cachedBitmap().empty()) {
2034 SkBitmap colorsAndOffsetsBitmap =
2035 create_color_and_offset_bitmap(colorCount, colors, positions);
2036 if (colorsAndOffsetsBitmap.empty()) {
2037 SKGPU_LOG_W("Couldn't create GradientShader's color and offset bitmap");
2038 builder->addBlock(BuiltInCodeSnippetID::kError);
2039 return;
2040 }
2041 shader->setCachedBitmap(colorsAndOffsetsBitmap);
2042 }
2043
2044 proxy = RecorderPriv::CreateCachedProxy(keyContext.recorder(), shader->cachedBitmap());
2045 if (!proxy) {
2046 SKGPU_LOG_W("Couldn't create GradientShader's color and offset bitmap proxy");
2047 builder->addBlock(BuiltInCodeSnippetID::kError);
2048 return;
2049 }
2050 }
2051
2053 point0,
2054 point1,
2055 radius0,
2056 radius1,
2057 bias,
2058 scale,
2059 shader->getTileMode(),
2060 colorCount,
2061 colors,
2062 positions,
2063 std::move(proxy),
2064 shader->getInterpolation());
2065
2066 make_interpolated_to_dst(keyContext,
2067 builder,
2068 gatherer,
2069 data,
2070 shader->getInterpolation(),
2071 xformedColors.fIntermediateColorSpace.get());
2072}
2073
2074static void add_gradient_to_key(const KeyContext& keyContext,
2075 PaintParamsKeyBuilder* builder,
2076 PipelineDataGatherer* gatherer,
2077 const SkConicalGradient* shader) {
2078 add_gradient_to_key(keyContext,
2079 builder,
2080 gatherer,
2081 shader,
2082 shader->getStartCenter(),
2083 shader->getEndCenter(),
2084 shader->getStartRadius(),
2085 shader->getEndRadius(),
2086 0.0f,
2087 0.0f);
2088}
2089
2090static void add_gradient_to_key(const KeyContext& keyContext,
2091 PaintParamsKeyBuilder* builder,
2092 PipelineDataGatherer* gatherer,
2093 const SkLinearGradient* shader) {
2094 add_gradient_to_key(keyContext,
2095 builder,
2096 gatherer,
2097 shader,
2098 shader->start(),
2099 shader->end(),
2100 0.0f,
2101 0.0f,
2102 0.0f,
2103 0.0f);
2104}
2105
2106static void add_gradient_to_key(const KeyContext& keyContext,
2107 PaintParamsKeyBuilder* builder,
2108 PipelineDataGatherer* gatherer,
2109 const SkRadialGradient* shader) {
2110 add_gradient_to_key(keyContext,
2111 builder,
2112 gatherer,
2113 shader,
2114 shader->center(),
2115 { 0.0f, 0.0f },
2116 shader->radius(),
2117 0.0f,
2118 0.0f,
2119 0.0f);
2120}
2121
2122static void add_gradient_to_key(const KeyContext& keyContext,
2123 PaintParamsKeyBuilder* builder,
2124 PipelineDataGatherer* gatherer,
2125 const SkSweepGradient* shader) {
2126 add_gradient_to_key(keyContext,
2127 builder,
2128 gatherer,
2129 shader,
2130 shader->center(),
2131 { 0.0f, 0.0f },
2132 0.0f,
2133 0.0f,
2134 shader->tBias(),
2135 shader->tScale());
2136}
2137
2138static void add_to_key(const KeyContext& keyContext,
2139 PaintParamsKeyBuilder* builder,
2140 PipelineDataGatherer* gatherer,
2141 const SkGradientBaseShader* shader) {
2142 SkASSERT(shader);
2143 switch (shader->asGradient()) {
2144#define M(type) \
2145 case SkShaderBase::GradientType::k##type: \
2146 add_gradient_to_key(keyContext, \
2147 builder, \
2148 gatherer, \
2149 static_cast<const Sk##type##Gradient*>(shader)); \
2150 return;
2152#undef M
2154 SkDEBUGFAIL("Gradient shader says its type is none");
2155 return;
2156 }
2158}
2160 // Gradients do not have children, so no images to notify
2161}
2162
2163void AddToKey(const KeyContext& keyContext,
2164 PaintParamsKeyBuilder* builder,
2165 PipelineDataGatherer* gatherer,
2166 const SkShader* shader) {
2167 if (!shader) {
2168 return;
2169 }
2170 switch (as_SB(shader)->type()) {
2171#define M(type) \
2172 case SkShaderBase::ShaderType::k##type: \
2173 add_to_key(keyContext, \
2174 builder, \
2175 gatherer, \
2176 static_cast<const Sk##type##Shader*>(shader)); \
2177 return;
2179#undef M
2180 }
2182}
2183
2185 DrawContext* drawContext,
2186 const SkShader* shader) {
2187 if (!shader) {
2188 return;
2189 }
2190 switch (as_SB(shader)->type()) {
2191#define M(type) \
2192 case SkShaderBase::ShaderType::k##type: \
2193 notify_in_use(recorder, \
2194 drawContext, \
2195 static_cast<const Sk##type##Shader*>(shader)); \
2196 return;
2198#undef M
2199 }
2201}
2202
2203
2204} // namespace skgpu::graphite
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SkColor4f color
#define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
kUnpremul_SkAlphaType
SkAlphaType
Definition SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkUNREACHABLE
Definition SkAssert.h:135
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkDEBUGFAILF(fmt,...)
Definition SkAssert.h:119
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
@ kDstIn
r = d * sa
@ kSrcOver
r = s + (1-sa)*d
#define SK_ALL_BLENDERS(M)
SkBlenderBase * as_BB(SkBlender *blend)
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
#define SK_ALL_COLOR_FILTERS(M)
static SkColorFilterBase * as_CFB(SkColorFilter *filter)
SkColorSpace * sk_srgb_linear_singleton()
SkColorSpace * sk_srgb_singleton()
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static float2 interp(const float2 &v0, const float2 &v1, const float2 &t)
float SkHalfToFloat(SkHalf h)
Definition SkHalf.cpp:24
SkHalf SkFloatToHalf(float f)
Definition SkHalf.cpp:16
uint16_t SkHalf
Definition SkHalf.h:16
static SkImage_Base * as_IB(SkImage *image)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
#define SkIntToFloat(x)
Definition SkScalar.h:58
SkShaderBase * as_SB(SkShader *shader)
#define SK_ALL_GRADIENTS(M)
#define SK_ALL_SHADERS(M)
SkTileMode
Definition SkTileMode.h:13
void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20])
Type::kYUV Type::kRGBA() int(0.7 *637)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
bool empty() const
Definition SkBitmap.h:210
void erase(SkColor4f c, const SkIRect &area) const
Definition SkBitmap.cpp:420
SkBlendMode mode() const
sk_sp< SkShader > dst() const
SkBlendMode mode() const
sk_sp< SkShader > src() const
const SkMatrix & ctm() const
sk_sp< SkShader > proxyShader() const
SkColor4f color() const
sk_sp< SkColorSpace > colorSpace() const
sk_sp< SkColorFilterBase > filter() const
sk_sp< SkShader > shader() const
SkAlphaType alphaType() const
sk_sp< SkColorSpace > refColorSpace() const
SkColorSpace * colorSpace() const
SkColorType colorType() const
SkColor color() const
sk_sp< SkColorSpace > dst() const
sk_sp< SkColorSpace > src() const
static sk_sp< SkColorSpace > MakeSRGB()
sk_sp< SkColorFilterBase > inner() const
sk_sp< SkColorFilterBase > outer() const
const SkPoint & getEndCenter() const
SkScalar getEndRadius() const
const SkPoint & getStartCenter() const
SkScalar getStartRadius() const
sk_sp< SkShader > shader() const
const uint8_t * bytes() const
Definition SkData.h:43
const Interpolation & getInterpolation() const
void setCachedBitmap(SkBitmap b) const
const SkBitmap & cachedBitmap() const
SkTileMode getTileMode() const
SkSamplingOptions sampling() const
static SkM44 CubicResamplerMatrix(float B, float C)
SkTileMode tileModeX() const
sk_sp< SkImage > image() const
bool isRaw() const
SkTileMode tileModeY() const
SkRect subset() const
const SkPoint & start() const
const SkPoint & end() const
const SkMatrix & localMatrix() const
sk_sp< SkShader > wrappedShader() const
Definition SkM44.h:150
SkMatrix asM33() const
Definition SkM44.h:409
bool invert(SkM44 *inverse) const
Definition SkM44.cpp:247
SkM44 & setIdentity()
Definition SkM44.h:293
const float * matrix() const
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition SkMatrix.h:75
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition SkMatrix.h:562
SkMatrix & preConcat(const SkMatrix &other)
Definition SkMatrix.cpp:674
SkPerlinNoiseShaderType noiseType() const
std::unique_ptr< PaintingData > getPaintingData() const
SkRect tile() const
SkTileMode tileModeY() const
SkTileMode tileModeX() const
SkFilterMode filter() const
sk_sp< SkPicture > picture() const
SkScalar radius() const
const SkPoint & center() const
sk_sp< SkRuntimeEffect > effect() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
sk_sp< const SkData > uniforms() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
sk_sp< SkRuntimeEffect > effect() const
sk_sp< const SkData > uniforms() const
static sk_sp< const SkData > TransformUniforms(SkSpan< const SkRuntimeEffect::Uniform > uniforms, sk_sp< const SkData > originalData, const SkColorSpaceXformSteps &)
static bool UsesColorTransform(const SkRuntimeEffect *effect)
SkBlender * blender() const
std::optional< ChildType > type() const
SkColorFilter * colorFilter() const
SkSpan< const Uniform > uniforms() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
sk_sp< const SkData > uniformData(const SkColorSpace *dstCS) const
sk_sp< SkRuntimeEffect > effect() const
virtual GradientType asGradient(GradientInfo *info=nullptr, SkMatrix *localMatrix=nullptr) const
constexpr size_t size() const
Definition SkSpan_impl.h:95
const char * data() const
Definition SkString.h:132
SkScalar tBias() const
SkScalar tScale() const
const SkPoint & center() const
const SkBitmap & bitmap() const
sk_sp< SkShader > shader() const
sk_sp< SkColorSpace > workingSpace() const
sk_sp< SkColorFilter > child() const
sk_sp< SkColorSpace > workingFormat(const sk_sp< SkColorSpace > &dstCS, SkAlphaType *at) const
int width() const
Definition SkYUVAInfo.h:172
Siting sitingY() const
Definition SkYUVAInfo.h:177
SkMatrix originMatrix() const
Definition SkYUVAInfo.h:181
SkYUVColorSpace yuvColorSpace() const
Definition SkYUVAInfo.h:175
int height() const
Definition SkYUVAInfo.h:173
static constexpr int kYUVAChannelCount
Definition SkYUVAInfo.h:29
Siting sitingX() const
Definition SkYUVAInfo.h:176
T * get() const
Definition SkRefCnt.h:303
static constexpr Swizzle Concat(const Swizzle &a, const Swizzle &b)
Definition Swizzle.h:156
SkString asString() const
Definition Swizzle.cpp:46
static constexpr Swizzle BGRA()
Definition Swizzle.h:67
static constexpr Swizzle RGBA()
Definition Swizzle.h:66
static constexpr Swizzle RGB1()
Definition Swizzle.h:69
bool clampToBorderSupport() const
Definition Caps.h:217
int maxTextureSize() const
Definition Caps.h:134
std::tuple< int, int > uvSubsampleFactors() const
const SkYUVAInfo & yuvaInfo() const
const TextureProxyView & proxyView(int channelIndex) const
const SkM44 & local2Dev() const
Definition KeyContext.h:59
RuntimeEffectDictionary * rtEffectDict() const
Definition KeyContext.h:63
Recorder * recorder() const
Definition KeyContext.h:55
const SkMatrix * localMatrix() const
Definition KeyContext.h:60
const SkPMColor4f & paintColor() const
Definition KeyContext.h:72
const SkColorInfo & dstColorInfo() const
Definition KeyContext.h:65
ShaderCodeDictionary * dict() const
Definition KeyContext.h:62
const Caps * caps() const
Definition KeyContext.h:57
void writeArray(SkSpan< const T > t)
void writePaintColor(const SkPMColor4f &color)
static sk_sp< TextureProxy > CreateCachedProxy(Recorder *, const SkBitmap &, Mipmapped=skgpu::Mipmapped::kNo)
Definition Recorder.cpp:536
const Caps * caps() const
void set(int codeSnippetID, sk_sp< const SkRuntimeEffect > effect)
int findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect *effect)
const ShaderSnippet * getEntry(int codeSnippetID) const SK_EXCLUDES(fSpinLock)
sk_sp< TextureProxy > refProxy() const
int size() const
Definition SkTArray.h:416
sk_sp< SkImage > image
Definition examples.cpp:29
static bool b
struct MyStruct a[10]
const uint8_t uint32_t uint32_t GError ** error
static constexpr int kUnknownRuntimeEffectIDStart
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
ColorSpace
Definition image.h:16
void AddToKey(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlender *blender)
void AddKnownModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
void AddBlendModeColorFilter(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm, const SkPMColor4f &srcColor)
void Compose(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addInnerToKey, AddToKeyFn addOuterToKey)
static void notify_in_use(Recorder *recorder, DrawContext *drawContext, const SkBlendShader *shader)
static void add_yuv_image_to_key(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkImageShader *origShader, sk_sp< const SkImage > imageToDraw, SkSamplingOptions sampling)
static bool can_do_tiling_in_hw(const Caps *caps, const ImageShaderBlock::ImageData &imgData)
static SkBitmap create_color_and_offset_bitmap(int numStops, const SkPMColor4f *colors, const float *offsets)
std::pair< sk_sp< SkImage >, SkSamplingOptions > GetGraphiteBacked(Recorder *recorder, const SkImage *imageIn, SkSamplingOptions sampling)
static void make_interpolated_to_dst(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const GradientShaderBlocks::GradientData &gradData, const SkGradientShader::Interpolation &interp, SkColorSpace *intermediateCS)
static void add_to_key(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlendModeColorFilter *filter)
void Blend(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addBlendToKey, AddToKeyFn addSrcToKey, AddToKeyFn addDstToKey)
static void add_gradient_to_key(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkGradientBaseShader *shader, SkPoint point0, SkPoint point1, float radius0, float radius1, float bias, float scale)
static skgpu::graphite::ReadSwizzle swizzle_class_to_read_enum(const skgpu::Swizzle &swizzle)
void AddModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
static void gather_runtime_effect_uniforms(const KeyContext &keyContext, const SkRuntimeEffect *effect, SkSpan< const Uniform > graphiteUniforms, const SkData *uniformData, PipelineDataGatherer *gatherer)
static SkPMColor4f map_color(const SkColor4f &c, SkColorSpace *src, SkColorSpace *dst)
static bool skdata_matches(const SkData *a, const SkData *b)
TextureProxyView AsView(const SkImage *image)
void NotifyImagesInUse(Recorder *recorder, DrawContext *drawContext, const SkBlender *blender)
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition ref_ptr.h:256
#define M(PROC, DITHER)
skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction *tf)
Definition skcms.cc:183
const Scalar scale
Point offset
sk_sp< SkColorSpace > fIntermediateColorSpace
constexpr uint32_t mask() const
skcms_TransferFunction srcTF
void apply(float rgba[4]) const
skcms_TransferFunction dstTFInv
constexpr int32_t y() const
constexpr int32_t x() const
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static CachedImageInfo Make(const SkRect &bounds, const SkMatrix &totalM, SkColorType dstColorType, SkColorSpace *dstColorSpace, const int maxTextureSize, const SkSurfaceProps &propsIn)
float fX
x-axis value
float fY
y-axis value
SkRGBA4f< kPremul_SkAlphaType > premul() const
Definition SkColor.h:385
static SkRGBA4f FromColor(SkColor color)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
bool contains(SkScalar x, SkScalar y) const
Definition extension.cpp:19
const SkFilterMode filter
const SkMipmapMode mipmap
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition SkSize.h:56
Definition SkM44.h:98
const float * ptr() const
Definition SkM44.h:129
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, SkBlendMode)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, SkSpan< const float > coeffs)
ColorSpaceTransformData(const SkColorSpace *src, SkAlphaType srcAT, const SkColorSpace *dst, SkAlphaType dstAT)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ColorSpaceTransformData &)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const CoordClampData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const DitherData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, sk_sp< TextureProxy > dst, SkIPoint dstOffset)
SkPMColor4f fColors[kNumInternalStorageStops]
Definition KeyHelpers.h:126
GradientData(SkShaderBase::GradientType, int numStops)
SkV4 fOffsets[kNumInternalStorageStops/4]
Definition KeyHelpers.h:127
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const GradientData &)
ImageData(const SkSamplingOptions &sampling, SkTileMode tileModeX, SkTileMode tileModeY, SkISize imgSize, SkRect subset, ReadSwizzle readSwizzle)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ImageData &)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const LMShaderData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const MatrixColorFilterData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const PerlinNoiseData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
sk_sp< const SkRuntimeEffect > fEffect
Definition KeyHelpers.h:386
ShaderData(sk_sp< const SkRuntimeEffect > effect)
bool operator==(const ShaderData &rhs) const
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ShaderData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const SkPMColor4f &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const TableColorFilterData &)
ImageData(const SkSamplingOptions &sampling, SkTileMode tileModeX, SkTileMode tileModeY, SkISize imgSize, SkRect subset)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const ImageData &)