Flutter Engine
The Flutter Engine
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
15#include "include/core/SkM44.h"
41#include "src/base/SkRandom.h"
48//#include "src/gpu/graphite/FactoryFunctionsPriv.h"
68#include "tools/ToolUtils.h"
72
73// Set this to 1 for more expansive (aka far slower) local testing
74#define EXPANDED_SET 0
75
76// This flag is set to true if during the PaintOption creation an SkPictureShader is created.
77// The SkPictureShader will need an additional program in order to draw the contents of its
78// SkPicture.
79bool gNeedSKPPaintOption = false;
80
81using namespace skgpu::graphite;
82
83namespace {
84
85std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom*, Recorder*);
86std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom*);
87std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(SkRandom*);
88
89[[maybe_unused]] std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>>
90create_random_image_filter(Recorder*, SkRandom*);
91
92//--------------------------------------------------------------------------------------------------
93//--------------------------------------------------------------------------------------------------
94#define SK_ALL_TEST_SHADERS(M) \
95 M(Blend) \
96 M(ColorFilter) \
97 M(CoordClamp) \
98 M(ConicalGradient) \
99 M(Empty) \
100 M(Image) \
101 M(LinearGradient) \
102 M(LocalMatrix) \
103 M(None) \
104 M(PerlinNoise) \
105 M(Picture) \
106 M(RadialGradient) \
107 M(Runtime) \
108 M(SolidColor) \
109 M(SweepGradient) \
110 M(WorkingColorSpace)
111
112enum class ShaderType {
113#define M(type) k##type,
114 SK_ALL_TEST_SHADERS(M)
115#undef M
116
117 kLast = kWorkingColorSpace
118};
119
120static constexpr int kShaderTypeCount = static_cast<int>(ShaderType::kLast) + 1;
121
122const char* to_str(ShaderType s) {
123 switch (s) {
124#define M(type) case ShaderType::k##type : return "ShaderType::k" #type;
125 SK_ALL_TEST_SHADERS(M)
126#undef M
127 }
128
130}
131
132//--------------------------------------------------------------------------------------------------
133//--------------------------------------------------------------------------------------------------
134#define SK_ALL_TEST_MASKFILTERS(M) \
135 M(None) \
136 M(Blur)
137
138enum class MaskFilterType {
139#define M(type) k##type,
140 SK_ALL_TEST_MASKFILTERS(M)
141#undef M
142
143 kLast = kBlur
144};
145
146const char* to_str(MaskFilterType mf) {
147 switch (mf) {
148#define M(type) case MaskFilterType::k##type : return "MaskFilterType::k" #type;
149 SK_ALL_TEST_MASKFILTERS(M)
150#undef M
151 }
152
154}
155
156//--------------------------------------------------------------------------------------------------
157//--------------------------------------------------------------------------------------------------
158#define SK_ALL_TEST_BLENDERS(M) \
159 M(None) \
160 M(PorterDuff) \
161 M(ShaderBased) \
162 M(Arithmetic) \
163 M(Runtime)
164
165// TODO: do we need to add a separable category and/or a category for dstRead requiring blends?
166enum class BlenderType {
167#define M(type) k##type,
168 SK_ALL_TEST_BLENDERS(M)
169#undef M
170
171 kLast = kRuntime
172};
173
174static constexpr int kBlenderTypeCount = static_cast<int>(BlenderType::kLast) + 1;
175
176const char* to_str(BlenderType b) {
177 switch (b) {
178#define M(type) case BlenderType::k##type : return "BlenderType::k" #type;
179 SK_ALL_TEST_BLENDERS(M)
180#undef M
181 }
182
184}
185
186std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_blender(SkRandom*, BlenderType);
187
188//--------------------------------------------------------------------------------------------------
189//--------------------------------------------------------------------------------------------------
190#define SK_ALL_TEST_COLORFILTERS(M) \
191 M(None) \
192 M(BlendMode) \
193 M(ColorSpaceXform) \
194 M(Compose) \
195 M(Gaussian) \
196 M(HighContrast) \
197 M(HSLAMatrix) \
198 M(Lerp) \
199 M(Lighting) \
200 M(LinearToSRGB) \
201 M(Luma) \
202 M(Matrix) \
203 M(Overdraw) \
204 M(Runtime) \
205 M(SRGBToLinear) \
206 M(Table) \
207 M(WorkingFormat)
208
209enum class ColorFilterType {
210#define M(type) k##type,
211 SK_ALL_TEST_COLORFILTERS(M)
212#undef M
213
214 kLast = kWorkingFormat
215};
216
217static constexpr int kColorFilterTypeCount = static_cast<int>(ColorFilterType::kLast) + 1;
218
219const char* to_str(ColorFilterType cf) {
220 switch (cf) {
221#define M(type) case ColorFilterType::k##type : return "ColorFilterType::k" #type;
222 SK_ALL_TEST_COLORFILTERS(M)
223#undef M
224 }
225
227}
228
229//--------------------------------------------------------------------------------------------------
230//--------------------------------------------------------------------------------------------------
231#define SK_ALL_TEST_CLIPS(M) \
232 M(None) \
233 M(Shader) \
234 M(Shader_Diff)
235
236enum class ClipType {
237#define M(type) k##type,
238 SK_ALL_TEST_CLIPS(M)
239#undef M
240};
241
242const char* to_str(ClipType c) {
243 switch (c) {
244#define M(type) case ClipType::k##type : return "ClipType::k" #type;
245 SK_ALL_TEST_CLIPS(M)
246#undef M
247 }
248
250}
251
252//--------------------------------------------------------------------------------------------------
253//--------------------------------------------------------------------------------------------------
254#define SK_ALL_TEST_IMAGE_FILTERS(M) \
255 M(None) \
256 M(Arithmetic) \
257 M(BlendMode) \
258 M(RuntimeBlender) \
259 M(Blur) \
260 M(ColorFilter) \
261 M(Displacement) \
262 M(Lighting) \
263 M(MatrixConvolution) \
264 M(Morphology)
265
266enum class ImageFilterType {
267#define M(type) k##type,
268 SK_ALL_TEST_IMAGE_FILTERS(M)
269#undef M
270 kLast = kMorphology
271};
272
273static constexpr int kImageFilterTypeCount = static_cast<int>(ImageFilterType::kLast) + 1;
274
275const char* to_str(ImageFilterType c) {
276 switch (c) {
277#define M(type) case ImageFilterType::k##type : return "ImageFilterType::k" #type;
278 SK_ALL_TEST_IMAGE_FILTERS(M)
279#undef M
280 }
282}
283
284//--------------------------------------------------------------------------------------------------
285//--------------------------------------------------------------------------------------------------
286static constexpr skcms_TransferFunction gTransferFunctions[] = {
293};
294
295static constexpr int kTransferFunctionCount = std::size(gTransferFunctions);
296
297const skcms_TransferFunction& random_xfer_function(SkRandom* rand) {
298 return gTransferFunctions[rand->nextULessThan(kTransferFunctionCount)];
299}
300
301static constexpr skcms_Matrix3x3 gGamuts[] = {
307};
308
309static constexpr int kGamutCount = std::size(gGamuts);
310
311const skcms_Matrix3x3& random_gamut(SkRandom* rand) {
312 return gGamuts[rand->nextULessThan(kGamutCount)];
313}
314
315enum class ColorSpaceType {
316 kNone,
317 kSRGB,
318 kSRGBLinear,
319 kRGB,
320
321 kLast = kRGB
322};
323
324static constexpr int kColorSpaceTypeCount = static_cast<int>(ColorSpaceType::kLast) + 1;
325
326ColorSpaceType random_colorspacetype(SkRandom* rand) {
327 return static_cast<ColorSpaceType>(rand->nextULessThan(kColorSpaceTypeCount));
328}
329
330sk_sp<SkColorSpace> random_colorspace(SkRandom* rand) {
331 ColorSpaceType cs = random_colorspacetype(rand);
332
333 switch (cs) {
335 return nullptr;
336 case ColorSpaceType::kSRGB:
337 return SkColorSpace::MakeSRGB();
338 case ColorSpaceType::kSRGBLinear:
340 case ColorSpaceType::kRGB:
341 return SkColorSpace::MakeRGB(random_xfer_function(rand), random_gamut(rand));
342 }
343
345}
346
347enum class ColorConstraint {
348 kNone,
349 kOpaque,
351};
352
353SkColor random_color(SkRandom* rand, ColorConstraint constraint) {
354 uint32_t color = rand->nextU();
355
356 switch (constraint) {
357 case ColorConstraint::kNone: return color;
358 case ColorConstraint::kOpaque: return 0xff000000 | color;
359 case ColorConstraint::kTransparent: return 0x80000000 | color;
360 }
361
363}
364
365SkColor4f random_color4f(SkRandom* rand, ColorConstraint constraint) {
366 SkColor4f result = { rand->nextRangeF(0.0f, 1.0f),
367 rand->nextRangeF(0.0f, 1.0f),
368 rand->nextRangeF(0.0f, 1.0f),
369 rand->nextRangeF(0.0f, 1.0f) };
370
371 switch (constraint) {
372 case ColorConstraint::kNone: return result;
373 case ColorConstraint::kOpaque: result.fA = 1.0f; return result;
374 case ColorConstraint::kTransparent: result.fA = 0.5f; return result;
375 }
376
378}
379
380SkTileMode random_tilemode(SkRandom* rand) {
381 return static_cast<SkTileMode>(rand->nextULessThan(kSkTileModeCount));
382}
383
384ShaderType random_shadertype(SkRandom* rand) {
385 return static_cast<ShaderType>(rand->nextULessThan(kShaderTypeCount));
386}
387
388SkBlendMode random_porter_duff_bm(SkRandom* rand) {
389 return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kClear,
390 (unsigned int) SkBlendMode::kLastCoeffMode));
391}
392
393SkBlendMode random_complex_bm(SkRandom* rand) {
394 return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kLastCoeffMode,
395 (unsigned int) SkBlendMode::kLastMode));
396}
397
398SkBlendMode random_blend_mode(SkRandom* rand) {
399 return static_cast<SkBlendMode>(rand->nextULessThan(kSkBlendModeCount));
400}
401
402BlenderType random_blendertype(SkRandom* rand) {
403 return static_cast<BlenderType>(rand->nextULessThan(kBlenderTypeCount));
404}
405
406ColorFilterType random_colorfiltertype(SkRandom* rand) {
407 return static_cast<ColorFilterType>(rand->nextULessThan(kColorFilterTypeCount));
408}
409
410ImageFilterType random_imagefiltertype(SkRandom* rand) {
411 return static_cast<ImageFilterType>(rand->nextULessThan(kImageFilterTypeCount));
412}
413
414SkMatrix* random_local_matrix(SkRandom* rand, SkMatrix* storage) {
415 switch (rand->nextULessThan(3)) {
416 case 0: return nullptr;
417 case 1: storage->setIdentity(); return storage;
418 case 2: [[fallthrough]];
419 default: storage->setTranslate(2.0f, 2.0f); return storage;
420 }
421
423}
424
425sk_sp<SkImage> make_image(SkRandom* rand, Recorder* recorder) {
427 if (rand->nextBool()) {
429 }
430
431 SkImageInfo info = SkImageInfo::Make(32, 32, ct, kPremul_SkAlphaType, random_colorspace(rand));
432
434 bitmap.allocPixels(info);
435 bitmap.eraseColor(SK_ColorBLACK);
436
437 sk_sp<SkImage> img = bitmap.asImage();
438
439 // TODO: fuzz mipmappedness
440 return SkImages::TextureFromImage(recorder, img, {false});
441}
442
443//--------------------------------------------------------------------------------------------------
445 constexpr SkRect kRect = SkRect::MakeWH(128, 128);
446
447 SkPictureRecorder recorder;
448
449 SkCanvas* canvas = recorder.beginRecording(kRect);
450
451 SkPaint paint; // Explicitly using the default SkPaint here
452
453 canvas->drawRect(kRect, paint);
454
455 return recorder.finishRecordingAsPicture();
456}
457
458//--------------------------------------------------------------------------------------------------
459std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_coord_clamp_shader(SkRandom* rand,
460 Recorder* recorder) {
461 auto [s, o] = create_random_shader(rand, recorder);
462 SkASSERT(!s == !o);
463
464 if (!s) {
465 return { nullptr, nullptr };
466 }
467
468 constexpr SkRect kSubset{0, 0, 256, 256}; // this is somewhat arbitrary but we need some subset
469 sk_sp<SkShader> ccs = SkShaders::CoordClamp(std::move(s), kSubset);
471
472 return { ccs, cco };
473}
474
475std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_empty_shader(SkRandom* /* rand */) {
478
479 return { s, o };
480}
481
482std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_perlin_noise_shader(SkRandom* rand) {
485
486 if (rand->nextBool()) {
487 s = SkShaders::MakeFractalNoise(/* baseFrequencyX= */ 0.3f,
488 /* baseFrequencyY= */ 0.3f,
489 /* numOctaves= */ 2,
490 /* seed= */ 4);
492 } else {
493 s = SkShaders::MakeTurbulence(/* baseFrequencyX= */ 0.3f,
494 /* baseFrequencyY= */ 0.3f,
495 /* numOctaves= */ 2,
496 /* seed= */ 4);
498 }
499
500 return { s, o };
501}
502
503std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_picture_shader(SkRandom* rand) {
505
506 gNeedSKPPaintOption = true;
507
508 SkMatrix lmStorage;
509 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
510
511 // TODO: can the clamp, filter mode, or tileRect affect the final program?
515 lmPtr,
516 /* tileRect= */ nullptr);
518
519 return { s, o };
520}
521
522std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_runtime_shader(SkRandom* /* rand */) {
523 static SkRuntimeEffect* sEffect = SkMakeRuntimeEffect(
525 // draw a circle centered at "center" w/ inner and outer radii in "radii"
526 "uniform float2 center;"
527 "uniform float2 radii;"
528 "half4 main(float2 xy) {"
529 "float len = length(xy - center);"
530 "half value = len < radii.x ? 0.0 : (len > radii.y ? 0.0 : 1.0);"
531 "return half4(value);"
532 "}"
533 );
534
535 static const float kUniforms[4] = { 50.0f, 50.0f, 40.0f, 50.0f };
536
537 sk_sp<SkData> uniforms = SkData::MakeWithCopy(kUniforms, sizeof(kUniforms));
538
539 sk_sp<SkShader> s = sEffect->makeShader(std::move(uniforms), /* children= */ {});
541 return { std::move(s), std::move(o) };
542}
543
544std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_solid_shader(
545 SkRandom* rand,
546 ColorConstraint constraint = ColorConstraint::kNone) {
549
550 if (rand->nextBool()) {
551 s = SkShaders::Color(random_color(rand, constraint));
553 } else {
554 sk_sp<SkColorSpace> cs = random_colorspace(rand);
555 s = SkShaders::Color(random_color4f(rand, constraint), cs);
556 o = PrecompileShaders::Color(std::move(cs));
557 }
558
559 return { s, o };
560}
561
562std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_gradient_shader(
563 SkRandom* rand,
565 ColorConstraint constraint = ColorConstraint::kOpaque) {
566 // TODO: fuzz more of the gradient parameters
567
568 static constexpr int kMaxNumStops = 9;
569 SkColor colors[kMaxNumStops] = {
570 random_color(rand, constraint),
571 random_color(rand, constraint),
572 random_color(rand, constraint),
573 random_color(rand, constraint),
574 random_color(rand, constraint),
575 random_color(rand, constraint),
576 random_color(rand, constraint),
577 random_color(rand, constraint),
578 random_color(rand, constraint)
579 };
580 static const SkPoint kPts[kMaxNumStops] = {
581 { -100.0f, -100.0f },
582 { -50.0f, -50.0f },
583 { -25.0f, -25.0f },
584 { -12.5f, -12.5f },
585 { 0.0f, 0.0f },
586 { 12.5f, 12.5f },
587 { 25.0f, 25.0f },
588 { 50.0f, 50.0f },
589 { 100.0f, 100.0f }
590 };
591 static const float kOffsets[kMaxNumStops] =
592 { 0.0f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, 1.0f };
593
594 int numStops;
595
596 switch (rand->nextULessThan(3)) {
597 case 0: numStops = 2; break;
598 case 1: numStops = 7; break;
599 case 2: [[fallthrough]];
600 default: numStops = kMaxNumStops; break;
601 }
602
603 SkMatrix lmStorage;
604 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
605
607
610
611 SkTileMode tm = random_tilemode(rand);
612
613 switch (type) {
616 colors, kOffsets, numStops, tm, flags, lmPtr);
618 break;
619 case SkShaderBase::GradientType::kRadial:
620 s = SkGradientShader::MakeRadial(/* center= */ {0, 0}, /* radius= */ 100,
621 colors, kOffsets, numStops, tm, flags, lmPtr);
623 break;
624 case SkShaderBase::GradientType::kSweep:
625 s = SkGradientShader::MakeSweep(/* cx= */ 0, /* cy= */ 0,
626 colors, kOffsets, numStops, tm,
627 /* startAngle= */ 0, /* endAngle= */ 359,
628 flags, lmPtr);
630 break;
631 case SkShaderBase::GradientType::kConical:
632 s = SkGradientShader::MakeTwoPointConical(/* start= */ {100, 100},
633 /* startRadius= */ 100,
634 /* end= */ {-100, -100},
635 /* endRadius= */ 100,
636 colors, kOffsets, numStops, tm, flags, lmPtr);
638 break;
640 SkDEBUGFAIL("Gradient shader says its type is none");
641 break;
642 }
643
644 return { s, o };
645}
646
647std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_localmatrix_shader(SkRandom* rand,
648 Recorder* recorder) {
649 auto [s, o] = create_random_shader(rand, recorder);
650 SkASSERT(!s == !o);
651
652 if (!s) {
653 return { nullptr, nullptr };
654 }
655
656 SkMatrix lmStorage;
657 random_local_matrix(rand, &lmStorage);
658
659 return { s->makeWithLocalMatrix(lmStorage), o->makeWithLocalMatrix() };
660}
661
662std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_colorfilter_shader(SkRandom* rand,
663 Recorder* recorder) {
664 auto [s, o] = create_random_shader(rand, recorder);
665 SkASSERT(!s == !o);
666
667 if (!s) {
668 return { nullptr, nullptr };
669 }
670
671 auto [cf, cfO] = create_random_colorfilter(rand);
672
673 return { s->makeWithColorFilter(std::move(cf)), o->makeWithColorFilter(std::move(cfO)) };
674}
675
676// TODO: With the new explicit PrecompileImageFilter API we need to test out complete DAGS of IFs
677std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_image_shader(SkRandom* rand,
678 Recorder* recorder) {
679 SkTileMode tmX = random_tilemode(rand);
680 SkTileMode tmY = random_tilemode(rand);
681
682 SkMatrix lmStorage;
683 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
684
687
688 // TODO: the combination system accounts for cubic vs. non-cubic sampling and HW vs. non-HW
689 // tiling. We should test those combinations in the fuzzer.
690 if (rand->nextBool()) {
691 s = SkShaders::Image(make_image(rand, recorder),
692 tmX, tmY,
694 lmPtr);
696 } else {
697 s = SkShaders::RawImage(make_image(rand, recorder),
698 tmX, tmY,
700 lmPtr);
702 }
703
704 return { s, o };
705}
706
707std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_blend_shader(SkRandom* rand,
708 Recorder* recorder) {
709 // TODO: add explicit testing of the kClear, kDst and kSrc blend modes since they short
710 // circuit creation of a true blend shader (i.e., in SkShaders::Blend).
711 auto [blender, blenderO] = create_random_blender(rand);
712
713 auto [dstS, dstO] = create_random_shader(rand, recorder);
714 SkASSERT(!dstS == !dstO);
715 if (!dstS) {
716 return { nullptr, nullptr };
717 }
718
719 auto [srcS, srcO] = create_random_shader(rand, recorder);
720 SkASSERT(!srcS == !srcO);
721 if (!srcS) {
722 return { nullptr, nullptr };
723 }
724
725 auto s = SkShaders::Blend(std::move(blender), std::move(dstS), std::move(srcS));
726 auto o = PrecompileShaders::Blend(SkSpan<const sk_sp<PrecompileBlender>>({ blenderO }),
727 { dstO }, { srcO });
728
729 return { s, o };
730}
731
732std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_workingCS_shader(SkRandom* rand,
733 Recorder* recorder) {
734 auto [wrappedS, wrappedO] = create_random_shader(rand, recorder);
735 SkASSERT(!wrappedS == !wrappedO);
736 if (!wrappedS) {
737 return { nullptr, nullptr };
738 }
739
740 sk_sp<SkColorSpace> cs = random_colorspace(rand);
741 sk_sp<SkShader> s = wrappedS->makeWithWorkingColorSpace(cs);
742 sk_sp<PrecompileShader> o = wrappedO->makeWithWorkingColorSpace(std::move(cs));
743
744 return { s, o };
745}
746
747std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_shader(SkRandom* rand,
748 Recorder* recorder,
749 ShaderType shaderType) {
750
751 switch (shaderType) {
753 return { nullptr, nullptr };
754 case ShaderType::kBlend:
755 return create_blend_shader(rand, recorder);
756 case ShaderType::kColorFilter:
757 return create_colorfilter_shader(rand, recorder);
758 case ShaderType::kCoordClamp:
759 return create_coord_clamp_shader(rand, recorder);
760 case ShaderType::kConicalGradient:
761 return create_gradient_shader(rand, SkShaderBase::GradientType::kConical);
763 return create_empty_shader(rand);
764 case ShaderType::kImage:
765 return create_image_shader(rand, recorder);
766 case ShaderType::kLinearGradient:
767 return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear);
768 case ShaderType::kLocalMatrix:
769 return create_localmatrix_shader(rand, recorder);
770 case ShaderType::kPerlinNoise:
771 return create_perlin_noise_shader(rand);
772 case ShaderType::kPicture:
773 return create_picture_shader(rand);
774 case ShaderType::kRadialGradient:
775 return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial);
776 case ShaderType::kRuntime:
777 return create_runtime_shader(rand);
778 case ShaderType::kSolidColor:
779 return create_solid_shader(rand);
780 case ShaderType::kSweepGradient:
781 return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep);
782 case ShaderType::kWorkingColorSpace:
783 return create_workingCS_shader(rand, recorder);
784 }
785
787}
788
789std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom* rand,
790 Recorder* recorder) {
791 return create_shader(rand, recorder, random_shadertype(rand));
792}
793
794std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_clip_shader(SkRandom* rand,
795 Recorder* recorder) {
796 // The clip shader has to be transparent to be at all interesting.
797 // TODO/Note: an opaque clipShader is eliminated from the SkPaint by the normal Skia API
798 // but I'm unsure if we should bother capturing that possibility in the precompile system.
799 switch (rand->nextULessThan(5)) {
800 case 0: return create_gradient_shader(rand, SkShaderBase::GradientType::kConical,
802 case 1: return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear,
804 case 2: return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial,
806 case 3: return create_solid_shader(rand, ColorConstraint::kTransparent);
807 case 4: return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep,
809 }
810
812}
813
814//--------------------------------------------------------------------------------------------------
815std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> src_blender() {
816 static SkRuntimeEffect* sSrcEffect = SkMakeRuntimeEffect(
818 "half4 main(half4 src, half4 dst) {"
819 "return src;"
820 "}"
821 );
822
823 sk_sp<SkBlender> b = sSrcEffect->makeBlender(/* uniforms= */ nullptr);
825 return { std::move(b) , std::move(o) };
826}
827
828std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> dest_blender() {
829 static SkRuntimeEffect* sDestEffect = SkMakeRuntimeEffect(
831 "half4 main(half4 src, half4 dst) {"
832 "return dst;"
833 "}"
834 );
835
836 sk_sp<SkBlender> b = sDestEffect->makeBlender(/* uniforms= */ nullptr);
838 return { std::move(b) , std::move(o) };
839}
840
841
842std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> combo_blender() {
843 static SkRuntimeEffect* sComboEffect = SkMakeRuntimeEffect(
845 "uniform float blendFrac;"
846 "uniform blender a;"
847 "uniform blender b;"
848 "half4 main(half4 src, half4 dst) {"
849 "return (blendFrac * a.eval(src, dst)) + ((1 - blendFrac) * b.eval(src, dst));"
850 "}"
851 );
852
853 auto [src, srcO] = src_blender();
854 auto [dst, dstO] = dest_blender();
855
856 SkRuntimeEffect::ChildPtr children[] = { src, dst };
857 const PrecompileChildPtr childOptions[] = { srcO, dstO };
858
859 const float kUniforms[] = { 1.0f };
860
861 sk_sp<SkData> uniforms = SkData::MakeWithCopy(kUniforms, sizeof(kUniforms));
862 sk_sp<SkBlender> b = sComboEffect->makeBlender(std::move(uniforms), children);
863 sk_sp<PrecompileBlender> o = MakePrecompileBlender(sk_ref_sp(sComboEffect), { childOptions });
864 return { std::move(b) , std::move(o) };
865}
866
867std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_bm_blender(SkRandom* rand,
868 SkBlendMode bm) {
869 return { SkBlender::Mode(bm), PrecompileBlenders::Mode(bm) };
870}
871
872std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_arithmetic_blender() {
874 /* k2= */ 0.5,
875 /* k3= */ 0.5,
876 /* k4= */ 0.5,
877 /* enforcePremul= */ true);
879
880 return { std::move(b), std::move(o) };
881}
882
883std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_rt_blender(SkRandom* rand) {
884 int option = rand->nextULessThan(3);
885
886 switch (option) {
887 case 0: return src_blender();
888 case 1: return dest_blender();
889 case 2: return combo_blender();
890 }
891
892 return { nullptr, nullptr };
893}
894
895std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_blender(SkRandom* rand,
896 BlenderType type) {
897 switch (type) {
899 return { nullptr, nullptr };
900 case BlenderType::kPorterDuff:
901 return create_bm_blender(rand, random_porter_duff_bm(rand));
902 case BlenderType::kShaderBased:
903 return create_bm_blender(rand, random_complex_bm(rand));
904 case BlenderType::kArithmetic:
905 return create_arithmetic_blender();
906 case BlenderType::kRuntime:
907 return create_rt_blender(rand);
908 }
909
911}
912
913std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom* rand) {
914 return create_blender(rand, random_blendertype(rand));
915}
916
917//--------------------------------------------------------------------------------------------------
918//--------------------------------------------------------------------------------------------------
919std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> double_colorfilter() {
920 static SkRuntimeEffect* sSrcEffect = SkMakeRuntimeEffect(
922 "half4 main(half4 c) {"
923 "return 2*c;"
924 "}"
925 );
926
927 return { sSrcEffect->makeColorFilter(/* uniforms= */ nullptr),
929}
930
931std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> half_colorfilter() {
932 static SkRuntimeEffect* sDestEffect = SkMakeRuntimeEffect(
934 "half4 main(half4 c) {"
935 "return 0.5*c;"
936 "}"
937 );
938
939 return { sDestEffect->makeColorFilter(/* uniforms= */ nullptr),
940 MakePrecompileColorFilter(sk_ref_sp(sDestEffect)) };
941}
942
943std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> combo_colorfilter() {
944 static SkRuntimeEffect* sComboEffect = SkMakeRuntimeEffect(
946 "uniform float blendFrac;"
947 "uniform colorFilter a;"
948 "uniform colorFilter b;"
949 "half4 main(half4 c) {"
950 "return (blendFrac * a.eval(c)) + ((1 - blendFrac) * b.eval(c));"
951 "}"
952 );
953
954 auto [src, srcO] = double_colorfilter();
955 auto [dst, dstO] = half_colorfilter();
956
957 SkRuntimeEffect::ChildPtr children[] = { src, dst };
958 const PrecompileChildPtr childOptions[] = { srcO, dstO };
959
960 const float kUniforms[] = { 0.5f };
961
962 sk_sp<SkData> uniforms = SkData::MakeWithCopy(kUniforms, sizeof(kUniforms));
963 sk_sp<SkColorFilter> cf = sComboEffect->makeColorFilter(std::move(uniforms), children);
965 { childOptions });
966 return { std::move(cf) , std::move(o) };
967}
968
969std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_rt_colorfilter(
970 SkRandom* rand) {
971 int option = rand->nextULessThan(3);
972
973 switch (option) {
974 case 0: return double_colorfilter();
975 case 1: return half_colorfilter();
976 case 2: return combo_colorfilter();
977 }
978
979 return { nullptr, nullptr };
980}
981
982std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_lerp_colorfilter(
983 SkRandom* rand) {
984
985 auto [dst, dstO] = create_random_colorfilter(rand);
986 auto [src, srcO] = create_random_colorfilter(rand);
987 // SkColorFilters::Lerp optimizes away the case where src == dst. I don't know if it is worth
988 // capturing it in the precompilation API
989 while (src == dst) {
990 std::tie(src, srcO) = create_random_colorfilter(rand);
991 }
992
993 // TODO: SkColorFilters::Lerp will return a different colorFilter depending on the
994 // weight value and the child color filters. I don't know if that is worth capturing
995 // in the precompile API.
996 sk_sp<SkColorFilter> cf = SkColorFilters::Lerp(0.5f, std::move(dst), std::move(src));
997
999
1000 return { cf, o };
1001}
1002
1003std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_lighting_colorfilter() {
1004 // TODO: the lighting color filter factory special cases when nothing is added and converts it
1005 // to a blendmode color filter
1008}
1009
1010std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_blendmode_colorfilter(
1011 SkRandom* rand) {
1012
1014
1015 // SkColorFilters::Blend is clever and can weed out noop color filters. Loop until we get
1016 // a valid color filter.
1017 while (!cf) {
1018 cf = SkColorFilters::Blend(random_color4f(rand, ColorConstraint::kNone),
1019 random_colorspace(rand),
1020 random_blend_mode(rand));
1021 }
1022
1024
1025 return { std::move(cf), std::move(o) };
1026}
1027
1028std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_matrix_colorfilter() {
1032
1033 return { std::move(cf), std::move(o) };
1034}
1035
1036std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_color_space_colorfilter(
1037 SkRandom* rand) {
1038 return { SkColorFilterPriv::MakeColorSpaceXform(random_colorspace(rand),
1039 random_colorspace(rand)),
1041}
1042
1043std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_linear_to_srgb_colorfilter() {
1045}
1046
1047std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_srgb_to_linear_colorfilter() {
1049}
1050
1051std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_high_contrast_colorfilter() {
1052 SkHighContrastConfig config(/* grayscale= */ false,
1054 /* contrast= */ 0.5f);
1056}
1057
1058std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_luma_colorfilter() {
1060}
1061
1062std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_overdraw_colorfilter() {
1063 // Black to red heat map gradation
1071 };
1072
1074}
1075
1076std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_compose_colorfilter(
1077 SkRandom* rand) {
1078 auto [outerCF, outerO] = create_random_colorfilter(rand);
1079 auto [innerCF, innerO] = create_random_colorfilter(rand);
1080
1081 // TODO: if outerCF is null, innerCF will be returned by Compose. We need a Precompile
1082 // list object that can encapsulate innerO if there are no combinations in outerO.
1083 return { SkColorFilters::Compose(std::move(outerCF), std::move(innerCF)),
1084 PrecompileColorFilters::Compose({ std::move(outerO) }, { std::move(innerO) }) };
1085}
1086
1087std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_gaussian_colorfilter() {
1089}
1090
1091std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_table_colorfilter() {
1092 static constexpr uint8_t kTable[256] = { 0 };
1093
1095}
1096
1097std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_workingformat_colorfilter(
1098 SkRandom* rand) {
1099 auto [childCF, childO] = create_random_colorfilter(rand);
1100
1101 if (!childCF) {
1102 return { nullptr, nullptr };
1103 }
1104
1105 SkASSERT(childCF && childO);
1106
1109 &random_xfer_function(rand),
1110 &random_gamut(rand),
1111 &unpremul);
1112
1114 { std::move(childO) });
1115
1116 return { std::move(cf), std::move(o) };
1117}
1118
1119std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_hsla_matrix_colorfilter() {
1123
1124 return { std::move(cf), std::move(o) };
1125}
1126
1127std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_colorfilter(
1128 SkRandom* rand,
1129 ColorFilterType type) {
1130
1131 switch (type) {
1133 return { nullptr, nullptr };
1134 case ColorFilterType::kBlendMode:
1135 return create_blendmode_colorfilter(rand);
1136 case ColorFilterType::kColorSpaceXform:
1137 return create_color_space_colorfilter(rand);
1138 case ColorFilterType::kCompose:
1139 return create_compose_colorfilter(rand);
1140 case ColorFilterType::kGaussian:
1141 return create_gaussian_colorfilter();
1143 return create_high_contrast_colorfilter();
1144 case ColorFilterType::kHSLAMatrix:
1145 return create_hsla_matrix_colorfilter();
1146 case ColorFilterType::kLerp:
1147 return create_lerp_colorfilter(rand);
1148 case ColorFilterType::kLighting:
1149 return create_lighting_colorfilter();
1150 case ColorFilterType::kLinearToSRGB:
1151 return create_linear_to_srgb_colorfilter();
1152 case ColorFilterType::kLuma:
1153 return create_luma_colorfilter();
1154 case ColorFilterType::kMatrix:
1155 return create_matrix_colorfilter();
1156 case ColorFilterType::kOverdraw:
1157 return create_overdraw_colorfilter();
1158 case ColorFilterType::kRuntime:
1159 return create_rt_colorfilter(rand);
1160 case ColorFilterType::kSRGBToLinear:
1161 return create_srgb_to_linear_colorfilter();
1162 case ColorFilterType::kTable:
1163 return create_table_colorfilter();
1164 case ColorFilterType::kWorkingFormat:
1165 return create_workingformat_colorfilter(rand);
1166 }
1167
1169}
1170
1171std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(
1172 SkRandom* rand) {
1173 return create_colorfilter(rand, random_colorfiltertype(rand));
1174}
1175
1176//--------------------------------------------------------------------------------------------------
1177//--------------------------------------------------------------------------------------------------
1178std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> arithmetic_imagefilter(
1179 SkRandom* /* rand */) {
1180
1181 sk_sp<SkImageFilter> arithmeticIF = SkImageFilters::Arithmetic(/* k1= */ 0.5f,
1182 /* k2= */ 0.5f,
1183 /* k3= */ 0.5f,
1184 /* k4= */ 0.5f,
1185 /* enforcePMColor= */ false,
1186 /* background= */ nullptr,
1187 /* foreground= */ nullptr);
1189 /* background= */ nullptr,
1190 /* foreground= */ nullptr);
1191
1192 return { std::move(arithmeticIF), std::move(option) };
1193}
1194
1195std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> blendmode_imagefilter(
1196 SkRandom* rand) {
1197
1198 SkBlendMode bm = random_blend_mode(rand);
1200 /* background= */ nullptr,
1201 /* foreground= */ nullptr);
1203 bm,
1204 /* background= */ nullptr,
1205 /* foreground= */ nullptr);
1206
1207 return { std::move(blendIF), std::move(blendO) };
1208}
1209
1210std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> runtime_blender_imagefilter(
1211 SkRandom* rand) {
1212
1213 auto [blender, blenderO] = create_blender(rand, BlenderType::kRuntime);
1214 sk_sp<SkImageFilter> blenderIF = SkImageFilters::Blend(std::move(blender),
1215 /* background= */ nullptr,
1216 /* foreground= */ nullptr);
1218 /* background= */ nullptr,
1219 /* foreground= */ nullptr);
1220
1221 return { std::move(blenderIF), std::move(option) };
1222}
1223
1224std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> blur_imagefilter(
1225 SkRandom* rand) {
1226
1227 int option = rand->nextULessThan(3);
1228
1229 float sigma;
1230 switch (option) {
1231 case 0: sigma = 1.0f; break; // 1DBlur4
1232 case 1: sigma = 2.0f; break; // 1DBlur8
1233 case 2: [[fallthrough]];
1234 default: sigma = 5.0f; break; // 1DBlur16
1235 }
1236
1237 sk_sp<SkImageFilter> blurIF = SkImageFilters::Blur(sigma, sigma, /* input= */ nullptr);
1238 sk_sp<PrecompileImageFilter> blurO = PrecompileImageFilters::Blur(/* input= */ nullptr);
1239
1240 return { std::move(blurIF), std::move(blurO) };
1241}
1242
1243std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> displacement_imagefilter(
1244 Recorder* recorder,
1245 SkRandom* rand) {
1246
1250 /* checkSize= */ 4);
1251 checkerboard = SkImages::TextureFromImage(recorder, std::move(checkerboard), {false});
1253
1256
1257 sk_sp<SkImageFilter> displacementIF;
1258
1261 /* scale= */ 2.0f,
1262 /* displacement= */ std::move(imageIF),
1263 /* color= */ nullptr);
1265 PrecompileImageFilters::DisplacementMap(/* input= */ nullptr);
1266
1267 return { std::move(displacementIF), std::move(option) };
1268}
1269
1270std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> colorfilter_imagefilter(
1271 SkRandom* rand) {
1272
1273 auto [cf, o] = create_random_colorfilter(rand);
1274
1275 sk_sp<SkImageFilter> inputIF;
1277 if (rand->nextBool()) {
1278 // Exercise color filter collapsing in the factories
1279 auto [cf2, o2] = create_random_colorfilter(rand);
1280 inputIF = SkImageFilters::ColorFilter(std::move(cf2), /* input= */ nullptr);
1281 inputO = PrecompileImageFilters::ColorFilter(std::move(o2), /* input= */ nullptr);
1282 }
1283
1284 sk_sp<SkImageFilter> cfIF = SkImageFilters::ColorFilter(std::move(cf), std::move(inputIF));
1286 std::move(inputO));
1287
1288 return { std::move(cfIF), std::move(cfIFO) };
1289}
1290
1291std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> lighting_imagefilter(
1292 SkRandom* rand) {
1293 static constexpr SkPoint3 kLocation{10.0f, 2.0f, 30.0f};
1294 static constexpr SkPoint3 kTarget{0, 0, 0};
1295 static constexpr SkPoint3 kDirection{0, 1, 0};
1296
1297 sk_sp<SkImageFilter> lightingIF;
1298
1299 int option = rand->nextULessThan(6);
1300 switch (option) {
1301 case 0:
1302 lightingIF = SkImageFilters::DistantLitDiffuse(kDirection, SK_ColorRED,
1303 /* surfaceScale= */ 1.0f,
1304 /* kd= */ 0.5f,
1305 /* input= */ nullptr);
1306 break;
1307 case 1:
1308 lightingIF = SkImageFilters::PointLitDiffuse(kLocation, SK_ColorGREEN,
1309 /* surfaceScale= */ 1.0f,
1310 /* kd= */ 0.5f,
1311 /* input= */ nullptr);
1312 break;
1313 case 2:
1314 lightingIF = SkImageFilters::SpotLitDiffuse(kLocation, kTarget,
1315 /* falloffExponent= */ 2.0f,
1316 /* cutoffAngle= */ 30.0f,
1318 /* surfaceScale= */ 1.0f,
1319 /* kd= */ 0.5f,
1320 /* input= */ nullptr);
1321 break;
1322 case 3:
1323 lightingIF = SkImageFilters::DistantLitSpecular(kDirection, SK_ColorCYAN,
1324 /* surfaceScale= */ 1.0f,
1325 /* ks= */ 0.5f,
1326 /* shininess= */ 2.0f,
1327 /* input= */ nullptr);
1328 break;
1329 case 4:
1330 lightingIF = SkImageFilters::PointLitSpecular(kLocation, SK_ColorMAGENTA,
1331 /* surfaceScale= */ 1.0f,
1332 /* ks= */ 0.5f,
1333 /* shininess= */ 2.0f,
1334 /* input= */ nullptr);
1335 break;
1336 case 5:
1337 lightingIF = SkImageFilters::SpotLitSpecular(kLocation, kTarget,
1338 /* falloffExponent= */ 2.0f,
1339 /* cutoffAngle= */ 30.0f,
1341 /* surfaceScale= */ 1.0f,
1342 /* ks= */ 4.0f,
1343 /* shininess= */ 0.5f,
1344 /* input= */ nullptr);
1345 break;
1346 }
1347
1348 sk_sp<PrecompileImageFilter> lightingO = PrecompileImageFilters::Lighting(/* input= */ nullptr);
1349 return { std::move(lightingIF), std::move(lightingO) };
1350}
1351
1352std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> matrix_convolution_imagefilter(
1353 SkRandom* rand) {
1354
1355 int kernelSize = 1;
1356
1357 int option = rand->nextULessThan(3);
1358 switch (option) {
1359 case 0: kernelSize = 3; break;
1360 case 1: kernelSize = 7; break;
1361 case 2: kernelSize = 11; break;
1362 }
1363
1364 int center = (kernelSize * kernelSize - 1) / 2;
1365 std::vector<float> kernel(kernelSize * kernelSize, SkIntToScalar(1));
1366 kernel[center] = 2.0f - kernelSize * kernelSize;
1367
1368 sk_sp<SkImageFilter> matrixConvIF;
1369 matrixConvIF = SkImageFilters::MatrixConvolution({ kernelSize, kernelSize },
1370 /* kernel= */ kernel.data(),
1371 /* gain= */ 0.3f,
1372 /* bias= */ 100.0f,
1373 /* kernelOffset= */ { 1, 1 },
1375 /* convolveAlpha= */ false,
1376 /* input= */ nullptr);
1377 SkASSERT(matrixConvIF);
1379 /* input= */ nullptr);
1380
1381 return { std::move(matrixConvIF), std::move(convOption) };
1382}
1383
1384std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> morphology_imagefilter(
1385 SkRandom* rand) {
1386 static constexpr float kRadX = 2.0f, kRadY = 4.0f;
1387
1388 sk_sp<SkImageFilter> morphologyIF;
1389
1390 if (rand->nextBool()) {
1391 morphologyIF = SkImageFilters::Erode(kRadX, kRadY, /* input= */ nullptr);
1392 } else {
1393 morphologyIF = SkImageFilters::Dilate(kRadX, kRadY, /* input= */ nullptr);
1394 }
1395 SkASSERT(morphologyIF);
1397
1398 return { std::move(morphologyIF), std::move(option) };
1399}
1400
1401std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> create_image_filter(
1402 Recorder* recorder,
1403 SkRandom* rand,
1404 ImageFilterType type) {
1405
1406 switch (type) {
1408 return {};
1409 case ImageFilterType::kArithmetic:
1410 return arithmetic_imagefilter(rand);
1411 case ImageFilterType::kBlendMode:
1412 return blendmode_imagefilter(rand);
1413 case ImageFilterType::kRuntimeBlender:
1414 return runtime_blender_imagefilter(rand);
1416 return blur_imagefilter(rand);
1417 case ImageFilterType::kColorFilter:
1418 return colorfilter_imagefilter(rand);
1419 case ImageFilterType::kDisplacement:
1420 return displacement_imagefilter(recorder, rand);
1421 case ImageFilterType::kLighting:
1422 return lighting_imagefilter(rand);
1423 case ImageFilterType::kMatrixConvolution:
1424 return matrix_convolution_imagefilter(rand);
1425 case ImageFilterType::kMorphology:
1426 return morphology_imagefilter(rand);
1427 }
1428
1430}
1431
1432std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> create_random_image_filter(
1433 Recorder* recorder,
1434 SkRandom* rand) {
1435 return create_image_filter(recorder, rand, random_imagefiltertype(rand));
1436}
1437
1438std::pair<sk_sp<SkMaskFilter>, sk_sp<PrecompileMaskFilter>> create_blur_maskfilter(SkRandom* rand) {
1439 SkBlurStyle style;
1440 switch (rand->nextULessThan(4)) {
1441 case 0: style = kNormal_SkBlurStyle; break;
1442 case 1: style = kSolid_SkBlurStyle; break;
1443 case 2: style = kOuter_SkBlurStyle; break;
1444 case 3: [[fallthrough]];
1445 default: style = kInner_SkBlurStyle; break;
1446 }
1447
1448 float sigma = 1.0f;
1449 switch (rand->nextULessThan(2)) {
1450 case 0: sigma = 1.0f; break;
1451 case 1: sigma = 2.0f; break;
1452 case 2: [[fallthrough]];
1453 default: sigma = 5.0f; break;
1454 }
1455
1456 bool respectCTM = rand->nextBool();
1457
1458 return { SkMaskFilter::MakeBlur(style, sigma, respectCTM), PrecompileMaskFilters::Blur() };
1459}
1460
1461std::pair<sk_sp<SkMaskFilter>, sk_sp<PrecompileMaskFilter>> create_maskfilter(SkRandom* rand,
1463 switch (type) {
1464 case MaskFilterType::kNone: return {nullptr, nullptr};
1465 case MaskFilterType::kBlur: return create_blur_maskfilter(rand);
1466 }
1467
1469}
1470
1471//--------------------------------------------------------------------------------------------------
1472std::pair<SkPaint, PaintOptions> create_paint(SkRandom* rand,
1473 Recorder* recorder,
1474 ShaderType shaderType,
1475 BlenderType blenderType,
1476 ColorFilterType colorFilterType,
1477 MaskFilterType maskFilterType,
1478 ImageFilterType imageFilterType) {
1479 SkPaint paint;
1480 paint.setColor(random_color(rand, ColorConstraint::kOpaque));
1481
1482 PaintOptions paintOptions;
1483
1484 {
1485 auto [s, o] = create_shader(rand, recorder, shaderType);
1486 SkASSERT(!s == !o);
1487
1488 if (s) {
1489 paint.setShader(std::move(s));
1490 paintOptions.setShaders({o});
1491 }
1492 }
1493
1494 {
1495 auto [cf, o] = create_colorfilter(rand, colorFilterType);
1496 SkASSERT(!cf == !o);
1497
1498 if (cf) {
1499 paint.setColorFilter(std::move(cf));
1500 paintOptions.setColorFilters({o});
1501 }
1502 }
1503
1504 {
1505 auto [mf, o] = create_maskfilter(rand, maskFilterType);
1506 SkASSERT(!mf == !o);
1507
1508 if (mf) {
1509 paint.setMaskFilter(std::move(mf));
1510 paintOptions.setMaskFilters({o});
1511 }
1512 }
1513
1514 {
1515 auto [b, o] = create_blender(rand, blenderType);
1516 SkASSERT(!b == !o);
1517
1518 if (b) {
1519 paint.setBlender(std::move(b));
1520 paintOptions.setBlenders({o});
1521 }
1522 }
1523
1524 {
1525 auto [filter, o] = create_image_filter(recorder, rand, imageFilterType);
1526 SkASSERT(!filter == !o);
1527
1528 if (filter) {
1529 paint.setImageFilter(std::move(filter));
1530 paintOptions.setImageFilters({o});
1531 }
1532 }
1533
1534 if (rand->nextBool()) {
1535 paint.setDither(true);
1536 paintOptions.setDither(true);
1537 }
1538
1539 return { paint, paintOptions };
1540}
1541
1542SkPath make_path() {
1544 path.moveTo(0, 0);
1545 path.lineTo(8, 2);
1546 path.lineTo(16, 0);
1547 path.lineTo(14, 8);
1548 path.lineTo(16, 16);
1549 path.lineTo(8, 14);
1550 path.lineTo(0, 16);
1551 path.lineTo(2, 8);
1552 path.close();
1553 return path.detach();
1554}
1555
1556struct DrawData {
1557 SkPath fPath;
1558 sk_sp<SkTextBlob> fBlob;
1559 sk_sp<SkVertices> fVertsWithColors;
1560 sk_sp<SkVertices> fVertsWithOutColors;
1561};
1562
1563void simple_draws(SkCanvas* canvas, const SkPaint& paint) {
1564 // TODO: add some drawLine calls
1565 canvas->drawRect(SkRect::MakeWH(16, 16), paint);
1566 canvas->drawRRect(SkRRect::MakeOval({0, 0, 16, 16}), paint);
1567 canvas->drawRRect(SkRRect::MakeRectXY({0, 0, 16, 16}, 4, 4), paint);
1568
1569 if (!paint.getShader() &&
1570 !paint.getColorFilter() &&
1571 !paint.getImageFilter() &&
1572 paint.asBlendMode().has_value()) {
1573 // The SkPaint reconstructed inside the drawEdgeAAQuad call needs to match 'paint' for
1574 // the precompilation checks to work.
1576 /* clip= */ nullptr,
1578 paint.getColor4f(),
1579 paint.asBlendMode().value());
1580 }
1581}
1582
1583void non_simple_draws(SkCanvas* canvas, const SkPaint& paint, const DrawData& drawData) {
1584 // TODO: add strokeAndFill draws here as well as a stroked non-circular rrect draw
1585 canvas->drawPath(drawData.fPath, paint);
1586}
1587
1588void check_draw(skiatest::Reporter* reporter,
1589 Context* context,
1591 Recorder* recorder,
1592 const SkPaint& paint,
1593 DrawTypeFlags dt,
1594 ClipType clip, sk_sp<SkShader> clipShader,
1595 const DrawData& drawData) {
1596
1597 int before = context->priv().globalCache()->numGraphicsPipelines();
1598
1599#ifdef SK_DEBUG
1600 std::vector<skgpu::UniqueKey> beforeKeys;
1601
1602 UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &beforeKeys);
1603#endif
1604
1605 {
1606 // TODO: vary the colorType of the target surface too
1607 SkImageInfo ii = SkImageInfo::Make(16, 16,
1610
1611 sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, ii);
1612 SkCanvas* canvas = surf->getCanvas();
1613
1614 switch (clip) {
1615 case ClipType::kNone:
1616 break;
1617 case ClipType::kShader:
1618 SkASSERT(clipShader);
1619 canvas->clipShader(clipShader, SkClipOp::kIntersect);
1620 break;
1621 case ClipType::kShader_Diff:
1622 SkASSERT(clipShader);
1623 canvas->clipShader(clipShader, SkClipOp::kDifference);
1624 break;
1625 }
1626
1627 switch (dt) {
1629 simple_draws(canvas, paint);
1630 break;
1632 non_simple_draws(canvas, paint, drawData);
1633 break;
1635 simple_draws(canvas, paint);
1636 non_simple_draws(canvas, paint, drawData);
1637 break;
1639 canvas->drawTextBlob(drawData.fBlob, 0, 16, paint);
1640 break;
1642 canvas->drawVertices(drawData.fVertsWithColors, SkBlendMode::kDst, paint);
1643 canvas->drawVertices(drawData.fVertsWithOutColors, SkBlendMode::kDst, paint);
1644 break;
1645 default:
1646 SkASSERT(false);
1647 break;
1648 }
1649
1650 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
1651 context->insertRecording({ recording.get() });
1652 testContext->syncedSubmit(context);
1653 }
1654
1655 int after = context->priv().globalCache()->numGraphicsPipelines();
1656
1657 // Actually using the SkPaint with the specified type of draw shouldn't have caused
1658 // any additional compilation
1659 REPORTER_ASSERT(reporter, before == after, "before: %d after: %d", before, after);
1660#ifdef SK_DEBUG
1661 if (before != after) {
1662 const RendererProvider* rendererProvider = context->priv().rendererProvider();
1663 const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1664
1665 std::vector<skgpu::UniqueKey> afterKeys;
1666
1667 UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &afterKeys);
1668
1669 for (const skgpu::UniqueKey& afterKey : afterKeys) {
1670 if (std::find(beforeKeys.begin(), beforeKeys.end(), afterKey) == beforeKeys.end()) {
1671 GraphicsPipelineDesc originalPipelineDesc;
1672 RenderPassDesc originalRenderPassDesc;
1673 UniqueKeyUtils::ExtractKeyDescs(context, afterKey,
1674 &originalPipelineDesc,
1675 &originalRenderPassDesc);
1676
1677 SkDebugf("------- New key from draw:\n");
1678 afterKey.dump("original key:");
1679 UniqueKeyUtils::DumpDescs(rendererProvider, dict,
1680 originalPipelineDesc,
1681 originalRenderPassDesc);
1682 }
1683 }
1684 }
1685#endif // SK_DEBUG
1686}
1687
1688} // anonymous namespace
1689
1691 Context*,
1693 const KeyContext& precompileKeyContext,
1694 const DrawData&,
1695 ShaderType,
1696 BlenderType,
1697 ColorFilterType,
1699 ImageFilterType,
1700 ClipType);
1701
1702// This is intended to be a smoke test for the agreement between the two ways of creating a
1703// PaintParamsKey:
1704// via ExtractPaintData (i.e., from an SkPaint)
1705// and via the pre-compilation system
1706//
1707// TODO: keep this as a smoke test but add a fuzzer that reuses all the helpers
1708// TODO(b/306174708): enable in SkQP (if it's feasible)
1710 reporter,
1711 context,
1712 testContext,
1713 true,
1715 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1716
1719
1720 std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
1721
1722 auto dstTexInfo = context->priv().caps()->getDefaultSampledTextureInfo(
1727 // Use Budgeted::kYes to avoid instantiating the proxy immediately; this test doesn't need
1728 // a full resource.
1729 sk_sp<TextureProxy> fakeDstTexture = TextureProxy::Make(context->priv().caps(),
1730 context->priv().resourceProvider(),
1731 SkISize::Make(1, 1),
1732 dstTexInfo,
1733 "PaintParamsKeyTestFakeDstTexture",
1735 constexpr SkIPoint kFakeDstOffset = SkIPoint::Make(0, 0);
1736
1737 KeyContext precompileKeyContext(context->priv().caps(),
1738 dict,
1739 rtDict.get(),
1740 destColorInfo,
1741 fakeDstTexture,
1742 kFakeDstOffset);
1743
1745 const char text[] = "hambur";
1746
1747 constexpr int kNumVerts = 4;
1748 constexpr SkPoint kPositions[kNumVerts] { {0,0}, {0,16}, {16,16}, {16,0} };
1749 constexpr SkColor kColors[kNumVerts] = { SK_ColorBLUE, SK_ColorGREEN,
1751
1752 DrawData drawData = {
1753 make_path(),
1756 kPositions, kPositions, kColors),
1758 kPositions, kPositions, /* colors= */ nullptr),
1759 };
1760
1761 ShaderType shaders[] = {
1762 ShaderType::kBlend,
1763 ShaderType::kImage,
1764 ShaderType::kRadialGradient,
1765 ShaderType::kSolidColor,
1766#if EXPANDED_SET
1768 ShaderType::kColorFilter,
1769 ShaderType::kCoordClamp,
1770 ShaderType::kConicalGradient,
1772 ShaderType::kLinearGradient,
1773 ShaderType::kLocalMatrix,
1774 ShaderType::kPerlinNoise,
1775 ShaderType::kPicture,
1776 ShaderType::kRuntime,
1777 ShaderType::kSweepGradient,
1778 ShaderType::kWorkingColorSpace,
1779#endif
1780 };
1781
1782 BlenderType blenders[] = {
1783 BlenderType::kPorterDuff,
1784 BlenderType::kShaderBased,
1785 BlenderType::kRuntime,
1786#if EXPANDED_SET
1788 BlenderType::kArithmetic,
1789#endif
1790 };
1791
1792 ColorFilterType colorFilters[] = {
1794 ColorFilterType::kBlendMode,
1795 ColorFilterType::kMatrix,
1796#if EXPANDED_SET
1797 ColorFilterType::kColorSpaceXform,
1798 ColorFilterType::kCompose,
1799 ColorFilterType::kGaussian,
1801 ColorFilterType::kHSLAMatrix,
1802 ColorFilterType::kLerp,
1803 ColorFilterType::kLighting,
1804 ColorFilterType::kLinearToSRGB,
1805 ColorFilterType::kLuma,
1806 ColorFilterType::kOverdraw,
1807 ColorFilterType::kRuntime,
1808 ColorFilterType::kSRGBToLinear,
1809 ColorFilterType::kTable,
1810 ColorFilterType::kWorkingFormat,
1811#endif
1812 };
1813
1814 MaskFilterType maskFilters[] = {
1816#if EXPANDED_SET
1818#endif
1819 };
1820
1821 ImageFilterType imageFilters[] = {
1823#if EXPANDED_SET
1824 ImageFilterType::kArithmetic,
1825 ImageFilterType::kBlendMode,
1826 ImageFilterType::kRuntimeBlender,
1828 ImageFilterType::kColorFilter,
1829 ImageFilterType::kDisplacement,
1830 ImageFilterType::kLighting,
1831 ImageFilterType::kMatrixConvolution,
1832 ImageFilterType::kMorphology,
1833#endif
1834 };
1835
1836 ClipType clips[] = {
1838#if EXPANDED_SET
1839 ClipType::kShader, // w/ a SkClipOp::kIntersect
1840 ClipType::kShader_Diff, // w/ a SkClipOp::kDifference
1841#endif
1842 };
1843
1844#if EXPANDED_SET
1845 size_t kExpected = std::size(shaders) * std::size(blenders) * std::size(colorFilters) *
1846 std::size(maskFilters) * std::size(imageFilters) * std::size(clips);
1847 int current = 0;
1848#endif
1849
1850 for (auto shader : shaders) {
1851 for (auto blender : blenders) {
1852 for (auto cf : colorFilters) {
1853 for (auto mf : maskFilters) {
1854 for (auto imageFilter : imageFilters) {
1855 for (auto clip : clips) {
1856#if EXPANDED_SET
1857 SkDebugf("%d/%zu\n", current, kExpected);
1858 ++current;
1859#endif
1860
1861 run_test(reporter, context, testContext, precompileKeyContext,
1862 drawData, shader, blender, cf, mf, imageFilter, clip);
1863 }
1864 }
1865 }
1866 }
1867 }
1868 }
1869
1870#if EXPANDED_SET
1871 SkASSERT(current == (int) kExpected);
1872#endif
1873}
1874
1876 Context* context,
1878 const KeyContext& precompileKeyContext,
1879 const DrawData& drawData,
1880 ShaderType s,
1881 BlenderType bm,
1882 ColorFilterType cf,
1883 MaskFilterType mf,
1884 ImageFilterType imageFilter,
1885 ClipType clip) {
1886 SkRandom rand;
1887
1888 std::unique_ptr<Recorder> recorder = context->makeRecorder();
1889
1890 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1891
1892 sk_sp<SkShader> clipShader;
1893 sk_sp<PrecompileShader> clipShaderOption;
1894
1895 if (clip == ClipType::kShader || clip == ClipType::kShader_Diff) {
1896 std::tie(clipShader, clipShaderOption) = create_clip_shader(&rand, recorder.get());
1897 SkASSERT(!clipShader == !clipShaderOption);
1898 }
1899
1901 PipelineDataGatherer paramsGatherer(Layout::kMetal);
1902 PipelineDataGatherer precompileGatherer(Layout::kMetal);
1903
1904 gNeedSKPPaintOption = false;
1905 auto [paint, paintOptions] = create_paint(&rand, recorder.get(), s, bm, cf, mf, imageFilter);
1906
1912
1913 // Note: 'withPrimitiveBlender' and 'primitiveBlender' are only used in ExtractPaintData
1914 // and PaintOptions::buildCombinations. Thus, as long as those two uses agree, it doesn't
1915 // matter if the actual draw uses a primitive blender (i.e., those variables are only used
1916 // in a local unit test independent of the follow-on Precompile/check_draw test)
1917 for (bool withPrimitiveBlender : { false, true }) {
1918
1919 sk_sp<SkBlender> primitiveBlender;
1920 if (withPrimitiveBlender) {
1921 if (dt != DrawTypeFlags::kDrawVertices) {
1922 // Only drawVertices calls need a primitive blender
1923 continue;
1924 }
1925
1926 primitiveBlender = SkBlender::Mode(SkBlendMode::kSrcOver);
1927 }
1928
1929 constexpr Coverage coverageOptions[3] = {
1930 Coverage::kNone, Coverage::kSingleChannel, Coverage::kLCD};
1931 Coverage coverage = coverageOptions[rand.nextULessThan(3)];
1932
1934 const SkBlenderBase* blender = as_BB(paint.getBlender());
1935 if (blender) {
1936 dstReadReq = GetDstReadRequirement(recorder->priv().caps(),
1937 blender->asBlendMode(),
1938 coverage);
1939 }
1940 bool needsDstSample = dstReadReq == DstReadRequirement::kTextureCopy ||
1941 dstReadReq == DstReadRequirement::kTextureSample;
1942 sk_sp<TextureProxy> curDst = needsDstSample ? precompileKeyContext.dstTexture()
1943 : nullptr;
1944
1945 // In the normal API this modification happens in SkDevice::clipShader()
1946 // All clipShaders get wrapped in a CTMShader
1947 sk_sp<SkShader> modifiedClipShader = clipShader
1948 ? as_SB(clipShader)->makeWithCTM(SkMatrix::I())
1949 : nullptr;
1950 if (clip == ClipType::kShader_Diff && modifiedClipShader) {
1951 // The CTMShader gets further wrapped in a ColorFilterShader for kDifference clips
1952 modifiedClipShader = modifiedClipShader->makeWithColorFilter(
1954 }
1955
1956 auto [paintID, uData, tData] =
1957 ExtractPaintData(recorder.get(),
1958 &paramsGatherer,
1959 &builder,
1961 {},
1963 primitiveBlender,
1964 std::move(modifiedClipShader),
1965 dstReadReq,
1966 /* skipColorXform= */ false),
1967 {},
1968 curDst,
1969 precompileKeyContext.dstOffset(),
1970 precompileKeyContext.dstColorInfo());
1971
1972 paintOptions.priv().setClipShaders({ clipShaderOption });
1973
1974 std::vector<UniquePaintParamsID> precompileIDs;
1975 paintOptions.priv().buildCombinations(precompileKeyContext,
1976 &precompileGatherer,
1978 withPrimitiveBlender,
1979 coverage,
1980 [&precompileIDs](UniquePaintParamsID id,
1982 bool /* withPrimitiveBlender */,
1983 Coverage) {
1984 precompileIDs.push_back(id);
1985 });
1986
1987 // Although we've gathered both sets of uniforms (i.e., from the paint
1988 // params and the precompilation paths) we can't compare the two since the
1989 // precompilation path may have generated multiple sets
1990 // and the last one created may not be the one that matches the paint
1991 // params' set. Additionally, for runtime effects we just skip gathering
1992 // the uniforms in the precompilation path.
1993
1994 // The specific key generated by ExtractPaintData should be one of the
1995 // combinations generated by the combination system.
1996 auto result = std::find(precompileIDs.begin(), precompileIDs.end(), paintID);
1997
1998 if (result == precompileIDs.end()) {
1999 SkDebugf("Failure on case: %s %s %s %s %s %s\n",
2000 to_str(s), to_str(bm), to_str(cf), to_str(clip), to_str(mf),
2001 to_str(imageFilter));
2002 }
2003
2004#ifdef SK_DEBUG
2005 if (result == precompileIDs.end()) {
2006 SkDebugf("From paint: ");
2007 dict->dump(paintID);
2008
2009 SkDebugf("From combination builder [%d]:", static_cast<int>(precompileIDs.size()));
2010 for (auto iter : precompileIDs) {
2011 dict->dump(iter);
2012 }
2013 }
2014#endif
2015
2016 REPORTER_ASSERT(reporter, result != precompileIDs.end());
2017
2018 {
2019 context->priv().globalCache()->resetGraphicsPipelines();
2020
2021 int before = context->priv().globalCache()->numGraphicsPipelines();
2022 Precompile(context, paintOptions, dt);
2023 if (gNeedSKPPaintOption) {
2024 // The skp draws a rect w/ a default SkPaint
2025 PaintOptions skpPaintOptions;
2026 Precompile(context, skpPaintOptions, DrawTypeFlags::kSimpleShape);
2027 }
2028 int after = context->priv().globalCache()->numGraphicsPipelines();
2029
2030 REPORTER_ASSERT(reporter, before == 0);
2031 REPORTER_ASSERT(reporter, after > before);
2032
2033 check_draw(reporter,
2034 context,
2035 testContext,
2036 recorder.get(),
2037 paint,
2038 dt,
2039 clip,
2040 clipShader,
2041 drawData);
2042 }
2043 }
2044 }
2045}
2046
2047#endif // SK_GRAPHITE
SkPath fPath
static void run_test(GrDirectContext *dContext, skiatest::Reporter *reporter, BulkRectTest test)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
reporter
Definition: FontMgrTest.cpp:39
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ImageWrapTextureMipmapsTest, reporter, context, testContext, true, CtsEnforcement::kNextRelease)
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)
Definition: SkBlenderBase.h:69
SkBlurStyle
Definition: SkBlurTypes.h:11
@ kOuter_SkBlurStyle
nothing inside, fuzzy outside
Definition: SkBlurTypes.h:14
@ kSolid_SkBlurStyle
solid inside, fuzzy outside
Definition: SkBlurTypes.h:13
@ kInner_SkBlurStyle
fuzzy inside, nothing outside
Definition: SkBlurTypes.h:15
@ kNormal_SkBlurStyle
fuzzy inside and outside
Definition: SkBlurTypes.h:12
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
constexpr SkColor SK_ColorMAGENTA
Definition: SkColor.h:147
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
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
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:3892
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{})
#define SkIntToScalar(x)
Definition: SkScalar.h:57
SkShaderBase * as_SB(SkShader *shader)
Definition: SkShaderBase.h:412
SkTileMode
Definition: SkTileMode.h:13
static constexpr int kSkTileModeCount
Definition: SkTileMode.h:39
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static SkScalar center(float pos0, float pos1)
int find(T *array, int N, T item)
static sk_sp< SkImage > make_image(SkCanvas *destCanvas)
Definition: bitmaprect.cpp:31
GLenum type
virtual std::optional< SkBlendMode > asBlendMode() const
Definition: SkBlenderBase.h:45
static sk_sp< SkBlender > Mode(SkBlendMode mode)
static sk_sp< SkBlender > Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul)
Definition: SkBlenders.cpp:20
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void experimental_DrawEdgeAAQuad(const SkRect &rect, const SkPoint clip[4], QuadAAFlags aaFlags, const SkColor4f &color, SkBlendMode mode)
Definition: SkCanvas.cpp:1845
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:1705
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void clipShader(sk_sp< SkShader >, SkClipOp=SkClipOp::kIntersect)
Definition: SkCanvas.cpp:1488
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:1720
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
@ 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)
Definition: SkColorFilter.h:92
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
Definition: SkFont.h:35
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 > PointLitDiffuse(const SkPoint3 &location, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > MatrixConvolution(const SkISize &kernelSize, const SkScalar kernel[], SkScalar gain, SkScalar bias, const SkIPoint &kernelOffset, SkTileMode tileMode, bool convolveAlpha, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > ColorFilter(sk_sp< SkColorFilter > cf, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Erode(SkScalar radiusX, SkScalar radiusY, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > DistantLitSpecular(const SkPoint3 &direction, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > DistantLitDiffuse(const SkPoint3 &direction, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Arithmetic(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, bool enforcePMColor, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > DisplacementMap(SkColorChannel xChannelSelector, SkColorChannel yChannelSelector, SkScalar scale, sk_sp< SkImageFilter > displacement, sk_sp< SkImageFilter > color, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Image(sk_sp< SkImage > image, const SkRect &srcRect, const SkRect &dstRect, const SkSamplingOptions &sampling)
static sk_sp< SkImageFilter > Blend(SkBlendMode mode, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground=nullptr, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Dilate(SkScalar radiusX, SkScalar radiusY, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > PointLitSpecular(const SkPoint3 &location, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > SpotLitDiffuse(const SkPoint3 &location, const SkPoint3 &target, SkScalar falloffExponent, SkScalar cutoffAngle, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > SpotLitSpecular(const SkPoint3 &location, const SkPoint3 &target, SkScalar falloffExponent, SkScalar cutoffAngle, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkMaskFilter > MakeBlur(SkBlurStyle style, SkScalar sigma, bool respectCTM=true)
SkMatrix & setTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:254
SkMatrix & setIdentity()
Definition: SkMatrix.h:626
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
static sk_sp< SkColorFilter > MakeWithSkColors(const SkColor[kNumColors])
static constexpr int kNumColors
Definition: SkPath.h:59
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
sk_sp< SkShader > makeShader(sk_sp< const SkData > uniforms, sk_sp< SkShader > children[], size_t childCount, const SkMatrix *localMatrix=nullptr) const
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 &)
static Result MakeForShader(SkString sksl, const Options &)
sk_sp< SkColorFilter > makeColorFilter(sk_sp< const SkData > uniforms) const
sk_sp< SkShader > makeWithCTM(const SkMatrix &) const
sk_sp< SkShader > makeWithColorFilter(sk_sp< SkColorFilter >) const
Definition: SkShader.cpp:43
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
static sk_sp< SkTextBlob > MakeFromText(const void *text, size_t byteLength, const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
Definition: SkTextBlob.cpp:788
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
Definition: SkVertices.cpp:200
@ kTriangleFan_VertexMode
Definition: SkVertices.h:33
SkIPoint dstOffset() const
Definition: KeyContext.h:72
sk_sp< TextureProxy > dstTexture() const
Definition: KeyContext.h:70
const SkColorInfo & dstColorInfo() const
Definition: KeyContext.h:67
void setClipShaders(SkSpan< const sk_sp< PrecompileShader > > clipShaders)
void buildCombinations(const KeyContext &keyContext, PipelineDataGatherer *gatherer, DrawTypeFlags drawTypes, bool withPrimitiveBlender, Coverage coverage, const ProcessCombination &processCombination) const
void setColorFilters(SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
void setDither(bool dither)
Definition: PaintOptions.h:138
void setShaders(SkSpan< const sk_sp< PrecompileShader > > shaders)
void setMaskFilters(SkSpan< const sk_sp< PrecompileMaskFilter > > maskFilters)
void setImageFilters(SkSpan< const sk_sp< PrecompileImageFilter > > imageFilters)
void setBlenders(SkSpan< const sk_sp< PrecompileBlender > > blenders)
std::unique_ptr< Recording > snap()
Definition: Recorder.cpp:159
void syncedSubmit(skgpu::graphite::Context *)
const Paint & paint
Definition: color_source.cc:38
static const skcms_Matrix3x3 gGamuts[]
Definition: colorspace.cpp:27
DlColor color
@ kMetal
Definition: embedder.h:85
static bool b
struct MyStruct s
FlutterSemanticsFlag flags
static const FlSetting kHighContrast
GAsyncResult * result
constexpr char kText[]
Definition: glyph_pos.cpp:28
std::u16string text
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)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
static constexpr skcms_Matrix3x3 kSRGB
Definition: SkColorSpace.h:67
static constexpr skcms_Matrix3x3 kAdobeRGB
Definition: SkColorSpace.h:77
static constexpr skcms_Matrix3x3 kXYZ
Definition: SkColorSpace.h:99
static constexpr skcms_Matrix3x3 kRec2020
Definition: SkColorSpace.h:93
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kRec2020
Definition: SkColorSpace.h:54
static constexpr skcms_TransferFunction k2Dot2
Definition: SkColorSpace.h:48
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
static constexpr skcms_TransferFunction kHLG
Definition: SkColorSpace.h:60
static constexpr skcms_TransferFunction kPQ
Definition: SkColorSpace.h:57
static constexpr skcms_TransferFunction kLinear
Definition: SkColorSpace.h:51
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
PODArray< SkColor > colors
Definition: SkRecords.h:276
SK_API sk_sp< SkShader > Blend(SkBlendMode mode, sk_sp< SkShader > dst, sk_sp< SkShader > src)
SK_API sk_sp< SkShader > Color(SkColor)
SK_API sk_sp< SkShader > MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
SK_API sk_sp< SkShader > CoordClamp(sk_sp< SkShader >, const SkRect &subset)
SK_API sk_sp< SkShader > RawImage(sk_sp< SkImage > image, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &options, const SkMatrix *localMatrix=nullptr)
SK_API sk_sp< SkShader > Image(sk_sp< SkImage > image, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &options, const SkMatrix *localMatrix=nullptr)
SK_API sk_sp< SkShader > MakeFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
SK_API sk_sp< SkShader > Empty()
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()
sk_sp< SkImage > create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize)
Definition: ToolUtils.cpp:168
void FetchUniqueKeys(GlobalCache *globalCache, std::vector< UniqueKey > *keys)
bool ExtractKeyDescs(Context *context, const UniqueKey &origKey, GraphicsPipelineDesc *pipelineDesc, RenderPassDesc *renderPassDesc)
Definition: bitmap.py:1
const DlColor kColors[]
constexpr std::array< std::array< float, 2 >, 2 > kRect
@ kNone
Definition: layer.h:53
@ kSRGB
Definition: image.h:17
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
CanvasImage Image
Definition: dart_ui.cc:55
MaskFilterType
Definition: paint.cc:59
@ kBlur
Definition: paint.cc:59
font
Font Metadata and Metrics.
dst
Definition: cp.py:12
SK_API sk_sp< PrecompileBlender > Arithmetic()
sk_sp< PrecompileColorFilter > WithWorkingFormat(SkSpan< const sk_sp< PrecompileColorFilter > > childOptions)
sk_sp< PrecompileColorFilter > ColorSpaceXform()
SK_API sk_sp< PrecompileColorFilter > HSLAMatrix()
SK_API sk_sp< PrecompileColorFilter > Matrix()
SK_API sk_sp< PrecompileColorFilter > Overdraw()
SK_API sk_sp< PrecompileColorFilter > Lighting()
SK_API sk_sp< PrecompileColorFilter > Luma()
SK_API sk_sp< PrecompileColorFilter > Compose(SkSpan< const sk_sp< PrecompileColorFilter > > outer, SkSpan< const sk_sp< PrecompileColorFilter > > inner)
SK_API sk_sp< PrecompileColorFilter > HighContrast()
SK_API sk_sp< PrecompileColorFilter > SRGBToLinearGamma()
SK_API sk_sp< PrecompileColorFilter > LinearToSRGBGamma()
SK_API sk_sp< PrecompileColorFilter > Table()
SK_API sk_sp< PrecompileColorFilter > Lerp(SkSpan< const sk_sp< PrecompileColorFilter > > dstOptions, SkSpan< const sk_sp< PrecompileColorFilter > > srcOptions)
SK_API sk_sp< PrecompileImageFilter > Blur(sk_sp< PrecompileImageFilter > input)
SK_API sk_sp< PrecompileImageFilter > MatrixConvolution(sk_sp< PrecompileImageFilter > input)
SK_API sk_sp< PrecompileImageFilter > DisplacementMap(sk_sp< PrecompileImageFilter > input)
SK_API sk_sp< PrecompileImageFilter > Morphology(sk_sp< PrecompileImageFilter > input)
SK_API sk_sp< PrecompileShader > ColorFilter(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
SK_API sk_sp< PrecompileShader > LinearGradient()
SK_API sk_sp< PrecompileShader > RadialGradient()
SK_API sk_sp< PrecompileShader > Picture()
SK_API sk_sp< PrecompileShader > SweepGradient()
SK_API sk_sp< PrecompileShader > TwoPointConicalGradient()
static std::string to_str(const SharedContext *ctx, const GraphicsPipelineDesc &gpDesc, const RenderPassDesc &rpDesc)
sk_sp< PrecompileBlender > MakePrecompileBlender(sk_sp< SkRuntimeEffect > effect, SkSpan< const PrecompileChildOptions > childOptions)
sk_sp< PrecompileShader > MakePrecompileShader(sk_sp< SkRuntimeEffect > effect, SkSpan< const PrecompileChildOptions > childOptions)
DstReadRequirement GetDstReadRequirement(const Caps *caps, std::optional< SkBlendMode > blendMode, Coverage coverage)
void Precompile(Context *context, const PaintOptions &paintOptions, DrawTypeFlags drawTypes=kMostCommon)
DstReadRequirement
Definition: Caps.h:64
sk_sp< PrecompileColorFilter > MakePrecompileColorFilter(sk_sp< SkRuntimeEffect > effect, SkSpan< const PrecompileChildOptions > childOptions)
std::tuple< UniquePaintParamsID, const UniformDataBlock *, const TextureDataBlock * > ExtractPaintData(Recorder *recorder, PipelineDataGatherer *gatherer, PaintParamsKeyBuilder *builder, const Layout layout, const SkM44 &local2Dev, const PaintParams &p, const Geometry &geometry, sk_sp< TextureProxy > dstTexture, SkIPoint dstOffset, const SkColorInfo &targetColorInfo)
static constexpr SkPoint kPts[kPtsCount]
Definition: emptypath.cpp:123
SkSamplingOptions(SkFilterMode::kLinear))
static SkPath make_path()
#define M(PROC, DITHER)
static sk_sp< SkColorFilter > Make(const SkHighContrastConfig &config)
static constexpr SkIPoint Make(int32_t x, int32_t y)
Definition: SkPoint_impl.h:38
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< SkImage > make_picture(const SkImageInfo &info, GrRecordingContext *, void(*draw)(SkCanvas *))
Definition: image.cpp:248
static void checkerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)