Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
PaintParamsKeyTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 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 "tests/Test.h"
9
10#if defined(SK_GRAPHITE)
11
14#include "include/core/SkM44.h"
33#include "src/base/SkRandom.h"
57#include "tools/ToolUtils.h"
61
62// Set this to 1 for more expansive (aka far slower) local testing
63#define EXPANDED_SET 0
64
65// This flag is set to true if during the PaintOption creation an SkPictureShader is created.
66// The SkPictureShader will need an additional program in order to draw the contents of its
67// SkPicture.
68bool gNeedSKPPaintOption = false;
69
70using namespace skgpu::graphite;
71
72namespace {
73
74std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom*, Recorder*);
75std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom*);
76std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(SkRandom*);
77[[maybe_unused]] std::pair<sk_sp<SkImageFilter>, SkEnumBitMask<PrecompileImageFilters>>
78 create_random_image_filter(SkRandom*);
79
80//--------------------------------------------------------------------------------------------------
81//--------------------------------------------------------------------------------------------------
82#define SK_ALL_TEST_SHADERS(M) \
83 M(Blend) \
84 M(ColorFilter) \
85 M(CoordClamp) \
86 M(ConicalGradient) \
87 M(Empty) \
88 M(Image) \
89 M(LinearGradient) \
90 M(LocalMatrix) \
91 M(None) \
92 M(PerlinNoise) \
93 M(Picture) \
94 M(RadialGradient) \
95 M(SolidColor) \
96 M(SweepGradient) \
97 M(WorkingColorSpace)
98
99enum class ShaderType {
100#define M(type) k##type,
101 SK_ALL_TEST_SHADERS(M)
102#undef M
103
104 kLast = kWorkingColorSpace
105};
106
107static constexpr int kShaderTypeCount = static_cast<int>(ShaderType::kLast) + 1;
108
109const char* to_str(ShaderType s) {
110 switch (s) {
111#define M(type) case ShaderType::k##type : return "ShaderType::k" #type;
112 SK_ALL_TEST_SHADERS(M)
113#undef M
114 }
115
117}
118
119//--------------------------------------------------------------------------------------------------
120//--------------------------------------------------------------------------------------------------
121#define SK_ALL_TEST_BLENDERS(M) \
122 M(None) \
123 M(PorterDuff) \
124 M(ShaderBased) \
125 M(Arithmetic) \
126 M(Runtime)
127
128// TODO: do we need to add a separable category and/or a category for dstRead requiring blends?
129enum class BlenderType {
130#define M(type) k##type,
131 SK_ALL_TEST_BLENDERS(M)
132#undef M
133
134 kLast = kRuntime
135};
136
137static constexpr int kBlenderTypeCount = static_cast<int>(BlenderType::kLast) + 1;
138
139const char* to_str(BlenderType b) {
140 switch (b) {
141#define M(type) case BlenderType::k##type : return "BlenderType::k" #type;
142 SK_ALL_TEST_BLENDERS(M)
143#undef M
144 }
145
147}
148
149//--------------------------------------------------------------------------------------------------
150//--------------------------------------------------------------------------------------------------
151#define SK_ALL_TEST_COLORFILTERS(M) \
152 M(None) \
153 M(BlendMode) \
154 M(ColorSpaceXform) \
155 M(Compose) \
156 M(Gaussian) \
157 M(HSLAMatrix) \
158 M(Lerp) \
159 M(Lighting) \
160 M(LinearToSRGB) \
161 M(Luma) \
162 M(Matrix) \
163 M(Runtime) \
164 M(SRGBToLinear) \
165 M(Table) \
166 M(WorkingFormat)
167
168enum class ColorFilterType {
169#define M(type) k##type,
170 SK_ALL_TEST_COLORFILTERS(M)
171#undef M
172
173 kLast = kWorkingFormat
174};
175
176static constexpr int kColorFilterTypeCount = static_cast<int>(ColorFilterType::kLast) + 1;
177
178const char* to_str(ColorFilterType cf) {
179 switch (cf) {
180#define M(type) case ColorFilterType::k##type : return "ColorFilterType::k" #type;
181 SK_ALL_TEST_COLORFILTERS(M)
182#undef M
183 }
184
186}
187
188//--------------------------------------------------------------------------------------------------
189//--------------------------------------------------------------------------------------------------
190#define SK_ALL_TEST_CLIPS(M) \
191 M(None) \
192 M(Shader) \
193 M(Shader_Diff)
194
195enum class ClipType {
196#define M(type) k##type,
197 SK_ALL_TEST_CLIPS(M)
198#undef M
199};
200
201const char* to_str(ClipType c) {
202 switch (c) {
203#define M(type) case ClipType::k##type : return "ClipType::k" #type;
204 SK_ALL_TEST_CLIPS(M)
205#undef M
206 }
207
209}
210
211//--------------------------------------------------------------------------------------------------
212//--------------------------------------------------------------------------------------------------
213#define SK_ALL_TEST_IMAGE_FILTERS(M) \
214 M(None) \
215 M(Blur)
216
217enum class ImageFilterType {
218#define M(type) k##type,
219 SK_ALL_TEST_IMAGE_FILTERS(M)
220#undef M
221 kLast = kBlur
222};
223
224static constexpr int kImageFilterTypeCount = static_cast<int>(ImageFilterType::kLast) + 1;
225
226const char* to_str(ImageFilterType c) {
227 switch (c) {
228#define M(type) case ImageFilterType::k##type : return "ImageFilterType::k" #type;
229 SK_ALL_TEST_IMAGE_FILTERS(M)
230#undef M
231 }
233}
234
235//--------------------------------------------------------------------------------------------------
236//--------------------------------------------------------------------------------------------------
237static constexpr skcms_TransferFunction gTransferFunctions[] = {
244};
245
246static constexpr int kTransferFunctionCount = std::size(gTransferFunctions);
247
248const skcms_TransferFunction& random_xfer_function(SkRandom* rand) {
249 return gTransferFunctions[rand->nextULessThan(kTransferFunctionCount)];
250}
251
252static constexpr skcms_Matrix3x3 gGamuts[] = {
258};
259
260static constexpr int kGamutCount = std::size(gGamuts);
261
262const skcms_Matrix3x3& random_gamut(SkRandom* rand) {
263 return gGamuts[rand->nextULessThan(kGamutCount)];
264}
265
266enum class ColorSpaceType {
267 kNone,
268 kSRGB,
269 kSRGBLinear,
270 kRGB,
271
272 kLast = kRGB
273};
274
275static constexpr int kColorSpaceTypeCount = static_cast<int>(ColorSpaceType::kLast) + 1;
276
277ColorSpaceType random_colorspacetype(SkRandom* rand) {
278 return static_cast<ColorSpaceType>(rand->nextULessThan(kColorSpaceTypeCount));
279}
280
281sk_sp<SkColorSpace> random_colorspace(SkRandom* rand) {
282 ColorSpaceType cs = random_colorspacetype(rand);
283
284 switch (cs) {
285 case ColorSpaceType::kNone:
286 return nullptr;
287 case ColorSpaceType::kSRGB:
288 return SkColorSpace::MakeSRGB();
289 case ColorSpaceType::kSRGBLinear:
291 case ColorSpaceType::kRGB:
292 return SkColorSpace::MakeRGB(random_xfer_function(rand), random_gamut(rand));
293 }
294
296}
297
298enum class ColorConstraint {
299 kNone,
300 kOpaque,
302};
303
304SkColor random_color(SkRandom* rand, ColorConstraint constraint) {
305 uint32_t color = rand->nextU();
306
307 switch (constraint) {
308 case ColorConstraint::kNone: return color;
309 case ColorConstraint::kOpaque: return 0xff000000 | color;
310 case ColorConstraint::kTransparent: return 0x80000000 | color;
311 }
312
314}
315
316SkColor4f random_color4f(SkRandom* rand, ColorConstraint constraint) {
317 SkColor4f result = { rand->nextRangeF(0.0f, 1.0f),
318 rand->nextRangeF(0.0f, 1.0f),
319 rand->nextRangeF(0.0f, 1.0f),
320 rand->nextRangeF(0.0f, 1.0f) };
321
322 switch (constraint) {
323 case ColorConstraint::kNone: return result;
324 case ColorConstraint::kOpaque: result.fA = 1.0f; return result;
325 case ColorConstraint::kTransparent: result.fA = 0.5f; return result;
326 }
327
329}
330
331SkTileMode random_tilemode(SkRandom* rand) {
332 return static_cast<SkTileMode>(rand->nextULessThan(kSkTileModeCount));
333}
334
335ShaderType random_shadertype(SkRandom* rand) {
336 return static_cast<ShaderType>(rand->nextULessThan(kShaderTypeCount));
337}
338
339SkBlendMode random_porter_duff_bm(SkRandom* rand) {
340 return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kClear,
341 (unsigned int) SkBlendMode::kLastCoeffMode));
342}
343
344SkBlendMode random_complex_bm(SkRandom* rand) {
345 return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kLastCoeffMode,
346 (unsigned int) SkBlendMode::kLastMode));
347}
348
349SkBlendMode random_blend_mode(SkRandom* rand) {
350 return static_cast<SkBlendMode>(rand->nextULessThan(kSkBlendModeCount));
351}
352
353BlenderType random_blendertype(SkRandom* rand) {
354 return static_cast<BlenderType>(rand->nextULessThan(kBlenderTypeCount));
355}
356
357ColorFilterType random_colorfiltertype(SkRandom* rand) {
358 return static_cast<ColorFilterType>(rand->nextULessThan(kColorFilterTypeCount));
359}
360
361ImageFilterType random_imagefiltertype(SkRandom* rand) {
362 return static_cast<ImageFilterType>(rand->nextULessThan(kImageFilterTypeCount));
363}
364
365SkMatrix* random_local_matrix(SkRandom* rand, SkMatrix* storage) {
366 switch (rand->nextULessThan(3)) {
367 case 0: return nullptr;
368 case 1: storage->setIdentity(); return storage;
369 case 2: [[fallthrough]];
370 default: storage->setTranslate(2.0f, 2.0f); return storage;
371 }
372
374}
375
376sk_sp<SkImage> make_image(SkRandom* rand, Recorder* recorder) {
378 if (rand->nextBool()) {
380 }
381
382 SkImageInfo info = SkImageInfo::Make(32, 32, ct, kPremul_SkAlphaType, random_colorspace(rand));
383
385 bitmap.allocPixels(info);
386 bitmap.eraseColor(SK_ColorBLACK);
387
388 sk_sp<SkImage> img = bitmap.asImage();
389
390 // TODO: fuzz mipmappedness
391 return SkImages::TextureFromImage(recorder, img, {false});
392}
393
394//--------------------------------------------------------------------------------------------------
396 constexpr SkRect kRect = SkRect::MakeWH(128, 128);
397
398 SkPictureRecorder recorder;
399
400 SkCanvas* canvas = recorder.beginRecording(kRect);
401
402 SkPaint paint; // Explicitly using the default SkPaint here
403
404 canvas->drawRect(kRect, paint);
405
406 return recorder.finishRecordingAsPicture();
407}
408
409//--------------------------------------------------------------------------------------------------
410std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_coord_clamp_shader(SkRandom* rand,
411 Recorder* recorder) {
412 auto [s, o] = create_random_shader(rand, recorder);
413 SkASSERT(!s == !o);
414
415 if (!s) {
416 return { nullptr, nullptr };
417 }
418
419 constexpr SkRect kSubset{0, 0, 256, 256}; // this is somewhat arbitrary but we need some subset
420 sk_sp<SkShader> ccs = SkShaders::CoordClamp(std::move(s), kSubset);
421 sk_sp<PrecompileShader> cco = PrecompileShaders::CoordClamp({ std::move(o) });
422
423 return { ccs, cco };
424}
425
426std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_empty_shader(SkRandom* /* rand */) {
427 sk_sp<SkShader> s = SkShaders::Empty();
428 sk_sp<PrecompileShader> o = PrecompileShaders::Empty();
429
430 return { s, o };
431}
432
433std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_perlin_noise_shader(SkRandom* rand) {
436
437 if (rand->nextBool()) {
438 s = SkShaders::MakeFractalNoise(/* baseFrequencyX= */ 0.3f,
439 /* baseFrequencyY= */ 0.3f,
440 /* numOctaves= */ 2,
441 /* seed= */ 4);
442 o = PrecompileShaders::MakeFractalNoise();
443 } else {
444 s = SkShaders::MakeTurbulence(/* baseFrequencyX= */ 0.3f,
445 /* baseFrequencyY= */ 0.3f,
446 /* numOctaves= */ 2,
447 /* seed= */ 4);
448 o = PrecompileShaders::MakeTurbulence();
449 }
450
451 return { s, o };
452}
453
454std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_picture_shader(SkRandom* rand) {
456
457 gNeedSKPPaintOption = true;
458
459 SkMatrix lmStorage;
460 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
461
462 // TODO: can the clamp, filter mode, or tileRect affect the final program?
466 lmPtr,
467 /* tileRect= */ nullptr);
468 sk_sp<PrecompileShader> o = PrecompileShadersPriv::Picture(SkToBool(lmPtr));
469
470 return { s, o };
471}
472
473std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_solid_shader(
474 SkRandom* rand,
475 ColorConstraint constraint = ColorConstraint::kNone) {
478
479 if (rand->nextBool()) {
480 s = SkShaders::Color(random_color(rand, constraint));
481 o = PrecompileShaders::Color();
482 } else {
483 sk_sp<SkColorSpace> cs = random_colorspace(rand);
484 s = SkShaders::Color(random_color4f(rand, constraint), cs);
485 o = PrecompileShaders::Color(std::move(cs));
486 }
487
488 return { s, o };
489}
490
491std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_gradient_shader(
492 SkRandom* rand,
494 ColorConstraint constraint = ColorConstraint::kOpaque) {
495 // TODO: fuzz the gradient parameters - esp. the number of stops & hard stops
496 SkPoint pts[2] = {{-100, -100},
497 {100, 100}};
498 SkColor colors[2] = {random_color(rand, constraint), random_color(rand, constraint)};
499 SkScalar offsets[2] = {0.0f, 1.0f};
500
501 SkMatrix lmStorage;
502 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
503
505
508
509 SkTileMode tm = random_tilemode(rand);
510
511 switch (type) {
512 case SkShaderBase::GradientType::kLinear:
513 s = SkGradientShader::MakeLinear(pts, colors, offsets, 2, tm, flags, lmPtr);
514 o = PrecompileShadersPriv::LinearGradient(SkToBool(lmPtr));
515 break;
516 case SkShaderBase::GradientType::kRadial:
517 s = SkGradientShader::MakeRadial({0, 0}, 100, colors, offsets, 2, tm, flags, lmPtr);
518 o = PrecompileShadersPriv::RadialGradient(SkToBool(lmPtr));
519 break;
520 case SkShaderBase::GradientType::kSweep:
521 s = SkGradientShader::MakeSweep(0, 0, colors, offsets, 2, tm,
522 /* startAngle= */ 0, /* endAngle= */ 359,
523 flags, lmPtr);
524 o = PrecompileShadersPriv::SweepGradient(SkToBool(lmPtr));
525 break;
526 case SkShaderBase::GradientType::kConical:
528 {-100, -100}, 100,
529 colors, offsets, 2,
530 tm, flags, lmPtr);
531 o = PrecompileShadersPriv::TwoPointConicalGradient(SkToBool(lmPtr));
532 break;
534 SkDEBUGFAIL("Gradient shader says its type is none");
535 break;
536 }
537
538 return { s, o };
539}
540
541std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_localmatrix_shader(SkRandom* rand,
542 Recorder* recorder) {
543 auto [s, o] = create_random_shader(rand, recorder);
544 SkASSERT(!s == !o);
545
546 if (!s) {
547 return { nullptr, nullptr };
548 }
549
550 SkMatrix lmStorage;
551 random_local_matrix(rand, &lmStorage);
552
553 return { s->makeWithLocalMatrix(lmStorage), o->makeWithLocalMatrix() };
554}
555
556std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_colorfilter_shader(SkRandom* rand,
557 Recorder* recorder) {
558 auto [s, o] = create_random_shader(rand, recorder);
559 SkASSERT(!s == !o);
560
561 if (!s) {
562 return { nullptr, nullptr };
563 }
564
565 auto [cf, cfO] = create_random_colorfilter(rand);
566
567 return { s->makeWithColorFilter(std::move(cf)), o->makeWithColorFilter(std::move(cfO)) };
568}
569
570std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_image_shader(SkRandom* rand,
571 Recorder* recorder) {
572 SkTileMode tmX = random_tilemode(rand);
573 SkTileMode tmY = random_tilemode(rand);
574
575 SkMatrix lmStorage;
576 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
577
580
581 // TODO: the combination system accounts for cubic vs. non-cubic sampling and HW vs. non-HW
582 // tiling. We should test those combinations in the fuzzer.
583 if (rand->nextBool()) {
584 s = SkShaders::Image(make_image(rand, recorder),
585 tmX, tmY,
587 lmPtr);
588 o = PrecompileShaders::Image();
589 } else {
590 s = SkShaders::RawImage(make_image(rand, recorder),
591 tmX, tmY,
593 lmPtr);
594 o = PrecompileShaders::RawImage();
595 }
596
597 return { s, o };
598}
599
600std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_blend_shader(SkRandom* rand,
601 Recorder* recorder) {
602 // TODO: add explicit testing of the kClear, kDst and kSrc blend modes since they short
603 // circuit creation of a true blend shader (i.e., in SkShaders::Blend).
604 auto [blender, blenderO] = create_random_blender(rand);
605
606 auto [dstS, dstO] = create_random_shader(rand, recorder);
607 SkASSERT(!dstS == !dstO);
608 if (!dstS) {
609 return { nullptr, nullptr };
610 }
611
612 auto [srcS, srcO] = create_random_shader(rand, recorder);
613 SkASSERT(!srcS == !srcO);
614 if (!srcS) {
615 return { nullptr, nullptr };
616 }
617
618 auto s = SkShaders::Blend(std::move(blender), std::move(dstS), std::move(srcS));
619 auto o = PrecompileShaders::Blend(SkSpan<const sk_sp<PrecompileBlender>>({ blenderO }),
620 { dstO }, { srcO });
621
622 return { s, o };
623}
624
625std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_workingCS_shader(SkRandom* rand,
626 Recorder* recorder) {
627 auto [wrappedS, wrappedO] = create_random_shader(rand, recorder);
628 SkASSERT(!wrappedS == !wrappedO);
629 if (!wrappedS) {
630 return { nullptr, nullptr };
631 }
632
633 sk_sp<SkColorSpace> cs = random_colorspace(rand);
634 sk_sp<SkShader> s = wrappedS->makeWithWorkingColorSpace(cs);
635 sk_sp<PrecompileShader> o = wrappedO->makeWithWorkingColorSpace(std::move(cs));
636
637 return { s, o };
638}
639
640std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_shader(SkRandom* rand,
641 Recorder* recorder,
642 ShaderType shaderType) {
643
644 switch (shaderType) {
645 case ShaderType::kNone:
646 return { nullptr, nullptr };
647 case ShaderType::kBlend:
648 return create_blend_shader(rand, recorder);
649 case ShaderType::kColorFilter:
650 return create_colorfilter_shader(rand, recorder);
651 case ShaderType::kCoordClamp:
652 return create_coord_clamp_shader(rand, recorder);
653 case ShaderType::kConicalGradient:
654 return create_gradient_shader(rand, SkShaderBase::GradientType::kConical);
655 case ShaderType::kEmpty:
656 return create_empty_shader(rand);
657 case ShaderType::kImage:
658 return create_image_shader(rand, recorder);
659 case ShaderType::kLinearGradient:
660 return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear);
661 case ShaderType::kLocalMatrix:
662 return create_localmatrix_shader(rand, recorder);
663 case ShaderType::kPerlinNoise:
664 return create_perlin_noise_shader(rand);
665 case ShaderType::kPicture:
666 return create_picture_shader(rand);
667 case ShaderType::kRadialGradient:
668 return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial);
669 case ShaderType::kSolidColor:
670 return create_solid_shader(rand);
671 case ShaderType::kSweepGradient:
672 return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep);
673 case ShaderType::kWorkingColorSpace:
674 return create_workingCS_shader(rand, recorder);
675 }
676
678}
679
680std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom* rand,
681 Recorder* recorder) {
682 return create_shader(rand, recorder, random_shadertype(rand));
683}
684
685std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_clip_shader(SkRandom* rand,
686 Recorder* recorder) {
687 // The clip shader has to be transparent to be at all interesting.
688 // TODO/Note: an opaque clipShader is eliminated from the SkPaint by the normal Skia API
689 // but I'm unsure if we should bother capturing that possibility in the precompile system.
690 switch (rand->nextULessThan(5)) {
691 case 0: return create_gradient_shader(rand, SkShaderBase::GradientType::kConical,
692 ColorConstraint::kTransparent);
693 case 1: return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear,
694 ColorConstraint::kTransparent);
695 case 2: return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial,
696 ColorConstraint::kTransparent);
697 case 3: return create_solid_shader(rand, ColorConstraint::kTransparent);
698 case 4: return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep,
699 ColorConstraint::kTransparent);
700 }
701
703}
704
705//--------------------------------------------------------------------------------------------------
706std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> src_blender() {
707 static SkRuntimeEffect* sSrcEffect = SkMakeRuntimeEffect(
709 "half4 main(half4 src, half4 dst) {"
710 "return src;"
711 "}"
712 );
713
714 sk_sp<SkBlender> b = sSrcEffect->makeBlender(/* uniforms= */ nullptr);
716 return { b , o };
717}
718
719std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> dest_blender() {
720 static SkRuntimeEffect* sDestEffect = SkMakeRuntimeEffect(
722 "half4 main(half4 src, half4 dst) {"
723 "return dst;"
724 "}"
725 );
726
727 sk_sp<SkBlender> b = sDestEffect->makeBlender(/* uniforms= */ nullptr);
729 return { b , o };
730}
731
732
733std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> combo_blender() {
734 static SkRuntimeEffect* sComboEffect = SkMakeRuntimeEffect(
736 "uniform float blendFrac;"
737 "uniform blender a;"
738 "uniform blender b;"
739 "half4 main(half4 src, half4 dst) {"
740 "return (blendFrac * a.eval(src, dst)) + ((1 - blendFrac) * b.eval(src, dst));"
741 "}"
742 );
743
744 auto [src, srcO] = src_blender();
745 auto [dst, dstO] = dest_blender();
746
747 SkRuntimeEffect::ChildPtr children[] = { src, dst };
748 const PrecompileChildPtr childOptions[] = { srcO, dstO };
749
750 const float kUniforms[] = { 1.0f };
751
752 sk_sp<SkData> uniforms = SkData::MakeWithCopy(kUniforms, sizeof(kUniforms));
753 sk_sp<SkBlender> b = sComboEffect->makeBlender(std::move(uniforms), children);
754 sk_sp<PrecompileBlender> o = MakePrecompileBlender(sk_ref_sp(sComboEffect), { childOptions });
755 return { b , o };
756}
757
758std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_bm_blender(SkRandom* rand,
759 SkBlendMode bm) {
760 return { SkBlender::Mode(bm), PrecompileBlender::Mode(bm) };
761}
762
763std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_arithmetic_blender() {
765 /* k2= */ 0.5,
766 /* k3= */ 0.5,
767 /* k4= */ 0.5,
768 /* enforcePremul= */ true);
769 sk_sp<PrecompileBlender> o = PrecompileBlenders::Arithmetic();
770
771 return { std::move(b), std::move(o) };
772}
773
774std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_rt_blender(SkRandom* rand) {
775 int option = rand->nextULessThan(3);
776
777 switch (option) {
778 case 0: return src_blender();
779 case 1: return dest_blender();
780 case 2: return combo_blender();
781 }
782
783 return { nullptr, nullptr };
784}
785
786std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_blender(SkRandom* rand,
787 BlenderType type) {
788 switch (type) {
789 case BlenderType::kNone:
790 return { nullptr, nullptr };
791 case BlenderType::kPorterDuff:
792 return create_bm_blender(rand, random_porter_duff_bm(rand));
793 case BlenderType::kShaderBased:
794 return create_bm_blender(rand, random_complex_bm(rand));
795 case BlenderType::kArithmetic:
796 return create_arithmetic_blender();
797 case BlenderType::kRuntime:
798 return create_rt_blender(rand);
799 }
800
802}
803
804std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom* rand) {
805 return create_blender(rand, random_blendertype(rand));
806}
807
808//--------------------------------------------------------------------------------------------------
809//--------------------------------------------------------------------------------------------------
810std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> double_colorfilter() {
811 static SkRuntimeEffect* sSrcEffect = SkMakeRuntimeEffect(
813 "half4 main(half4 c) {"
814 "return 2*c;"
815 "}"
816 );
817
818 return { sSrcEffect->makeColorFilter(/* uniforms= */ nullptr),
820}
821
822std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> half_colorfilter() {
823 static SkRuntimeEffect* sDestEffect = SkMakeRuntimeEffect(
825 "half4 main(half4 c) {"
826 "return 0.5*c;"
827 "}"
828 );
829
830 return { sDestEffect->makeColorFilter(/* uniforms= */ nullptr),
831 MakePrecompileColorFilter(sk_ref_sp(sDestEffect)) };
832}
833
834std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> combo_colorfilter() {
835 static SkRuntimeEffect* sComboEffect = SkMakeRuntimeEffect(
837 "uniform float blendFrac;"
838 "uniform colorFilter a;"
839 "uniform colorFilter b;"
840 "half4 main(half4 c) {"
841 "return (blendFrac * a.eval(c)) + ((1 - blendFrac) * b.eval(c));"
842 "}"
843 );
844
845 auto [src, srcO] = double_colorfilter();
846 auto [dst, dstO] = half_colorfilter();
847
848 SkRuntimeEffect::ChildPtr children[] = { src, dst };
849 const PrecompileChildPtr childOptions[] = { srcO, dstO };
850
851 const float kUniforms[] = { 0.5f };
852
853 sk_sp<SkData> uniforms = SkData::MakeWithCopy(kUniforms, sizeof(kUniforms));
854 sk_sp<SkColorFilter> cf = sComboEffect->makeColorFilter(std::move(uniforms), children);
856 { childOptions });
857 return { std::move(cf) , std::move(o) };
858}
859
860std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_rt_colorfilter(
861 SkRandom* rand) {
862 int option = rand->nextULessThan(3);
863
864 switch (option) {
865 case 0: return double_colorfilter();
866 case 1: return half_colorfilter();
867 case 2: return combo_colorfilter();
868 }
869
870 return { nullptr, nullptr };
871}
872
873std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_lerp_colorfilter(
874 SkRandom* rand) {
875
876 auto [dst, dstO] = create_random_colorfilter(rand);
877 auto [src, srcO] = create_random_colorfilter(rand);
878 // SkColorFilters::Lerp optimizes away the case where src == dst. I don't know if it is worth
879 // capturing it in the precompilation API
880 while (src == dst) {
881 std::tie(src, srcO) = create_random_colorfilter(rand);
882 }
883
884 // TODO: SkColorFilters::Lerp will return a different colorFilter depending on the
885 // weight value and the child color filters. I don't know if that is worth capturing
886 // in the precompile API.
887 sk_sp<SkColorFilter> cf = SkColorFilters::Lerp(0.5f, std::move(dst), std::move(src));
888
889 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Lerp({ dstO }, { srcO });
890
891 return { cf, o };
892}
893
894std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_lighting_colorfilter() {
895 // TODO: the lighting color filter factory special cases when nothing is added and converts it
896 // to a blendmode color filter
898 PrecompileColorFilters::Lighting() };
899}
900
901std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_blendmode_colorfilter(
902 SkRandom* rand) {
903
905
906 // SkColorFilters::Blend is clever and can weed out noop color filters. Loop until we get
907 // a valid color filter.
908 while (!cf) {
909 cf = SkColorFilters::Blend(random_color4f(rand, ColorConstraint::kNone),
910 random_colorspace(rand),
911 random_blend_mode(rand));
912 }
913
914 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Blend();
915
916 return { std::move(cf), std::move(o) };
917}
918
919std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_matrix_colorfilter() {
922 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Matrix();
923
924 return { std::move(cf), std::move(o) };
925}
926
927std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_color_space_colorfilter(
928 SkRandom* rand) {
929 return { SkColorFilterPriv::MakeColorSpaceXform(random_colorspace(rand),
930 random_colorspace(rand)),
931 PrecompileColorFiltersPriv::ColorSpaceXform() };
932}
933
934std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_linear_to_srgb_colorfilter() {
935 return { SkColorFilters::LinearToSRGBGamma(), PrecompileColorFilters::LinearToSRGBGamma() };
936}
937
938std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_srgb_to_linear_colorfilter() {
939 return { SkColorFilters::SRGBToLinearGamma(), PrecompileColorFilters::SRGBToLinearGamma() };
940}
941
942std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_luma_colorfilter() {
943 return { SkLumaColorFilter::Make(), PrecompileColorFilters::Luma() };
944}
945
946std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_compose_colorfilter(
947 SkRandom* rand) {
948 auto [outerCF, outerO] = create_random_colorfilter(rand);
949 auto [innerCF, innerO] = create_random_colorfilter(rand);
950
951 // TODO: if outerCF is null, innerCF will be returned by Compose. We need a Precompile
952 // list object that can encapsulate innerO if there are no combinations in outerO.
953 return { SkColorFilters::Compose(std::move(outerCF), std::move(innerCF)),
954 PrecompileColorFilters::Compose({ std::move(outerO) }, { std::move(innerO) }) };
955}
956
957std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_gaussian_colorfilter() {
958 return { SkColorFilterPriv::MakeGaussian(), PrecompileColorFiltersPriv::Gaussian() };
959}
960
961std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_table_colorfilter() {
962 static constexpr uint8_t kTable[256] = { 0 };
963
964 return { SkColorFilters::Table(kTable), PrecompileColorFilters::Table() };
965}
966
967std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_workingformat_colorfilter(
968 SkRandom* rand) {
969 auto [childCF, childO] = create_random_colorfilter(rand);
970
971 if (!childCF) {
972 return { nullptr, nullptr };
973 }
974
975 SkASSERT(childCF && childO);
976
979 &random_xfer_function(rand),
980 &random_gamut(rand),
981 &unpremul);
982
983 sk_sp<PrecompileColorFilter> o = PrecompileColorFiltersPriv::WithWorkingFormat(
984 { std::move(childO) });
985
986 return { std::move(cf), std::move(o) };
987}
988
989std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_hsla_matrix_colorfilter() {
992 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::HSLAMatrix();
993
994 return { std::move(cf), std::move(o) };
995}
996
997std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_colorfilter(
998 SkRandom* rand,
999 ColorFilterType type) {
1000
1001 switch (type) {
1002 case ColorFilterType::kNone:
1003 return { nullptr, nullptr };
1004 case ColorFilterType::kBlendMode:
1005 return create_blendmode_colorfilter(rand);
1006 case ColorFilterType::kColorSpaceXform:
1007 return create_color_space_colorfilter(rand);
1008 case ColorFilterType::kCompose:
1009 return create_compose_colorfilter(rand);
1010 case ColorFilterType::kGaussian:
1011 return create_gaussian_colorfilter();
1012 case ColorFilterType::kHSLAMatrix:
1013 return create_hsla_matrix_colorfilter();
1014 case ColorFilterType::kLerp:
1015 return create_lerp_colorfilter(rand);
1016 case ColorFilterType::kLighting:
1017 return create_lighting_colorfilter();
1018 case ColorFilterType::kLinearToSRGB:
1019 return create_linear_to_srgb_colorfilter();
1020 case ColorFilterType::kLuma:
1021 return create_luma_colorfilter();
1022 case ColorFilterType::kMatrix:
1023 return create_matrix_colorfilter();
1024 case ColorFilterType::kRuntime:
1025 return create_rt_colorfilter(rand);
1026 case ColorFilterType::kSRGBToLinear:
1027 return create_srgb_to_linear_colorfilter();
1028 case ColorFilterType::kTable:
1029 return create_table_colorfilter();
1030 case ColorFilterType::kWorkingFormat:
1031 return create_workingformat_colorfilter(rand);
1032 }
1033
1035}
1036
1037std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(
1038 SkRandom* rand) {
1039 return create_colorfilter(rand, random_colorfiltertype(rand));
1040}
1041
1042//--------------------------------------------------------------------------------------------------
1043//--------------------------------------------------------------------------------------------------
1044sk_sp<SkImageFilter> blur_imagefilter(SkRandom* rand,
1045 SkEnumBitMask<PrecompileImageFilters>* imageFilterMask) {
1046
1047 int option = rand->nextULessThan(3);
1048
1049 float sigma;
1050 switch (option) {
1051 case 0: sigma = 1.0f; break; // 1DBlur4
1052 case 1: sigma = 2.0f; break; // 1DBlur8
1053 case 2: [[fallthrough]];
1054 default: sigma = 5.0f; break; // 1DBlur16
1055 }
1056
1057 sk_sp<SkImageFilter> blurIF = SkImageFilters::Blur(sigma, sigma, /* input= */ nullptr);
1058 *imageFilterMask |= PrecompileImageFilters::kBlur;
1059
1060 return blurIF;
1061}
1062
1063std::pair<sk_sp<SkImageFilter>, SkEnumBitMask<PrecompileImageFilters>> create_image_filter(
1064 SkRandom* rand,
1065 ImageFilterType type) {
1066
1067 sk_sp<SkImageFilter> imgFilter;
1068 SkEnumBitMask<PrecompileImageFilters> imageFilterMask = PrecompileImageFilters::kNone;
1069
1070 switch (type) {
1071 case ImageFilterType::kNone:
1072 break;
1073 case ImageFilterType::kBlur:
1074 imgFilter = blur_imagefilter(rand, &imageFilterMask);
1075 }
1076
1077 return { std::move(imgFilter), imageFilterMask };
1078}
1079
1080std::pair<sk_sp<SkImageFilter>, SkEnumBitMask<PrecompileImageFilters>>
1081 create_random_image_filter(SkRandom* rand) {
1082 return create_image_filter(rand, random_imagefiltertype(rand));
1083}
1084
1085//--------------------------------------------------------------------------------------------------
1086std::pair<SkPaint, PaintOptions> create_paint(SkRandom* rand,
1087 Recorder* recorder,
1088 ShaderType shaderType,
1089 BlenderType blenderType,
1090 ColorFilterType colorFilterType,
1091 ImageFilterType imageFilterType) {
1092 SkPaint paint;
1093 paint.setColor(random_color(rand, ColorConstraint::kOpaque));
1094
1095 PaintOptions paintOptions;
1096
1097 {
1098 auto [s, o] = create_shader(rand, recorder, shaderType);
1099 SkASSERT(!s == !o);
1100
1101 if (s) {
1102 paint.setShader(std::move(s));
1103 paintOptions.setShaders({o});
1104 }
1105 }
1106
1107 {
1108 auto [cf, o] = create_colorfilter(rand, colorFilterType);
1109 SkASSERT(!cf == !o);
1110
1111 if (cf) {
1112 paint.setColorFilter(std::move(cf));
1113 paintOptions.setColorFilters({o});
1114 }
1115 }
1116
1117 {
1118 auto [b, o] = create_blender(rand, blenderType);
1119 SkASSERT(!b == !o);
1120
1121 if (b) {
1122 paint.setBlender(std::move(b));
1123 paintOptions.setBlenders({o});
1124 }
1125 }
1126
1127 {
1128 auto [filter, filterO] = create_image_filter(rand, imageFilterType);
1129 SkASSERT(!filter == !filterO);
1130
1131 if (filter) {
1132 paint.setImageFilter(std::move(filter));
1133 paintOptions.setImageFilters(filterO);
1134 }
1135 }
1136
1137 if (rand->nextBool()) {
1138 paint.setDither(true);
1139 paintOptions.setDither(true);
1140 }
1141
1142 return { paint, paintOptions };
1143}
1144
1145#ifdef SK_DEBUG
1147 dict->lookup(id).dump(dict);
1148}
1149#endif
1150
1151SkPath make_path() {
1153 path.moveTo(0, 0);
1154 path.lineTo(8, 2);
1155 path.lineTo(16, 0);
1156 path.lineTo(14, 8);
1157 path.lineTo(16, 16);
1158 path.lineTo(8, 14);
1159 path.lineTo(0, 16);
1160 path.lineTo(2, 8);
1161 path.close();
1162 return path.detach();
1163}
1164
1165struct DrawData {
1166 SkPath fPath;
1167 sk_sp<SkTextBlob> fBlob;
1168 sk_sp<SkVertices> fVertsWithColors;
1169 sk_sp<SkVertices> fVertsWithOutColors;
1170};
1171
1172void simple_draws(SkCanvas* canvas, const SkPaint& paint) {
1173 // TODO: add some drawLine calls
1174 canvas->drawRect(SkRect::MakeWH(16, 16), paint);
1175 canvas->drawRRect(SkRRect::MakeOval({0, 0, 16, 16}), paint);
1176 canvas->drawRRect(SkRRect::MakeRectXY({0, 0, 16, 16}, 4, 4), paint);
1177
1178 if (!paint.getShader() &&
1179 !paint.getColorFilter() &&
1180 !paint.getImageFilter() &&
1181 paint.asBlendMode().has_value()) {
1182 // The SkPaint reconstructed inside the drawEdgeAAQuad call needs to match 'paint' for
1183 // the precompilation checks to work.
1185 /* clip= */ nullptr,
1187 paint.getColor4f(),
1188 paint.asBlendMode().value());
1189 }
1190}
1191
1192void non_simple_draws(SkCanvas* canvas, const SkPaint& paint, const DrawData& drawData) {
1193 // TODO: add strokeAndFill draws here as well as a stroked non-circular rrect draw
1194 canvas->drawPath(drawData.fPath, paint);
1195}
1196
1197void check_draw(skiatest::Reporter* reporter,
1198 Context* context,
1200 Recorder* recorder,
1201 const SkPaint& paint,
1202 DrawTypeFlags dt,
1203 ClipType clip, sk_sp<SkShader> clipShader,
1204 const DrawData& drawData) {
1205
1206 int before = context->priv().globalCache()->numGraphicsPipelines();
1207
1208#ifdef SK_DEBUG
1209 std::vector<skgpu::UniqueKey> beforeKeys;
1210
1211 UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &beforeKeys);
1212#endif
1213
1214 {
1215 // TODO: vary the colorType of the target surface too
1216 SkImageInfo ii = SkImageInfo::Make(16, 16,
1219
1220 sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, ii);
1221 SkCanvas* canvas = surf->getCanvas();
1222
1223 switch (clip) {
1224 case ClipType::kNone:
1225 break;
1226 case ClipType::kShader:
1227 SkASSERT(clipShader);
1228 canvas->clipShader(clipShader, SkClipOp::kIntersect);
1229 break;
1230 case ClipType::kShader_Diff:
1231 SkASSERT(clipShader);
1232 canvas->clipShader(clipShader, SkClipOp::kDifference);
1233 break;
1234 }
1235
1236 switch (dt) {
1237 case DrawTypeFlags::kSimpleShape:
1238 simple_draws(canvas, paint);
1239 break;
1240 case DrawTypeFlags::kNonSimpleShape:
1241 non_simple_draws(canvas, paint, drawData);
1242 break;
1243 case DrawTypeFlags::kShape:
1244 simple_draws(canvas, paint);
1245 non_simple_draws(canvas, paint, drawData);
1246 break;
1247 case DrawTypeFlags::kText:
1248 canvas->drawTextBlob(drawData.fBlob, 0, 16, paint);
1249 break;
1250 case DrawTypeFlags::kDrawVertices:
1251 canvas->drawVertices(drawData.fVertsWithColors, SkBlendMode::kDst, paint);
1252 canvas->drawVertices(drawData.fVertsWithOutColors, SkBlendMode::kDst, paint);
1253 break;
1254 default:
1255 SkASSERT(false);
1256 break;
1257 }
1258
1259 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
1260 context->insertRecording({ recording.get() });
1261 testContext->syncedSubmit(context);
1262 }
1263
1264 int after = context->priv().globalCache()->numGraphicsPipelines();
1265
1266 // Actually using the SkPaint with the specified type of draw shouldn't have caused
1267 // any additional compilation
1268 REPORTER_ASSERT(reporter, before == after, "before: %d after: %d", before, after);
1269#ifdef SK_DEBUG
1270 if (before != after) {
1271 const RendererProvider* rendererProvider = context->priv().rendererProvider();
1272 const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1273
1274 std::vector<skgpu::UniqueKey> afterKeys;
1275
1276 UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &afterKeys);
1277
1278 for (const skgpu::UniqueKey& afterKey : afterKeys) {
1279 if (std::find(beforeKeys.begin(), beforeKeys.end(), afterKey) == beforeKeys.end()) {
1280 GraphicsPipelineDesc originalPipelineDesc;
1281 RenderPassDesc originalRenderPassDesc;
1282 UniqueKeyUtils::ExtractKeyDescs(context, afterKey,
1283 &originalPipelineDesc,
1284 &originalRenderPassDesc);
1285
1286 SkDebugf("------- New key from draw:\n");
1287 afterKey.dump("original key:");
1288 UniqueKeyUtils::DumpDescs(rendererProvider, dict,
1289 originalPipelineDesc,
1290 originalRenderPassDesc);
1291 }
1292 }
1293 }
1294#endif // SK_DEBUG
1295}
1296
1297} // anonymous namespace
1298
1300 Context*,
1302 const KeyContext& precompileKeyContext,
1303 const DrawData&,
1304 ShaderType,
1305 BlenderType,
1306 ColorFilterType,
1307 ClipType,
1308 ImageFilterType);
1309
1310// This is intended to be a smoke test for the agreement between the two ways of creating a
1311// PaintParamsKey:
1312// via ExtractPaintData (i.e., from an SkPaint)
1313// and via the pre-compilation system
1314//
1315// TODO: keep this as a smoke test but add a fuzzer that reuses all the helpers
1316// TODO(b/306174708): enable in SkQP (if it's feasible)
1318 reporter,
1319 context,
1320 testContext,
1321 true,
1323 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1324
1327
1328 std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
1329
1330 auto dstTexInfo = context->priv().caps()->getDefaultSampledTextureInfo(
1332 skgpu::Mipmapped::kNo,
1333 skgpu::Protected::kNo,
1334 skgpu::Renderable::kNo);
1335 // Use Budgeted::kYes to avoid instantiating the proxy immediately; this test doesn't need
1336 // a full resource.
1337 sk_sp<TextureProxy> fakeDstTexture = TextureProxy::Make(context->priv().caps(),
1338 context->priv().resourceProvider(),
1339 SkISize::Make(1, 1),
1340 dstTexInfo,
1342 constexpr SkIPoint kFakeDstOffset = SkIPoint::Make(0, 0);
1343
1344 KeyContext precompileKeyContext(context->priv().caps(),
1345 dict,
1346 rtDict.get(),
1347 destColorInfo,
1348 fakeDstTexture,
1349 kFakeDstOffset);
1350
1352 const char text[] = "hambur";
1353
1354 constexpr int kNumVerts = 4;
1355 constexpr SkPoint kPositions[kNumVerts] { {0,0}, {0,16}, {16,16}, {16,0} };
1356 constexpr SkColor kColors[kNumVerts] = { SK_ColorBLUE, SK_ColorGREEN,
1358
1359 DrawData drawData = {
1360 make_path(),
1361 SkTextBlob::MakeFromText(text, strlen(text), font),
1363 kPositions, kPositions, kColors),
1365 kPositions, kPositions, /* colors= */ nullptr),
1366 };
1367
1368 ShaderType shaders[] = {
1369 ShaderType::kBlend,
1370 ShaderType::kImage,
1371 ShaderType::kRadialGradient,
1372 ShaderType::kSolidColor,
1373#if EXPANDED_SET
1374 ShaderType::kNone,
1375 ShaderType::kColorFilter,
1376 ShaderType::kCoordClamp,
1377 ShaderType::kConicalGradient,
1378 ShaderType::kEmpty,
1379 ShaderType::kLinearGradient,
1380 ShaderType::kLocalMatrix,
1381 ShaderType::kPerlinNoise,
1382 ShaderType::kPicture,
1383 ShaderType::kSweepGradient,
1384 ShaderType::kWorkingColorSpace,
1385#endif
1386 };
1387
1388 BlenderType blenders[] = {
1389 BlenderType::kPorterDuff,
1390 BlenderType::kShaderBased,
1391 BlenderType::kRuntime,
1392#if EXPANDED_SET
1393 BlenderType::kNone,
1394 BlenderType::kArithmetic,
1395#endif
1396 };
1397
1398 ColorFilterType colorFilters[] = {
1399 ColorFilterType::kNone,
1400 ColorFilterType::kBlendMode,
1401 ColorFilterType::kMatrix,
1402#if EXPANDED_SET
1403 ColorFilterType::kColorSpaceXform,
1404 ColorFilterType::kCompose,
1405 ColorFilterType::kGaussian,
1406 ColorFilterType::kHSLAMatrix,
1407 ColorFilterType::kLerp,
1408 ColorFilterType::kLighting,
1409 ColorFilterType::kLinearToSRGB,
1410 ColorFilterType::kLuma,
1411 ColorFilterType::kRuntime,
1412 ColorFilterType::kSRGBToLinear,
1413 ColorFilterType::kTable,
1414 ColorFilterType::kWorkingFormat,
1415#endif
1416 };
1417
1418 ClipType clips[] = {
1419 ClipType::kNone,
1420#if EXPANDED_SET
1421 ClipType::kShader, // w/ a SkClipOp::kIntersect
1422 ClipType::kShader_Diff, // w/ a SkClipOp::kDifference
1423#endif
1424 };
1425
1426 ImageFilterType imageFilters[] = {
1427 ImageFilterType::kNone,
1428#if EXPANDED_SET
1429 ImageFilterType::kBlur,
1430#endif
1431 };
1432
1433#if EXPANDED_SET
1434 size_t kExpected = std::size(shaders) * std::size(blenders) * std::size(colorFilters) *
1435 std::size(clips) * std::size(imageFilters);
1436 int current = 0;
1437#endif
1438
1439 for (auto shader : shaders) {
1440 for (auto blender : blenders) {
1441 for (auto cf : colorFilters) {
1442 for (auto clip : clips) {
1443 for (auto imageFilter : imageFilters) {
1444#if EXPANDED_SET
1445 SkDebugf("%d/%zu\n", current, kExpected);
1446 ++current;
1447#endif
1448 run_test(reporter, context, testContext, precompileKeyContext, drawData,
1449 shader, blender, cf, clip, imageFilter);
1450 }
1451 }
1452 }
1453 }
1454 }
1455
1456#if EXPANDED_SET
1457 SkASSERT(current == (int) kExpected);
1458#endif
1459}
1460
1462 Context* context,
1464 const KeyContext& precompileKeyContext,
1465 const DrawData& drawData,
1466 ShaderType s,
1467 BlenderType bm,
1468 ColorFilterType cf,
1469 ClipType clip,
1470 ImageFilterType imageFilter) {
1471 SkRandom rand;
1472
1473 std::unique_ptr<Recorder> recorder = context->makeRecorder();
1474
1475 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1476
1477 sk_sp<SkShader> clipShader;
1478 sk_sp<PrecompileShader> clipShaderOption;
1479
1480 if (clip == ClipType::kShader || clip == ClipType::kShader_Diff) {
1481 std::tie(clipShader, clipShaderOption) = create_clip_shader(&rand, recorder.get());
1482 SkASSERT(!clipShader == !clipShaderOption);
1483 }
1484
1486 PipelineDataGatherer paramsGatherer(Layout::kMetal);
1487 PipelineDataGatherer precompileGatherer(Layout::kMetal);
1488
1489 gNeedSKPPaintOption = false;
1490 auto [paint, paintOptions] = create_paint(&rand, recorder.get(), s, bm, cf, imageFilter);
1491
1492 for (DrawTypeFlags dt : { DrawTypeFlags::kSimpleShape,
1493 DrawTypeFlags::kNonSimpleShape,
1494 DrawTypeFlags::kShape,
1495 DrawTypeFlags::kText,
1496 DrawTypeFlags::kDrawVertices }) {
1497
1498 // Note: 'withPrimitiveBlender' and 'primitiveBlender' are only used in ExtractPaintData
1499 // and PaintOptions::buildCombinations. Thus, as long as those two uses agree, it doesn't
1500 // matter if the actual draw uses a primitive blender (i.e., those variables are only used
1501 // in a local unit test independent of the follow-on Precompile/check_draw test)
1502 for (bool withPrimitiveBlender : { false, true }) {
1503
1504 sk_sp<SkBlender> primitiveBlender;
1505 if (withPrimitiveBlender) {
1506 if (dt != DrawTypeFlags::kDrawVertices) {
1507 // Only drawVertices calls need a primitive blender
1508 continue;
1509 }
1510
1511 primitiveBlender = SkBlender::Mode(SkBlendMode::kSrcOver);
1512 }
1513
1514 constexpr Coverage coverageOptions[3] = {
1515 Coverage::kNone, Coverage::kSingleChannel, Coverage::kLCD};
1516 Coverage coverage = coverageOptions[rand.nextULessThan(3)];
1517
1518 DstReadRequirement dstReadReq = DstReadRequirement::kNone;
1519 const SkBlenderBase* blender = as_BB(paint.getBlender());
1520 if (blender) {
1521 dstReadReq = GetDstReadRequirement(recorder->priv().caps(),
1522 blender->asBlendMode(),
1523 coverage);
1524 }
1525 bool needsDstSample = dstReadReq == DstReadRequirement::kTextureCopy ||
1526 dstReadReq == DstReadRequirement::kTextureSample;
1527 sk_sp<TextureProxy> curDst = needsDstSample ? precompileKeyContext.dstTexture()
1528 : nullptr;
1529
1530 // In the normal API this modification happens in SkDevice::clipShader()
1531 // All clipShaders get wrapped in a CTMShader
1532 sk_sp<SkShader> modifiedClipShader = clipShader
1533 ? as_SB(clipShader)->makeWithCTM(SkMatrix::I())
1534 : nullptr;
1535 if (clip == ClipType::kShader_Diff && modifiedClipShader) {
1536 // The CTMShader gets further wrapped in a ColorFilterShader for kDifference clips
1537 modifiedClipShader = modifiedClipShader->makeWithColorFilter(
1539 }
1540
1541 auto [paintID, uData, tData] = ExtractPaintData(
1542 recorder.get(), &paramsGatherer, &builder, Layout::kMetal, {},
1544 primitiveBlender,
1545 std::move(modifiedClipShader),
1546 dstReadReq,
1547 /* skipColorXform= */ false),
1548 curDst,
1549 precompileKeyContext.dstOffset(),
1550 precompileKeyContext.dstColorInfo());
1551
1552 paintOptions.setClipShaders({ clipShaderOption });
1553
1554 std::vector<UniquePaintParamsID> precompileIDs;
1555 paintOptions.priv().buildCombinations(precompileKeyContext,
1556 &precompileGatherer,
1557 DrawTypeFlags::kNone,
1558 withPrimitiveBlender,
1559 coverage,
1560 [&precompileIDs](UniquePaintParamsID id,
1562 bool /* withPrimitiveBlender */,
1563 Coverage) {
1564 precompileIDs.push_back(id);
1565 });
1566
1567 // Although we've gathered both sets of uniforms (i.e., from the paint
1568 // params and the precompilation paths) we can't compare the two since the
1569 // precompilation path may have generated multiple sets
1570 // and the last one created may not be the one that matches the paint
1571 // params' set. Additionally, for runtime effects we just skip gathering
1572 // the uniforms in the precompilation path.
1573
1574 // The specific key generated by ExtractPaintData should be one of the
1575 // combinations generated by the combination system.
1576 auto result = std::find(precompileIDs.begin(), precompileIDs.end(), paintID);
1577
1578 if (result == precompileIDs.end()) {
1579 SkDebugf("Failure on case: %s %s %s %s %s\n",
1580 to_str(s), to_str(bm), to_str(cf), to_str(clip), to_str(imageFilter));
1581 }
1582
1583#ifdef SK_DEBUG
1584 if (result == precompileIDs.end()) {
1585 SkDebugf("From paint: ");
1586 dump(dict, paintID);
1587
1588 SkDebugf("From combination builder [%d]:", static_cast<int>(precompileIDs.size()));
1589 for (auto iter : precompileIDs) {
1590 dump(dict, iter);
1591 }
1592 }
1593#endif
1594
1595 REPORTER_ASSERT(reporter, result != precompileIDs.end());
1596
1597 {
1598 context->priv().globalCache()->resetGraphicsPipelines();
1599
1600 int before = context->priv().globalCache()->numGraphicsPipelines();
1601 Precompile(context, paintOptions, dt);
1602 if (gNeedSKPPaintOption) {
1603 // The skp draws a rect w/ a default SkPaint
1604 PaintOptions skpPaintOptions;
1605 Precompile(context, skpPaintOptions, DrawTypeFlags::kSimpleShape);
1606 }
1607 int after = context->priv().globalCache()->numGraphicsPipelines();
1608
1609 REPORTER_ASSERT(reporter, before == 0);
1610 REPORTER_ASSERT(reporter, after > before);
1611
1612 check_draw(reporter,
1613 context,
1614 testContext,
1615 recorder.get(),
1616 paint,
1617 dt,
1618 clip, clipShader,
1619 drawData);
1620 }
1621 }
1622 }
1623}
1624
1625#endif // SK_GRAPHITE
SkPath fPath
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
reporter
SkColor4f color
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 SkASSERT(cond)
Definition SkAssert.h:116
static constexpr int kSkBlendModeCount
Definition SkBlendMode.h:76
SkBlendMode
Definition SkBlendMode.h:38
@ kSrcOut
r = s * (1-da)
@ kLastCoeffMode
last porter duff blend mode
@ kSrcOver
r = s + (1-sa)*d
@ kLastMode
last valid value
@ kClear
r = 0
SkBlenderBase * as_BB(SkBlender *blend)
SkColorType
Definition SkColorType.h:19
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
constexpr SkColor SK_ColorYELLOW
Definition SkColor.h:139
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition SkColor.h:143
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
@ kJPEG_Full_SkYUVColorSpace
describes full range
Definition SkImageInfo.h:69
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
SkShaderBase * as_SB(SkShader *shader)
SkTileMode
Definition SkTileMode.h:13
static constexpr int kSkTileModeCount
Definition SkTileMode.h:39
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
#define DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(name, reporter, graphite_ctx, test_ctx, cond, ctsEnforcement)
Definition Test.h:352
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
constexpr SkRect kRect
virtual std::optional< SkBlendMode > asBlendMode() const
static sk_sp< SkBlender > Mode(SkBlendMode mode)
static sk_sp< SkBlender > Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul)
void drawRect(const SkRect &rect, const SkPaint &paint)
void experimental_DrawEdgeAAQuad(const SkRect &rect, const SkPoint clip[4], QuadAAFlags aaFlags, const SkColor4f &color, SkBlendMode mode)
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
void drawPath(const SkPath &path, const SkPaint &paint)
void clipShader(sk_sp< SkShader >, SkClipOp=SkClipOp::kIntersect)
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
@ kAll_QuadAAFlags
Definition SkCanvas.h:1665
static sk_sp< SkColorFilter > WithWorkingFormat(sk_sp< SkColorFilter > child, const skcms_TransferFunction *tf, const skcms_Matrix3x3 *gamut, const SkAlphaType *at)
static sk_sp< SkColorFilter > MakeColorSpaceXform(sk_sp< SkColorSpace > src, sk_sp< SkColorSpace > dst)
static sk_sp< SkColorFilter > MakeGaussian()
static sk_sp< SkColorFilter > Compose(const sk_sp< SkColorFilter > &outer, sk_sp< SkColorFilter > inner)
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
static sk_sp< SkColorFilter > Table(const uint8_t table[256])
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
static sk_sp< SkColorFilter > HSLAMatrix(const SkColorMatrix &)
static sk_sp< SkColorFilter > Lighting(SkColor mul, SkColor add)
static sk_sp< SkColorFilter > SRGBToLinearGamma()
static sk_sp< SkColorFilter > Lerp(float t, sk_sp< SkColorFilter > dst, sk_sp< SkColorFilter > src)
static sk_sp< SkColorFilter > LinearToSRGBGamma()
static SkColorMatrix RGBtoYUV(SkYUVColorSpace)
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkColorSpace > MakeSRGBLinear()
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111
static sk_sp< SkShader > MakeTwoPointConical(const SkPoint &start, SkScalar startRadius, const SkPoint &end, SkScalar endRadius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkImageFilter > Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
SkMatrix & setTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:254
SkMatrix & setIdentity()
Definition SkMatrix.h:626
static const SkMatrix & I()
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, const SkMatrix *localMatrix, const SkRect *tileRect) const
static SkRRect MakeOval(const SkRect &oval)
Definition SkRRect.h:162
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.h:180
uint32_t nextU()
Definition SkRandom.h:42
bool nextBool()
Definition SkRandom.h:117
uint32_t nextULessThan(uint32_t count)
Definition SkRandom.h:93
float nextRangeF(float min, float max)
Definition SkRandom.h:64
uint32_t nextRangeU(uint32_t min, uint32_t max)
Definition SkRandom.h:80
static Result MakeForColorFilter(SkString sksl, const Options &)
sk_sp< SkBlender > makeBlender(sk_sp< const SkData > uniforms, SkSpan< const ChildPtr > children={}) const
static Result MakeForBlender(SkString sksl, const Options &)
sk_sp< SkColorFilter > makeColorFilter(sk_sp< const SkData > uniforms) const
sk_sp< SkShader > makeWithCTM(const SkMatrix &) const
static sk_sp< SkTextBlob > MakeFromText(const void *text, size_t byteLength, const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
@ kTriangleFan_VertexMode
Definition SkVertices.h:33
SkIPoint dstOffset() const
Definition KeyContext.h:70
sk_sp< TextureProxy > dstTexture() const
Definition KeyContext.h:68
const SkColorInfo & dstColorInfo() const
Definition KeyContext.h:65
void buildCombinations(const KeyContext &keyContext, PipelineDataGatherer *gatherer, DrawTypeFlags drawTypes, bool withPrimitiveBlender, Coverage coverage, const PaintOptions::ProcessCombination &processCombination) const
void setColorFilters(SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
Definition Precompile.h:180
void setImageFilters(SkEnumBitMask< PrecompileImageFilters > options)
Definition Precompile.h:184
void setDither(bool dither)
Definition Precompile.h:203
void setShaders(SkSpan< const sk_sp< PrecompileShader > > shaders)
Definition Precompile.h:172
void setClipShaders(SkSpan< const sk_sp< PrecompileShader > > clipShaders)
void setBlenders(SkSpan< const sk_sp< PrecompileBlender > > blenders)
Definition Precompile.h:191
std::unique_ptr< Recording > snap()
Definition Recorder.cpp:149
PaintParamsKey lookup(UniquePaintParamsID) const SK_EXCLUDES(fSpinLock)
void syncedSubmit(skgpu::graphite::Context *)
const Paint & paint
static const skcms_Matrix3x3 gGamuts[]
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct s
FlutterSemanticsFlag flags
GAsyncResult * result
std::u16string text
static sk_sp< SkImage > make_image()
Definition mipmap.cpp:21
constexpr SkColor4f kTransparent
Definition SkColor.h:434
SK_API sk_sp< SkImage > TextureFromImage(GrDirectContext *, const SkImage *, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Budgeted=skgpu::Budgeted::kYes)
static constexpr skcms_Matrix3x3 kSRGB
static constexpr skcms_Matrix3x3 kAdobeRGB
static constexpr skcms_Matrix3x3 kXYZ
static constexpr skcms_Matrix3x3 kRec2020
static constexpr skcms_Matrix3x3 kDisplayP3
static constexpr skcms_TransferFunction kRec2020
static constexpr skcms_TransferFunction k2Dot2
static constexpr skcms_TransferFunction kSRGB
static constexpr skcms_TransferFunction kHLG
static constexpr skcms_TransferFunction kPQ
static constexpr skcms_TransferFunction kLinear
sk_sp< const SkPicture > picture
Definition SkRecords.h:299
PODArray< SkColor > colors
Definition SkRecords.h:276
SK_API sk_sp< SkShader > MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
SK_API sk_sp< SkShader > MakeFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
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)
sk_sp< SkTypeface > DefaultPortableTypeface()
void FetchUniqueKeys(GlobalCache *globalCache, std::vector< UniqueKey > *keys)
bool ExtractKeyDescs(Context *context, const UniqueKey &origKey, GraphicsPipelineDesc *pipelineDesc, RenderPassDesc *renderPassDesc)
const DlColor kColors[]
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
@ kBlur
Definition paint.cc:59
font
Font Metadata and Metrics.
dst
Definition cp.py:12
sk_sp< PrecompileBlender > MakePrecompileBlender(sk_sp< SkRuntimeEffect > effect, SkSpan< const PrecompileChildOptions > childOptions)
DstReadRequirement GetDstReadRequirement(const Caps *caps, std::optional< SkBlendMode > blendMode, Coverage coverage)
bool Precompile(Context *context, RuntimeEffectDictionary *rteDict, const GraphicsPipelineDesc &pipelineDesc, const RenderPassDesc &renderPassDesc)
std::tuple< UniquePaintParamsID, const UniformDataBlock *, const TextureDataBlock * > ExtractPaintData(Recorder *recorder, PipelineDataGatherer *gatherer, PaintParamsKeyBuilder *builder, const Layout layout, const SkM44 &local2Dev, const PaintParams &p, sk_sp< TextureProxy > dstTexture, SkIPoint dstOffset, const SkColorInfo &targetColorInfo)
sk_sp< PrecompileColorFilter > MakePrecompileColorFilter(sk_sp< SkRuntimeEffect > effect, SkSpan< const PrecompileChildOptions > childOptions)
void run_test(skiatest::Reporter *reporter, Context *context, SkISize surfaceSize, SkISize recordingSize, SkISize replayOffset, DrawCallback draw, const std::vector< Expectation > &expectations)
static SkPath make_path()
#define M(PROC, DITHER)
static constexpr SkIPoint Make(int32_t x, int32_t y)
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static sk_sp< SkColorFilter > Make()
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static sk_sp< SkPicture > make_picture()
Definition picture.cpp:22