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
12 #include "include/core/SkBitmap.h"
13 #include "include/core/SkBlurTypes.h"
14 #include "include/core/SkCanvas.h"
15 #include "include/core/SkM44.h"
16 #include "include/core/SkMaskFilter.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPathBuilder.h"
19 #include "include/core/SkPicture.h"
20 #include "include/core/SkPictureRecorder.h"
21 #include "include/core/SkRRect.h"
22 #include "include/core/SkShader.h"
23 #include "include/core/SkTextBlob.h"
24 #include "include/core/SkVertices.h"
25 #include "include/core/SkYUVAPixmaps.h"
26 #include "include/effects/SkBlenders.h"
27 #include "include/effects/SkColorMatrix.h"
28 #include "include/effects/SkGradientShader.h"
29 #include "include/effects/SkHighContrastFilter.h"
30 #include "include/effects/SkImageFilters.h"
31 #include "include/effects/SkLumaColorFilter.h"
32 #include "include/effects/SkOverdrawColorFilter.h"
33 #include "include/effects/SkPerlinNoiseShader.h"
34 #include "include/effects/SkRuntimeEffect.h"
35 #include "include/gpu/graphite/Image.h"
36 #include "include/gpu/graphite/PrecompileContext.h"
37 #include "include/gpu/graphite/Recorder.h"
38 #include "include/gpu/graphite/Surface.h"
39 #include "include/gpu/graphite/precompile/Precompile.h"
40 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
41 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
42 #include "include/gpu/graphite/precompile/PrecompileImageFilter.h"
43 #include "include/gpu/graphite/precompile/PrecompileMaskFilter.h"
44 #include "include/gpu/graphite/precompile/PrecompileRuntimeEffect.h"
45 #include "include/gpu/graphite/precompile/PrecompileShader.h"
46 #include "src/base/SkRandom.h"
47 #include "src/core/SkBlenderBase.h"
48 #include "src/core/SkColorFilterPriv.h"
49 #include "src/core/SkRuntimeEffectPriv.h"
50 #include "src/gpu/graphite/ContextPriv.h"
51 #include "src/gpu/graphite/ContextUtils.h"
52 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
53 #include "src/gpu/graphite/KeyContext.h"
54 #include "src/gpu/graphite/KeyHelpers.h"
55 #include "src/gpu/graphite/PaintParams.h"
56 #include "src/gpu/graphite/PipelineData.h"
57 #include "src/gpu/graphite/PrecompileContextPriv.h"
58 #include "src/gpu/graphite/RecorderPriv.h"
59 #include "src/gpu/graphite/RenderPassDesc.h"
60 #include "src/gpu/graphite/Renderer.h"
61 #include "src/gpu/graphite/ResourceProvider.h"
62 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
63 #include "src/gpu/graphite/ShaderCodeDictionary.h"
64 #include "src/gpu/graphite/UniquePaintParamsID.h"
65 #include "src/gpu/graphite/geom/Geometry.h"
66 #include "src/gpu/graphite/precompile/PaintOptionsPriv.h"
67 #include "src/gpu/graphite/precompile/PrecompileColorFiltersPriv.h"
68 #include "src/gpu/graphite/precompile/PrecompileShadersPriv.h"
69 #include "src/shaders/SkImageShader.h"
70 #include "tools/ToolUtils.h"
71 #include "tools/fonts/FontToolUtils.h"
72 #include "tools/graphite/GraphiteTestContext.h"
73 #include "tools/graphite/UniqueKeyUtils.h"
74 #include "tools/graphite/precompile/PrecompileEffectFactories.h"
75
76 // Set this to 1 for more expansive (aka far slower) local testing
77 #define EXPANDED_SET 0
78
79 // This flag is set to true if during the PaintOption creation an SkPictureShader is created.
80 // The SkPictureShader will need an additional program in order to draw the contents of its
81 // SkPicture.
82 bool gNeedSKPPaintOption = false;
83
84 constexpr uint32_t kDefaultSeed = 0;
85
86 using namespace skgpu::graphite;
87 using namespace skiatest::graphite;
88
89 namespace {
90
91 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom*, Recorder*);
92 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom*);
93 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(SkRandom*);
94
95 [[maybe_unused]] std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>>
96 create_random_image_filter(Recorder*, SkRandom*);
97
98 //--------------------------------------------------------------------------------------------------
99 //--------------------------------------------------------------------------------------------------
100 // M(Empty)
101 #define SK_ALL_TEST_SHADERS(M) \
102 M(Blend) \
103 M(ColorFilter) \
104 M(CoordClamp) \
105 M(ConicalGradient) \
106 M(Image) \
107 M(LinearGradient) \
108 M(LocalMatrix) \
109 M(None) \
110 M(PerlinNoise) \
111 M(Picture) \
112 M(RadialGradient) \
113 M(Runtime) \
114 M(SolidColor) \
115 M(SweepGradient) \
116 M(YUVImage) \
117 M(WorkingColorSpace)
118
119 enum class ShaderType {
120 #define M(type) k##type,
121 SK_ALL_TEST_SHADERS(M)
122 #undef M
123
124 kLast = kWorkingColorSpace
125 };
126
127 static constexpr int kShaderTypeCount = static_cast<int>(ShaderType::kLast) + 1;
128
to_str(ShaderType s)129 const char* to_str(ShaderType s) {
130 switch (s) {
131 #define M(type) case ShaderType::k##type : return "ShaderType::k" #type;
132 SK_ALL_TEST_SHADERS(M)
133 #undef M
134 }
135
136 SkUNREACHABLE;
137 }
138
139 //--------------------------------------------------------------------------------------------------
140 //--------------------------------------------------------------------------------------------------
141 #define SK_ALL_TEST_MASKFILTERS(M) \
142 M(None) \
143 M(Blur)
144
145 enum class MaskFilterType {
146 #define M(type) k##type,
147 SK_ALL_TEST_MASKFILTERS(M)
148 #undef M
149
150 kLast = kBlur
151 };
152
153 static constexpr int kMaskFilterTypeCount = static_cast<int>(MaskFilterType::kLast) + 1;
154
to_str(MaskFilterType mf)155 const char* to_str(MaskFilterType mf) {
156 switch (mf) {
157 #define M(type) case MaskFilterType::k##type : return "MaskFilterType::k" #type;
158 SK_ALL_TEST_MASKFILTERS(M)
159 #undef M
160 }
161
162 SkUNREACHABLE;
163 }
164
165 //--------------------------------------------------------------------------------------------------
166 //--------------------------------------------------------------------------------------------------
167 #define SK_ALL_TEST_BLENDERS(M) \
168 M(None) \
169 M(PorterDuff) \
170 M(ShaderBased) \
171 M(Arithmetic) \
172 M(Runtime)
173
174 // TODO: do we need to add a separable category and/or a category for dstRead requiring blends?
175 enum class BlenderType {
176 #define M(type) k##type,
177 SK_ALL_TEST_BLENDERS(M)
178 #undef M
179
180 kLast = kRuntime
181 };
182
183 static constexpr int kBlenderTypeCount = static_cast<int>(BlenderType::kLast) + 1;
184
to_str(BlenderType b)185 const char* to_str(BlenderType b) {
186 switch (b) {
187 #define M(type) case BlenderType::k##type : return "BlenderType::k" #type;
188 SK_ALL_TEST_BLENDERS(M)
189 #undef M
190 }
191
192 SkUNREACHABLE;
193 }
194
195 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_blender(SkRandom*, BlenderType);
196
197 //--------------------------------------------------------------------------------------------------
198 //--------------------------------------------------------------------------------------------------
199 #define SK_ALL_TEST_COLORFILTERS(M) \
200 M(None) \
201 M(BlendMode) \
202 M(ColorSpaceXform) \
203 M(Compose) \
204 M(Gaussian) \
205 M(HighContrast) \
206 M(HSLAMatrix) \
207 M(Lerp) \
208 M(Lighting) \
209 M(LinearToSRGB) \
210 M(Luma) \
211 M(Matrix) \
212 M(Overdraw) \
213 M(Runtime) \
214 M(SRGBToLinear) \
215 M(Table) \
216 M(WorkingFormat)
217
218 enum class ColorFilterType {
219 #define M(type) k##type,
220 SK_ALL_TEST_COLORFILTERS(M)
221 #undef M
222
223 kLast = kWorkingFormat
224 };
225
226 static constexpr int kColorFilterTypeCount = static_cast<int>(ColorFilterType::kLast) + 1;
227
to_str(ColorFilterType cf)228 const char* to_str(ColorFilterType cf) {
229 switch (cf) {
230 #define M(type) case ColorFilterType::k##type : return "ColorFilterType::k" #type;
231 SK_ALL_TEST_COLORFILTERS(M)
232 #undef M
233 }
234
235 SkUNREACHABLE;
236 }
237
238 //--------------------------------------------------------------------------------------------------
239 //--------------------------------------------------------------------------------------------------
240 #define SK_ALL_TEST_CLIPS(M) \
241 M(None) \
242 M(Shader) \
243 M(Shader_Diff)
244
245 enum class ClipType {
246 #define M(type) k##type,
247 SK_ALL_TEST_CLIPS(M)
248 #undef M
249
250 kLast = kShader_Diff
251 };
252
253 static constexpr int kClipTypeCount = static_cast<int>(ClipType::kLast) + 1;
254
to_str(ClipType c)255 const char* to_str(ClipType c) {
256 switch (c) {
257 #define M(type) case ClipType::k##type : return "ClipType::k" #type;
258 SK_ALL_TEST_CLIPS(M)
259 #undef M
260 }
261
262 SkUNREACHABLE;
263 }
264
265 //--------------------------------------------------------------------------------------------------
266 //--------------------------------------------------------------------------------------------------
267 #define SK_ALL_TEST_IMAGE_FILTERS(M) \
268 M(None) \
269 M(Arithmetic) \
270 M(BlendMode) \
271 M(RuntimeBlender) \
272 M(Blur) \
273 M(ColorFilter) \
274 M(Displacement) \
275 M(Lighting) \
276 M(MatrixConvolution) \
277 M(Morphology)
278
279 enum class ImageFilterType {
280 #define M(type) k##type,
281 SK_ALL_TEST_IMAGE_FILTERS(M)
282 #undef M
283 kLast = kMorphology
284 };
285
286 static constexpr int kImageFilterTypeCount = static_cast<int>(ImageFilterType::kLast) + 1;
287
to_str(ImageFilterType c)288 const char* to_str(ImageFilterType c) {
289 switch (c) {
290 #define M(type) case ImageFilterType::k##type : return "ImageFilterType::k" #type;
291 SK_ALL_TEST_IMAGE_FILTERS(M)
292 #undef M
293 }
294 SkUNREACHABLE;
295 }
296
to_str(DrawTypeFlags dt)297 const char* to_str(DrawTypeFlags dt) {
298 SkASSERT(SkPopCount(static_cast<uint32_t>(dt)) == 1);
299
300 switch (dt) {
301 case DrawTypeFlags::kBitmapText_Mask: return "DrawTypeFlags::kBitmapText_Mask";
302 case DrawTypeFlags::kBitmapText_LCD: return "DrawTypeFlags::kBitmapText_LCD";
303 case DrawTypeFlags::kBitmapText_Color: return "DrawTypeFlags::kBitmapText_Color";
304 case DrawTypeFlags::kSDFText: return "DrawTypeFlags::kSDFText";
305 case DrawTypeFlags::kSDFText_LCD: return "DrawTypeFlags::kSDFText_LCD";
306 case DrawTypeFlags::kDrawVertices: return "DrawTypeFlags::kDrawVertices";
307 case DrawTypeFlags::kCircularArc: return "DrawTypeFlags::kCircularArc";
308 case DrawTypeFlags::kSimpleShape: return "DrawTypeFlags::kSimpleShape";
309 case DrawTypeFlags::kNonSimpleShape: return "DrawTypeFlags::kNonSimpleShape";
310 default: SkASSERT(0); return "DrawTypeFlags::kNone";
311 }
312
313 SkUNREACHABLE;
314 }
315
log_run(const char * label,uint32_t seed,ShaderType s,BlenderType bm,ColorFilterType cf,MaskFilterType mf,ImageFilterType imageFilter,ClipType clip,DrawTypeFlags drawTypeFlags)316 void log_run(const char* label,
317 uint32_t seed,
318 ShaderType s,
319 BlenderType bm,
320 ColorFilterType cf,
321 MaskFilterType mf,
322 ImageFilterType imageFilter,
323 ClipType clip,
324 DrawTypeFlags drawTypeFlags) {
325 SkDebugf("%s:\n"
326 "//------------------------\n"
327 "uint32_t seed = %u;\n"
328 "ShaderType shaderType = %s;\n"
329 "BlenderType blenderType = %s;\n"
330 "ColorFilterType colorFilterType = %s;\n"
331 "MaskFilterType maskFilterType = %s;\n"
332 "ImageFilterType imageFilterType = %s;\n"
333 "ClipType clipType = %s;\n"
334 "DrawTypeFlags drawTypeFlags = %s;\n"
335 "//-----------------------\n",
336 label, seed,
337 to_str(s), to_str(bm), to_str(cf), to_str(mf), to_str(imageFilter), to_str(clip),
338 to_str(drawTypeFlags));
339 }
340
341 //--------------------------------------------------------------------------------------------------
342 //--------------------------------------------------------------------------------------------------
343 static constexpr skcms_TransferFunction gTransferFunctions[] = {
344 SkNamedTransferFn::kSRGB,
345 SkNamedTransferFn::k2Dot2,
346 SkNamedTransferFn::kLinear,
347 SkNamedTransferFn::kRec2020,
348 SkNamedTransferFn::kPQ,
349 SkNamedTransferFn::kHLG,
350 };
351
352 static constexpr int kTransferFunctionCount = std::size(gTransferFunctions);
353
random_xfer_function(SkRandom * rand)354 const skcms_TransferFunction& random_xfer_function(SkRandom* rand) {
355 return gTransferFunctions[rand->nextULessThan(kTransferFunctionCount)];
356 }
357
358 static constexpr skcms_Matrix3x3 gGamuts[] = {
359 SkNamedGamut::kSRGB,
360 SkNamedGamut::kAdobeRGB,
361 SkNamedGamut::kDisplayP3,
362 SkNamedGamut::kRec2020,
363 SkNamedGamut::kXYZ,
364 };
365
366 static constexpr int kGamutCount = std::size(gGamuts);
367
random_gamut(SkRandom * rand)368 const skcms_Matrix3x3& random_gamut(SkRandom* rand) {
369 return gGamuts[rand->nextULessThan(kGamutCount)];
370 }
371
372 enum class ColorSpaceType {
373 kNone,
374 kSRGB,
375 kSRGBLinear,
376 kSRGBSpin,
377 kRGB,
378
379 kLast = kRGB
380 };
381
382 static constexpr int kColorSpaceTypeCount = static_cast<int>(ColorSpaceType::kLast) + 1;
383
random_colorspacetype(SkRandom * rand)384 ColorSpaceType random_colorspacetype(SkRandom* rand) {
385 return static_cast<ColorSpaceType>(rand->nextULessThan(kColorSpaceTypeCount));
386 }
387
random_colorspace(SkRandom * rand)388 sk_sp<SkColorSpace> random_colorspace(SkRandom* rand) {
389 ColorSpaceType cs = random_colorspacetype(rand);
390
391 switch (cs) {
392 case ColorSpaceType::kNone:
393 return nullptr;
394 case ColorSpaceType::kSRGB:
395 return SkColorSpace::MakeSRGB();
396 case ColorSpaceType::kSRGBLinear:
397 return SkColorSpace::MakeSRGBLinear();
398 case ColorSpaceType::kSRGBSpin:
399 return SkColorSpace::MakeSRGB()->makeColorSpin();
400 case ColorSpaceType::kRGB:
401 return SkColorSpace::MakeRGB(random_xfer_function(rand), random_gamut(rand));
402 }
403
404 SkUNREACHABLE;
405 }
406
407 enum class ColorConstraint {
408 kNone,
409 kOpaque,
410 kTransparent,
411 };
412
random_color(SkRandom * rand,ColorConstraint constraint)413 SkColor random_color(SkRandom* rand, ColorConstraint constraint) {
414 uint32_t color = rand->nextU();
415
416 switch (constraint) {
417 case ColorConstraint::kNone: return color;
418 case ColorConstraint::kOpaque: return 0xff000000 | color;
419 case ColorConstraint::kTransparent: return 0x80000000 | color;
420 }
421
422 SkUNREACHABLE;
423 }
424
random_color4f(SkRandom * rand,ColorConstraint constraint)425 SkColor4f random_color4f(SkRandom* rand, ColorConstraint constraint) {
426 SkColor4f result = { rand->nextRangeF(0.0f, 1.0f),
427 rand->nextRangeF(0.0f, 1.0f),
428 rand->nextRangeF(0.0f, 1.0f),
429 rand->nextRangeF(0.0f, 1.0f) };
430
431 switch (constraint) {
432 case ColorConstraint::kNone: return result;
433 case ColorConstraint::kOpaque: result.fA = 1.0f; return result;
434 case ColorConstraint::kTransparent: result.fA = 0.5f; return result;
435 }
436
437 SkUNREACHABLE;
438 }
439
random_tilemode(SkRandom * rand)440 SkTileMode random_tilemode(SkRandom* rand) {
441 return static_cast<SkTileMode>(rand->nextULessThan(kSkTileModeCount));
442 }
443
random_shadertype(SkRandom * rand)444 ShaderType random_shadertype(SkRandom* rand) {
445 return static_cast<ShaderType>(rand->nextULessThan(kShaderTypeCount));
446 }
447
random_porter_duff_bm(SkRandom * rand)448 SkBlendMode random_porter_duff_bm(SkRandom* rand) {
449 // NOTE: The porter duff modes refer to being able to be consolidated into a single
450 // call to sk_porter_duff_blend(), which has slightly fewer compatible blend modes than the
451 // "coefficient" blend mode that supports HW blending.
452 return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kClear,
453 (unsigned int) SkBlendMode::kPlus));
454 }
455
random_complex_bm(SkRandom * rand)456 SkBlendMode random_complex_bm(SkRandom* rand) {
457 return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kPlus,
458 (unsigned int) SkBlendMode::kLastMode));
459 }
460
random_blend_mode(SkRandom * rand)461 SkBlendMode random_blend_mode(SkRandom* rand) {
462 return static_cast<SkBlendMode>(rand->nextULessThan(kSkBlendModeCount));
463 }
464
random_maskfiltertype(SkRandom * rand)465 [[maybe_unused]] MaskFilterType random_maskfiltertype(SkRandom* rand) {
466 if (rand->nextBool()) {
467 return MaskFilterType::kNone; // bias this towards no mask filter
468 }
469
470 return static_cast<MaskFilterType>(rand->nextULessThan(kMaskFilterTypeCount));
471 }
472
random_blendertype(SkRandom * rand)473 BlenderType random_blendertype(SkRandom* rand) {
474 return static_cast<BlenderType>(rand->nextULessThan(kBlenderTypeCount));
475 }
476
random_colorfiltertype(SkRandom * rand)477 ColorFilterType random_colorfiltertype(SkRandom* rand) {
478 return static_cast<ColorFilterType>(rand->nextULessThan(kColorFilterTypeCount));
479 }
480
random_imagefiltertype(SkRandom * rand)481 ImageFilterType random_imagefiltertype(SkRandom* rand) {
482 return static_cast<ImageFilterType>(rand->nextULessThan(kImageFilterTypeCount));
483 }
484
random_cliptype(SkRandom * rand)485 [[maybe_unused]] ClipType random_cliptype(SkRandom* rand) {
486 if (rand->nextBool()) {
487 return ClipType::kNone; // bias this towards no clip
488 }
489
490 return static_cast<ClipType>(rand->nextULessThan(kClipTypeCount));
491 }
492
random_drawtype(SkRandom * rand)493 [[maybe_unused]] DrawTypeFlags random_drawtype(SkRandom* rand) {
494 uint32_t index = rand->nextULessThan(9);
495
496 switch (index) {
497 case 0: return DrawTypeFlags::kBitmapText_Mask;
498 case 1: return DrawTypeFlags::kBitmapText_LCD;
499 case 2: return DrawTypeFlags::kBitmapText_Color;
500 case 3: return DrawTypeFlags::kSDFText;
501 case 4: return DrawTypeFlags::kSDFText_LCD;
502 case 5: return DrawTypeFlags::kDrawVertices;
503 case 6: return DrawTypeFlags::kCircularArc;
504 case 7: return DrawTypeFlags::kSimpleShape;
505 case 8: return DrawTypeFlags::kNonSimpleShape;
506 }
507
508 SkASSERT(0);
509 return DrawTypeFlags::kNone;
510 }
511
512 enum LocalMatrixConstraint {
513 kNone,
514 kWithPerspective,
515 };
516
random_local_matrix(SkRandom * rand,SkMatrix * storage,LocalMatrixConstraint constaint=LocalMatrixConstraint::kNone)517 SkMatrix* random_local_matrix(SkRandom* rand,
518 SkMatrix* storage,
519 LocalMatrixConstraint constaint = LocalMatrixConstraint::kNone) {
520 // Only return nullptr if constraint == kNone.
521 uint32_t matrix = rand->nextULessThan(constaint == LocalMatrixConstraint::kNone ? 4 : 3);
522
523 switch (matrix) {
524 case 0: storage->setTranslate(2.0f, 2.0f); break;
525 case 1: storage->setIdentity(); break;
526 case 2: storage->setScale(0.25f, 0.25f, 0.0f, 0.0f); break;
527 case 3: return nullptr;
528 }
529
530 if (constaint == LocalMatrixConstraint::kWithPerspective) {
531 storage->setPerspX(0.5f);
532 }
533
534 return storage;
535 }
536
make_image(SkRandom * rand,Recorder * recorder)537 sk_sp<SkImage> make_image(SkRandom* rand, Recorder* recorder) {
538 SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
539 if (rand->nextBool()) {
540 ct = SkColorType::kAlpha_8_SkColorType;
541 }
542
543 SkImageInfo info = SkImageInfo::Make(32, 32, ct, kPremul_SkAlphaType, random_colorspace(rand));
544
545 SkBitmap bitmap;
546 bitmap.allocPixels(info);
547 bitmap.eraseColor(SK_ColorBLACK);
548
549 sk_sp<SkImage> img = bitmap.asImage();
550
551 // TODO: fuzz mipmappedness
552 return SkImages::TextureFromImage(recorder, img, {false});
553 }
554
make_yuv_image(SkRandom * rand,Recorder * recorder)555 sk_sp<SkImage> make_yuv_image(SkRandom* rand, Recorder* recorder) {
556
557 SkYUVAInfo::PlaneConfig planeConfig = SkYUVAInfo::PlaneConfig::kY_UV;
558 if (rand->nextBool()) {
559 planeConfig = SkYUVAInfo::PlaneConfig::kY_U_V_A;
560 }
561
562 SkYUVAInfo yuvaInfo({ 32, 32, },
563 planeConfig,
564 SkYUVAInfo::Subsampling::k420,
565 kJPEG_Full_SkYUVColorSpace);
566
567 SkASSERT(yuvaInfo.isValid());
568
569 SkYUVAPixmapInfo pmInfo(yuvaInfo, SkYUVAPixmapInfo::DataType::kUnorm8, nullptr);
570
571 SkYUVAPixmaps pixmaps = SkYUVAPixmaps::Allocate(pmInfo);
572
573 for (int i = 0; i < pixmaps.numPlanes(); ++i) {
574 pixmaps.plane(i).erase(SK_ColorBLACK);
575 }
576
577 sk_sp<SkColorSpace> cs;
578 if (rand->nextBool()) {
579 cs = SkColorSpace::MakeSRGBLinear();
580 }
581
582 return SkImages::TextureFromYUVAPixmaps(recorder,
583 pixmaps,
584 {/* fMipmapped= */ false},
585 /* limitToMaxTextureSize= */ false,
586 std::move(cs));
587 }
588
589 //--------------------------------------------------------------------------------------------------
make_picture(SkRandom * rand)590 sk_sp<SkPicture> make_picture(SkRandom* rand) {
591 constexpr SkRect kRect = SkRect::MakeWH(128, 128);
592
593 SkPictureRecorder recorder;
594
595 SkCanvas* canvas = recorder.beginRecording(kRect);
596
597 SkPaint paint; // Explicitly using the default SkPaint here
598
599 canvas->drawRect(kRect, paint);
600
601 return recorder.finishRecordingAsPicture();
602 }
603
604 //--------------------------------------------------------------------------------------------------
create_coord_clamp_shader(SkRandom * rand,Recorder * recorder)605 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_coord_clamp_shader(SkRandom* rand,
606 Recorder* recorder) {
607 auto [s, o] = create_random_shader(rand, recorder);
608 SkASSERT(!s == !o);
609
610 if (!s) {
611 return { nullptr, nullptr };
612 }
613
614 constexpr SkRect kSubset{0, 0, 256, 256}; // this is somewhat arbitrary but we need some subset
615 sk_sp<SkShader> ccs = SkShaders::CoordClamp(std::move(s), kSubset);
616 sk_sp<PrecompileShader> cco = PrecompileShaders::CoordClamp({ std::move(o) });
617
618 return { ccs, cco };
619 }
620
621 #if 0
622 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_empty_shader(SkRandom* /* rand */) {
623 sk_sp<SkShader> s = SkShaders::Empty();
624 sk_sp<PrecompileShader> o = PrecompileShaders::Empty();
625
626 return { s, o };
627 }
628 #endif
629
create_perlin_noise_shader(SkRandom * rand)630 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_perlin_noise_shader(SkRandom* rand) {
631 sk_sp<SkShader> s;
632 sk_sp<PrecompileShader> o;
633
634 if (rand->nextBool()) {
635 s = SkShaders::MakeFractalNoise(/* baseFrequencyX= */ 0.3f,
636 /* baseFrequencyY= */ 0.3f,
637 /* numOctaves= */ 2,
638 /* seed= */ 4);
639 o = PrecompileShaders::MakeFractalNoise();
640 } else {
641 s = SkShaders::MakeTurbulence(/* baseFrequencyX= */ 0.3f,
642 /* baseFrequencyY= */ 0.3f,
643 /* numOctaves= */ 2,
644 /* seed= */ 4);
645 o = PrecompileShaders::MakeTurbulence();
646 }
647
648 return { s, o };
649 }
650
create_picture_shader(SkRandom * rand)651 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_picture_shader(SkRandom* rand) {
652 sk_sp<SkPicture> picture = make_picture(rand);
653
654 gNeedSKPPaintOption = true;
655
656 SkMatrix lmStorage;
657 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
658
659 // TODO: can the clamp, filter mode, or tileRect affect the final program?
660 sk_sp<SkShader> s = picture->makeShader(SkTileMode::kClamp,
661 SkTileMode::kClamp,
662 SkFilterMode::kLinear,
663 lmPtr,
664 /* tileRect= */ nullptr);
665 sk_sp<PrecompileShader> o = PrecompileShadersPriv::Picture(SkToBool(lmPtr));
666
667 return { s, o };
668 }
669
create_solid_shader(SkRandom * rand,ColorConstraint constraint=ColorConstraint::kNone)670 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_solid_shader(
671 SkRandom* rand,
672 ColorConstraint constraint = ColorConstraint::kNone) {
673 sk_sp<SkShader> s;
674 sk_sp<PrecompileShader> o;
675
676 if (rand->nextBool()) {
677 s = SkShaders::Color(random_color(rand, constraint));
678 o = PrecompileShaders::Color();
679 } else {
680 sk_sp<SkColorSpace> cs = random_colorspace(rand);
681 s = SkShaders::Color(random_color4f(rand, constraint), cs);
682 o = PrecompileShaders::Color(std::move(cs));
683 }
684
685 return { s, o };
686 }
687
create_gradient_shader(SkRandom * rand,SkShaderBase::GradientType type,ColorConstraint constraint=ColorConstraint::kOpaque)688 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_gradient_shader(
689 SkRandom* rand,
690 SkShaderBase::GradientType type,
691 ColorConstraint constraint = ColorConstraint::kOpaque) {
692 // TODO: fuzz more of the gradient parameters
693
694 static constexpr int kMaxNumStops = 9;
695 SkColor4f colors[kMaxNumStops] = {
696 random_color4f(rand, constraint),
697 random_color4f(rand, constraint),
698 random_color4f(rand, constraint),
699 random_color4f(rand, constraint),
700 random_color4f(rand, constraint),
701 random_color4f(rand, constraint),
702 random_color4f(rand, constraint),
703 random_color4f(rand, constraint),
704 random_color4f(rand, constraint)
705 };
706 static const SkPoint kPts[kMaxNumStops] = {
707 { -100.0f, -100.0f },
708 { -50.0f, -50.0f },
709 { -25.0f, -25.0f },
710 { -12.5f, -12.5f },
711 { 0.0f, 0.0f },
712 { 12.5f, 12.5f },
713 { 25.0f, 25.0f },
714 { 50.0f, 50.0f },
715 { 100.0f, 100.0f }
716 };
717 static const float kOffsets[kMaxNumStops] =
718 { 0.0f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, 1.0f };
719
720 int numStops;
721
722 switch (rand->nextULessThan(3)) {
723 case 0: numStops = 2; break;
724 case 1: numStops = 7; break;
725 case 2: [[fallthrough]];
726 default: numStops = kMaxNumStops; break;
727 }
728
729 SkMatrix lmStorage;
730 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
731
732 const SkGradientShader::Interpolation::InPremul inPremul =
733 rand->nextBool() ? SkGradientShader::Interpolation::InPremul::kYes
734 : SkGradientShader::Interpolation::InPremul::kNo;
735 const SkGradientShader::Interpolation::ColorSpace colorSpace =
736 static_cast<SkGradientShader::Interpolation::ColorSpace>(
737 rand->nextULessThan(SkGradientShader::Interpolation::kColorSpaceCount));
738 SkGradientShader::Interpolation interpolation = {inPremul, colorSpace};
739
740 sk_sp<SkShader> s;
741 sk_sp<PrecompileShader> o;
742
743 SkTileMode tm = random_tilemode(rand);
744
745 switch (type) {
746 case SkShaderBase::GradientType::kLinear:
747 s = SkGradientShader::MakeLinear(kPts,
748 colors, /* colorSpace= */ nullptr, kOffsets, numStops,
749 tm, interpolation, lmPtr);
750 o = PrecompileShaders::LinearGradient(interpolation);
751 break;
752 case SkShaderBase::GradientType::kRadial:
753 s = SkGradientShader::MakeRadial(/* center= */ {0, 0}, /* radius= */ 100,
754 colors, /* colorSpace= */ nullptr, kOffsets, numStops,
755 tm, interpolation, lmPtr);
756 o = PrecompileShaders::RadialGradient(interpolation);
757 break;
758 case SkShaderBase::GradientType::kSweep:
759 s = SkGradientShader::MakeSweep(/* cx= */ 0, /* cy= */ 0,
760 colors, /* colorSpace= */ nullptr, kOffsets, numStops,
761 tm, /* startAngle= */ 0, /* endAngle= */ 359,
762 interpolation, lmPtr);
763 o = PrecompileShaders::SweepGradient(interpolation);
764 break;
765 case SkShaderBase::GradientType::kConical:
766 s = SkGradientShader::MakeTwoPointConical(/* start= */ {100, 100},
767 /* startRadius= */ 100,
768 /* end= */ {-100, -100},
769 /* endRadius= */ 100,
770 colors,
771 /* colorSpace= */ nullptr,
772 kOffsets, numStops, tm, interpolation, lmPtr);
773 o = PrecompileShaders::TwoPointConicalGradient(interpolation);
774 break;
775 case SkShaderBase::GradientType::kNone:
776 SkDEBUGFAIL("Gradient shader says its type is none");
777 break;
778 }
779
780 return { s, o };
781 }
782
create_localmatrix_shader(SkRandom * rand,Recorder * recorder)783 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_localmatrix_shader(SkRandom* rand,
784 Recorder* recorder) {
785 auto [s, o] = create_random_shader(rand, recorder);
786 SkASSERT(!s == !o);
787
788 if (!s) {
789 return { nullptr, nullptr };
790 }
791
792 bool hasPerspective = rand->nextBool();
793
794 SkMatrix lmStorage;
795 random_local_matrix(rand, &lmStorage, hasPerspective ? LocalMatrixConstraint::kWithPerspective
796 : LocalMatrixConstraint::kNone);
797
798 return { s->makeWithLocalMatrix(lmStorage), o->makeWithLocalMatrix(hasPerspective) };
799 }
800
create_colorfilter_shader(SkRandom * rand,Recorder * recorder)801 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_colorfilter_shader(SkRandom* rand,
802 Recorder* recorder) {
803 auto [s, o] = create_random_shader(rand, recorder);
804 SkASSERT(!s == !o);
805
806 if (!s) {
807 return { nullptr, nullptr };
808 }
809
810 auto [cf, cfO] = create_random_colorfilter(rand);
811
812 return { s->makeWithColorFilter(std::move(cf)), o->makeWithColorFilter(std::move(cfO)) };
813 }
814
815 // TODO: With the new explicit PrecompileImageFilter API we need to test out complete DAGS of IFs
create_image_shader(SkRandom * rand,Recorder * recorder)816 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_image_shader(SkRandom* rand,
817 Recorder* recorder) {
818 SkTileMode tmX = random_tilemode(rand);
819 SkTileMode tmY = random_tilemode(rand);
820
821 std::vector<SkTileMode> precompileTileModes =
822 (tmX == tmY) ? std::vector<SkTileMode>{tmX} : std::vector<SkTileMode>{};
823
824 SkMatrix lmStorage;
825 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
826
827 sk_sp<SkShader> s;
828 sk_sp<PrecompileShader> o;
829
830 sk_sp<SkImage> image = make_image(rand, recorder);
831 SkColorInfo colorInfo = image->imageInfo().colorInfo();
832
833 switch (rand->nextULessThan(4)) {
834 case 0: {
835 // Non-subset image.
836 s = SkShaders::Image(std::move(image), tmX, tmY, SkSamplingOptions(), lmPtr);
837 o = PrecompileShaders::Image({ colorInfo }, precompileTileModes);
838 } break;
839 case 1: {
840 // Subset image.
841 const SkRect subset = SkRect::MakeWH(image->width() / 2, image->height() / 2);
842 s = SkImageShader::MakeSubset(
843 std::move(image), subset, tmX, tmY, SkSamplingOptions(), lmPtr);
844 o = PrecompileShaders::Image({ colorInfo }, precompileTileModes);
845 } break;
846 case 2: {
847 // Cubic-sampled image.
848 s = SkShaders::Image(std::move(image), tmX, tmY, SkCubicResampler::Mitchell(), lmPtr);
849 o = PrecompileShaders::Image({ colorInfo }, precompileTileModes);
850 } break;
851 default: {
852 // Raw image draw.
853 s = SkShaders::RawImage(std::move(image), tmX, tmY, SkSamplingOptions(), lmPtr);
854 o = PrecompileShaders::RawImage({ colorInfo }, precompileTileModes);
855 } break;
856 }
857
858 return { s, o };
859 }
860
create_yuv_image_shader(SkRandom * rand,Recorder * recorder)861 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_yuv_image_shader(SkRandom* rand,
862 Recorder* recorder) {
863 SkTileMode tmX = random_tilemode(rand);
864 SkTileMode tmY = random_tilemode(rand);
865
866 SkMatrix lmStorage;
867 SkMatrix* lmPtr = random_local_matrix(rand, &lmStorage);
868
869 sk_sp<SkShader> s;
870 sk_sp<PrecompileShader> o;
871
872 SkSamplingOptions samplingOptions(SkFilterMode::kLinear);
873 if (rand->nextBool()) {
874 samplingOptions = SkCubicResampler::Mitchell();
875 }
876
877 sk_sp<SkImage> yuvImage = make_yuv_image(rand, recorder);
878 if (rand->nextBool()) {
879 s = SkImageShader::MakeSubset(std::move(yuvImage), SkRect::MakeXYWH(8, 8, 16, 16),
880 tmX, tmY, samplingOptions, lmPtr);
881 } else {
882 s = SkShaders::Image(std::move(yuvImage), tmX, tmY, samplingOptions, lmPtr);
883 }
884
885 o = PrecompileShaders::YUVImage();
886
887 return { s, o };
888 }
889
create_blend_shader(SkRandom * rand,Recorder * recorder)890 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_blend_shader(SkRandom* rand,
891 Recorder* recorder) {
892 // TODO: add explicit testing of the kClear, kDst and kSrc blend modes since they short
893 // circuit creation of a true blend shader (i.e., in SkShaders::Blend).
894 auto [blender, blenderO] = create_random_blender(rand);
895
896 auto [dstS, dstO] = create_random_shader(rand, recorder);
897 SkASSERT(!dstS == !dstO);
898 if (!dstS) {
899 return { nullptr, nullptr };
900 }
901
902 auto [srcS, srcO] = create_random_shader(rand, recorder);
903 SkASSERT(!srcS == !srcO);
904 if (!srcS) {
905 return { nullptr, nullptr };
906 }
907
908 auto s = SkShaders::Blend(std::move(blender), std::move(dstS), std::move(srcS));
909 auto o = PrecompileShaders::Blend(SkSpan<const sk_sp<PrecompileBlender>>({ blenderO }),
910 { dstO }, { srcO });
911
912 return { s, o };
913 }
914
create_workingCS_shader(SkRandom * rand,Recorder * recorder)915 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_workingCS_shader(SkRandom* rand,
916 Recorder* recorder) {
917 auto [wrappedS, wrappedO] = create_random_shader(rand, recorder);
918 SkASSERT(!wrappedS == !wrappedO);
919 if (!wrappedS) {
920 return { nullptr, nullptr };
921 }
922
923 sk_sp<SkColorSpace> cs = random_colorspace(rand);
924 sk_sp<SkShader> s = wrappedS->makeWithWorkingColorSpace(cs);
925 sk_sp<PrecompileShader> o = wrappedO->makeWithWorkingColorSpace(std::move(cs));
926
927 return { s, o };
928 }
929
create_shader(SkRandom * rand,Recorder * recorder,ShaderType shaderType)930 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_shader(SkRandom* rand,
931 Recorder* recorder,
932 ShaderType shaderType) {
933
934 switch (shaderType) {
935 case ShaderType::kNone:
936 return { nullptr, nullptr };
937 case ShaderType::kBlend:
938 return create_blend_shader(rand, recorder);
939 case ShaderType::kColorFilter:
940 return create_colorfilter_shader(rand, recorder);
941 case ShaderType::kCoordClamp:
942 return create_coord_clamp_shader(rand, recorder);
943 case ShaderType::kConicalGradient:
944 return create_gradient_shader(rand, SkShaderBase::GradientType::kConical);
945 // case ShaderType::kEmpty:
946 // return create_empty_shader(rand);
947 case ShaderType::kImage:
948 return create_image_shader(rand, recorder);
949 case ShaderType::kLinearGradient:
950 return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear);
951 case ShaderType::kLocalMatrix:
952 return create_localmatrix_shader(rand, recorder);
953 case ShaderType::kPerlinNoise:
954 return create_perlin_noise_shader(rand);
955 case ShaderType::kPicture:
956 return create_picture_shader(rand);
957 case ShaderType::kRadialGradient:
958 return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial);
959 case ShaderType::kRuntime:
960 return PrecompileFactories::CreateAnnulusRuntimeShader();
961 case ShaderType::kSolidColor:
962 return create_solid_shader(rand);
963 case ShaderType::kSweepGradient:
964 return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep);
965 case ShaderType::kYUVImage:
966 return create_yuv_image_shader(rand, recorder);
967 case ShaderType::kWorkingColorSpace:
968 return create_workingCS_shader(rand, recorder);
969 }
970
971 SkUNREACHABLE;
972 }
973
create_random_shader(SkRandom * rand,Recorder * recorder)974 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom* rand,
975 Recorder* recorder) {
976 return create_shader(rand, recorder, random_shadertype(rand));
977 }
978
create_clip_shader(SkRandom * rand,Recorder * recorder)979 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_clip_shader(SkRandom* rand,
980 Recorder* recorder) {
981 // The clip shader has to be transparent to be at all interesting.
982 // TODO/Note: an opaque clipShader is eliminated from the SkPaint by the normal Skia API
983 // but I'm unsure if we should bother capturing that possibility in the precompile system.
984 switch (rand->nextULessThan(5)) {
985 case 0: return create_gradient_shader(rand, SkShaderBase::GradientType::kConical,
986 ColorConstraint::kTransparent);
987 case 1: return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear,
988 ColorConstraint::kTransparent);
989 case 2: return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial,
990 ColorConstraint::kTransparent);
991 case 3: return create_solid_shader(rand, ColorConstraint::kTransparent);
992 case 4: return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep,
993 ColorConstraint::kTransparent);
994 }
995
996 SkUNREACHABLE;
997 }
998
create_bm_blender(SkRandom * rand,SkBlendMode bm)999 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_bm_blender(SkRandom* rand,
1000 SkBlendMode bm) {
1001 return { SkBlender::Mode(bm), PrecompileBlenders::Mode(bm) };
1002 }
1003
create_arithmetic_blender()1004 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_arithmetic_blender() {
1005 sk_sp<SkBlender> b = SkBlenders::Arithmetic(/* k1= */ 0.5,
1006 /* k2= */ 0.5,
1007 /* k3= */ 0.5,
1008 /* k4= */ 0.5,
1009 /* enforcePremul= */ true);
1010 sk_sp<PrecompileBlender> o = PrecompileBlenders::Arithmetic();
1011
1012 return { std::move(b), std::move(o) };
1013 }
1014
create_rt_blender(SkRandom * rand)1015 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_rt_blender(SkRandom* rand) {
1016 int option = rand->nextULessThan(3);
1017
1018 switch (option) {
1019 case 0: return PrecompileFactories::CreateSrcRuntimeBlender();
1020 case 1: return PrecompileFactories::CreateDstRuntimeBlender();
1021 case 2: return PrecompileFactories::CreateComboRuntimeBlender();
1022 }
1023
1024 return { nullptr, nullptr };
1025 }
1026
create_blender(SkRandom * rand,BlenderType type)1027 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_blender(SkRandom* rand,
1028 BlenderType type) {
1029 switch (type) {
1030 case BlenderType::kNone:
1031 return { nullptr, nullptr };
1032 case BlenderType::kPorterDuff:
1033 return create_bm_blender(rand, random_porter_duff_bm(rand));
1034 case BlenderType::kShaderBased:
1035 return create_bm_blender(rand, random_complex_bm(rand));
1036 case BlenderType::kArithmetic:
1037 return create_arithmetic_blender();
1038 case BlenderType::kRuntime:
1039 return create_rt_blender(rand);
1040 }
1041
1042 SkUNREACHABLE;
1043 }
1044
create_random_blender(SkRandom * rand)1045 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom* rand) {
1046 return create_blender(rand, random_blendertype(rand));
1047 }
1048
1049 //--------------------------------------------------------------------------------------------------
1050 //--------------------------------------------------------------------------------------------------
1051
1052
create_rt_colorfilter(SkRandom * rand)1053 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_rt_colorfilter(
1054 SkRandom* rand) {
1055 int option = rand->nextULessThan(3);
1056
1057 switch (option) {
1058 case 0: return PrecompileFactories::CreateDoubleRuntimeColorFilter();
1059 case 1: return PrecompileFactories::CreateHalfRuntimeColorFilter();
1060 case 2: return PrecompileFactories::CreateComboRuntimeColorFilter();
1061 }
1062
1063 return { nullptr, nullptr };
1064 }
1065
create_lerp_colorfilter(SkRandom * rand)1066 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_lerp_colorfilter(
1067 SkRandom* rand) {
1068
1069 auto [dst, dstO] = create_random_colorfilter(rand);
1070 auto [src, srcO] = create_random_colorfilter(rand);
1071 // SkColorFilters::Lerp optimizes away the case where src == dst. I don't know if it is worth
1072 // capturing it in the precompilation API
1073 while (src == dst) {
1074 std::tie(src, srcO) = create_random_colorfilter(rand);
1075 }
1076
1077 // TODO: SkColorFilters::Lerp will return a different colorFilter depending on the
1078 // weight value and the child color filters. I don't know if that is worth capturing
1079 // in the precompile API.
1080 sk_sp<SkColorFilter> cf = SkColorFilters::Lerp(0.5f, std::move(dst), std::move(src));
1081
1082 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Lerp({ dstO }, { srcO });
1083
1084 return { cf, o };
1085 }
1086
create_lighting_colorfilter()1087 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_lighting_colorfilter() {
1088 // TODO: the lighting color filter factory special cases when nothing is added and converts it
1089 // to a blendmode color filter
1090 return { SkColorFilters::Lighting(SK_ColorGREEN, SK_ColorRED),
1091 PrecompileColorFilters::Lighting() };
1092 }
1093
create_blendmode_colorfilter(SkRandom * rand)1094 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_blendmode_colorfilter(
1095 SkRandom* rand) {
1096
1097 sk_sp<SkColorFilter> cf;
1098
1099 // SkColorFilters::Blend is clever and can weed out noop color filters. Loop until we get
1100 // a valid color filter.
1101 SkBlendMode blend;
1102 while (!cf) {
1103 blend = random_blend_mode(rand);
1104 cf = SkColorFilters::Blend(random_color4f(rand, ColorConstraint::kNone),
1105 random_colorspace(rand),
1106 blend);
1107 }
1108
1109 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Blend({&blend, 1});
1110
1111 return { std::move(cf), std::move(o) };
1112 }
1113
create_matrix_colorfilter()1114 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_matrix_colorfilter() {
1115 sk_sp<SkColorFilter> cf = SkColorFilters::Matrix(
1116 SkColorMatrix::RGBtoYUV(SkYUVColorSpace::kJPEG_Full_SkYUVColorSpace));
1117 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Matrix();
1118
1119 return { std::move(cf), std::move(o) };
1120 }
1121
create_color_space_colorfilter(SkRandom * rand)1122 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_color_space_colorfilter(
1123 SkRandom* rand) {
1124 sk_sp<SkColorSpace> src = random_colorspace(rand);
1125 sk_sp<SkColorSpace> dst = random_colorspace(rand);
1126 return { SkColorFilterPriv::MakeColorSpaceXform(src, dst),
1127 PrecompileColorFiltersPriv::ColorSpaceXform({ src }, { dst }) };
1128 }
1129
create_linear_to_srgb_colorfilter()1130 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_linear_to_srgb_colorfilter() {
1131 return { SkColorFilters::LinearToSRGBGamma(), PrecompileColorFilters::LinearToSRGBGamma() };
1132 }
1133
create_srgb_to_linear_colorfilter()1134 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_srgb_to_linear_colorfilter() {
1135 return { SkColorFilters::SRGBToLinearGamma(), PrecompileColorFilters::SRGBToLinearGamma() };
1136 }
1137
create_high_contrast_colorfilter()1138 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_high_contrast_colorfilter() {
1139 SkHighContrastConfig config(/* grayscale= */ false,
1140 SkHighContrastConfig::InvertStyle::kInvertBrightness,
1141 /* contrast= */ 0.5f);
1142 return { SkHighContrastFilter::Make(config), PrecompileColorFilters::HighContrast() };
1143 }
1144
create_luma_colorfilter()1145 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_luma_colorfilter() {
1146 return { SkLumaColorFilter::Make(), PrecompileColorFilters::Luma() };
1147 }
1148
create_overdraw_colorfilter()1149 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_overdraw_colorfilter() {
1150 // Black to red heat map gradation
1151 static const SkColor kColors[SkOverdrawColorFilter::kNumColors] = {
1152 SK_ColorBLACK,
1153 SK_ColorBLUE,
1154 SK_ColorCYAN,
1155 SK_ColorGREEN,
1156 SK_ColorYELLOW,
1157 SK_ColorRED
1158 };
1159
1160 return { SkOverdrawColorFilter::MakeWithSkColors(kColors), PrecompileColorFilters::Overdraw() };
1161 }
1162
create_compose_colorfilter(SkRandom * rand)1163 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_compose_colorfilter(
1164 SkRandom* rand) {
1165 auto [outerCF, outerO] = create_random_colorfilter(rand);
1166 auto [innerCF, innerO] = create_random_colorfilter(rand);
1167
1168 // TODO: if outerCF is null, innerCF will be returned by Compose. We need a Precompile
1169 // list object that can encapsulate innerO if there are no combinations in outerO.
1170 return { SkColorFilters::Compose(std::move(outerCF), std::move(innerCF)),
1171 PrecompileColorFilters::Compose({ std::move(outerO) }, { std::move(innerO) }) };
1172 }
1173
create_gaussian_colorfilter()1174 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_gaussian_colorfilter() {
1175 return { SkColorFilterPriv::MakeGaussian(), PrecompileColorFiltersPriv::Gaussian() };
1176 }
1177
create_table_colorfilter()1178 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_table_colorfilter() {
1179 static constexpr uint8_t kTable[256] = { 0 };
1180
1181 return { SkColorFilters::Table(kTable), PrecompileColorFilters::Table() };
1182 }
1183
create_workingformat_colorfilter(SkRandom * rand)1184 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_workingformat_colorfilter(
1185 SkRandom* rand) {
1186 auto [childCF, childO] = create_random_colorfilter(rand);
1187
1188 if (!childCF) {
1189 return { nullptr, nullptr };
1190 }
1191
1192 SkASSERT(childCF && childO);
1193
1194 const skcms_TransferFunction* tf = rand->nextBool() ? &random_xfer_function(rand) : nullptr;
1195 const skcms_Matrix3x3* gamut = rand->nextBool() ? &random_gamut(rand) : nullptr;
1196 const SkAlphaType unpremul = kUnpremul_SkAlphaType;
1197
1198 sk_sp<SkColorFilter> cf =
1199 SkColorFilterPriv::WithWorkingFormat(std::move(childCF), tf, gamut, &unpremul);
1200
1201 sk_sp<PrecompileColorFilter> o = PrecompileColorFiltersPriv::WithWorkingFormat(
1202 { std::move(childO) }, tf, gamut, &unpremul);
1203
1204 return { std::move(cf), std::move(o) };
1205 }
1206
create_hsla_matrix_colorfilter()1207 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_hsla_matrix_colorfilter() {
1208 sk_sp<SkColorFilter> cf = SkColorFilters::HSLAMatrix(
1209 SkColorMatrix::RGBtoYUV(SkYUVColorSpace::kJPEG_Full_SkYUVColorSpace));
1210 sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::HSLAMatrix();
1211
1212 return { std::move(cf), std::move(o) };
1213 }
1214
create_colorfilter(SkRandom * rand,ColorFilterType type)1215 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_colorfilter(
1216 SkRandom* rand,
1217 ColorFilterType type) {
1218
1219 switch (type) {
1220 case ColorFilterType::kNone:
1221 return { nullptr, nullptr };
1222 case ColorFilterType::kBlendMode:
1223 return create_blendmode_colorfilter(rand);
1224 case ColorFilterType::kColorSpaceXform:
1225 return create_color_space_colorfilter(rand);
1226 case ColorFilterType::kCompose:
1227 return create_compose_colorfilter(rand);
1228 case ColorFilterType::kGaussian:
1229 return create_gaussian_colorfilter();
1230 case ColorFilterType::kHighContrast:
1231 return create_high_contrast_colorfilter();
1232 case ColorFilterType::kHSLAMatrix:
1233 return create_hsla_matrix_colorfilter();
1234 case ColorFilterType::kLerp:
1235 return create_lerp_colorfilter(rand);
1236 case ColorFilterType::kLighting:
1237 return create_lighting_colorfilter();
1238 case ColorFilterType::kLinearToSRGB:
1239 return create_linear_to_srgb_colorfilter();
1240 case ColorFilterType::kLuma:
1241 return create_luma_colorfilter();
1242 case ColorFilterType::kMatrix:
1243 return create_matrix_colorfilter();
1244 case ColorFilterType::kOverdraw:
1245 return create_overdraw_colorfilter();
1246 case ColorFilterType::kRuntime:
1247 return create_rt_colorfilter(rand);
1248 case ColorFilterType::kSRGBToLinear:
1249 return create_srgb_to_linear_colorfilter();
1250 case ColorFilterType::kTable:
1251 return create_table_colorfilter();
1252 case ColorFilterType::kWorkingFormat:
1253 return create_workingformat_colorfilter(rand);
1254 }
1255
1256 SkUNREACHABLE;
1257 }
1258
create_random_colorfilter(SkRandom * rand)1259 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(
1260 SkRandom* rand) {
1261 return create_colorfilter(rand, random_colorfiltertype(rand));
1262 }
1263
1264 //--------------------------------------------------------------------------------------------------
1265 //--------------------------------------------------------------------------------------------------
arithmetic_imagefilter(SkRandom *)1266 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> arithmetic_imagefilter(
1267 SkRandom* /* rand */) {
1268
1269 sk_sp<SkImageFilter> arithmeticIF = SkImageFilters::Arithmetic(/* k1= */ 0.5f,
1270 /* k2= */ 0.5f,
1271 /* k3= */ 0.5f,
1272 /* k4= */ 0.5f,
1273 /* enforcePMColor= */ false,
1274 /* background= */ nullptr,
1275 /* foreground= */ nullptr);
1276 sk_sp<PrecompileImageFilter> option = PrecompileImageFilters::Arithmetic(
1277 /* background= */ nullptr,
1278 /* foreground= */ nullptr);
1279
1280 return { std::move(arithmeticIF), std::move(option) };
1281 }
1282
blendmode_imagefilter(SkRandom * rand)1283 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> blendmode_imagefilter(
1284 SkRandom* rand) {
1285
1286 SkBlendMode bm = random_blend_mode(rand);
1287 sk_sp<SkImageFilter> blendIF = SkImageFilters::Blend(bm,
1288 /* background= */ nullptr,
1289 /* foreground= */ nullptr);
1290 sk_sp<PrecompileImageFilter> blendO = PrecompileImageFilters::Blend(
1291 bm,
1292 /* background= */ nullptr,
1293 /* foreground= */ nullptr);
1294
1295 return { std::move(blendIF), std::move(blendO) };
1296 }
1297
runtime_blender_imagefilter(SkRandom * rand)1298 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> runtime_blender_imagefilter(
1299 SkRandom* rand) {
1300
1301 auto [blender, blenderO] = create_blender(rand, BlenderType::kRuntime);
1302 sk_sp<SkImageFilter> blenderIF = SkImageFilters::Blend(std::move(blender),
1303 /* background= */ nullptr,
1304 /* foreground= */ nullptr);
1305 sk_sp<PrecompileImageFilter> option = PrecompileImageFilters::Blend(std::move(blenderO),
1306 /* background= */ nullptr,
1307 /* foreground= */ nullptr);
1308
1309 return { std::move(blenderIF), std::move(option) };
1310 }
1311
blur_imagefilter(SkRandom * rand)1312 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> blur_imagefilter(
1313 SkRandom* rand) {
1314
1315 int option = rand->nextULessThan(3);
1316
1317 float sigma;
1318 switch (option) {
1319 case 0: sigma = 1.0f; break; // 1DBlur4
1320 case 1: sigma = 2.0f; break; // 1DBlur8
1321 case 2: [[fallthrough]];
1322 default: sigma = 5.0f; break; // 1DBlur16
1323 }
1324
1325 sk_sp<SkImageFilter> blurIF = SkImageFilters::Blur(sigma, sigma, /* input= */ nullptr);
1326 sk_sp<PrecompileImageFilter> blurO = PrecompileImageFilters::Blur(/* input= */ nullptr);
1327
1328 return { std::move(blurIF), std::move(blurO) };
1329 }
1330
displacement_imagefilter(Recorder * recorder,SkRandom * rand)1331 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> displacement_imagefilter(
1332 Recorder* recorder,
1333 SkRandom* rand) {
1334
1335 sk_sp<SkImage> checkerboard = ToolUtils::create_checkerboard_image(16, 16,
1336 SK_ColorWHITE,
1337 SK_ColorBLACK,
1338 /* checkSize= */ 4);
1339 checkerboard = SkImages::TextureFromImage(recorder, std::move(checkerboard), {false});
1340 SkASSERT(checkerboard);
1341
1342 sk_sp<SkImageFilter> imageIF(SkImageFilters::Image(std::move(checkerboard),
1343 SkFilterMode::kLinear));
1344
1345 sk_sp<SkImageFilter> displacementIF;
1346
1347 displacementIF = SkImageFilters::DisplacementMap(SkColorChannel::kR,
1348 SkColorChannel::kB,
1349 /* scale= */ 2.0f,
1350 /* displacement= */ std::move(imageIF),
1351 /* color= */ nullptr);
1352 sk_sp<PrecompileImageFilter> option =
1353 PrecompileImageFilters::DisplacementMap(/* input= */ nullptr);
1354
1355 return { std::move(displacementIF), std::move(option) };
1356 }
1357
colorfilter_imagefilter(SkRandom * rand)1358 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> colorfilter_imagefilter(
1359 SkRandom* rand) {
1360
1361 auto [cf, o] = create_random_colorfilter(rand);
1362
1363 sk_sp<SkImageFilter> inputIF;
1364 sk_sp<PrecompileImageFilter> inputO;
1365 if (rand->nextBool()) {
1366 // Exercise color filter collapsing in the factories
1367 auto [cf2, o2] = create_random_colorfilter(rand);
1368 inputIF = SkImageFilters::ColorFilter(std::move(cf2), /* input= */ nullptr);
1369 inputO = PrecompileImageFilters::ColorFilter(std::move(o2), /* input= */ nullptr);
1370 }
1371
1372 sk_sp<SkImageFilter> cfIF = SkImageFilters::ColorFilter(std::move(cf), std::move(inputIF));
1373 sk_sp<PrecompileImageFilter> cfIFO = PrecompileImageFilters::ColorFilter(std::move(o),
1374 std::move(inputO));
1375
1376 return { std::move(cfIF), std::move(cfIFO) };
1377 }
1378
lighting_imagefilter(SkRandom * rand)1379 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> lighting_imagefilter(
1380 SkRandom* rand) {
1381 static constexpr SkPoint3 kLocation{10.0f, 2.0f, 30.0f};
1382 static constexpr SkPoint3 kTarget{0, 0, 0};
1383 static constexpr SkPoint3 kDirection{0, 1, 0};
1384
1385 sk_sp<SkImageFilter> lightingIF;
1386
1387 int option = rand->nextULessThan(6);
1388 switch (option) {
1389 case 0:
1390 lightingIF = SkImageFilters::DistantLitDiffuse(kDirection, SK_ColorRED,
1391 /* surfaceScale= */ 1.0f,
1392 /* kd= */ 0.5f,
1393 /* input= */ nullptr);
1394 break;
1395 case 1:
1396 lightingIF = SkImageFilters::PointLitDiffuse(kLocation, SK_ColorGREEN,
1397 /* surfaceScale= */ 1.0f,
1398 /* kd= */ 0.5f,
1399 /* input= */ nullptr);
1400 break;
1401 case 2:
1402 lightingIF = SkImageFilters::SpotLitDiffuse(kLocation, kTarget,
1403 /* falloffExponent= */ 2.0f,
1404 /* cutoffAngle= */ 30.0f,
1405 SK_ColorBLUE,
1406 /* surfaceScale= */ 1.0f,
1407 /* kd= */ 0.5f,
1408 /* input= */ nullptr);
1409 break;
1410 case 3:
1411 lightingIF = SkImageFilters::DistantLitSpecular(kDirection, SK_ColorCYAN,
1412 /* surfaceScale= */ 1.0f,
1413 /* ks= */ 0.5f,
1414 /* shininess= */ 2.0f,
1415 /* input= */ nullptr);
1416 break;
1417 case 4:
1418 lightingIF = SkImageFilters::PointLitSpecular(kLocation, SK_ColorMAGENTA,
1419 /* surfaceScale= */ 1.0f,
1420 /* ks= */ 0.5f,
1421 /* shininess= */ 2.0f,
1422 /* input= */ nullptr);
1423 break;
1424 case 5:
1425 lightingIF = SkImageFilters::SpotLitSpecular(kLocation, kTarget,
1426 /* falloffExponent= */ 2.0f,
1427 /* cutoffAngle= */ 30.0f,
1428 SK_ColorYELLOW,
1429 /* surfaceScale= */ 1.0f,
1430 /* ks= */ 4.0f,
1431 /* shininess= */ 0.5f,
1432 /* input= */ nullptr);
1433 break;
1434 }
1435
1436 sk_sp<PrecompileImageFilter> lightingO = PrecompileImageFilters::Lighting(/* input= */ nullptr);
1437 return { std::move(lightingIF), std::move(lightingO) };
1438 }
1439
matrix_convolution_imagefilter(SkRandom * rand)1440 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> matrix_convolution_imagefilter(
1441 SkRandom* rand) {
1442
1443 int kernelSize = 1;
1444
1445 int option = rand->nextULessThan(3);
1446 switch (option) {
1447 case 0: kernelSize = 3; break;
1448 case 1: kernelSize = 7; break;
1449 case 2: kernelSize = 11; break;
1450 }
1451
1452 int center = (kernelSize * kernelSize - 1) / 2;
1453 std::vector<float> kernel(kernelSize * kernelSize, SkIntToScalar(1));
1454 kernel[center] = 2.0f - kernelSize * kernelSize;
1455
1456 sk_sp<SkImageFilter> matrixConvIF;
1457 matrixConvIF = SkImageFilters::MatrixConvolution({ kernelSize, kernelSize },
1458 /* kernel= */ kernel.data(),
1459 /* gain= */ 0.3f,
1460 /* bias= */ 100.0f,
1461 /* kernelOffset= */ { 1, 1 },
1462 SkTileMode::kMirror,
1463 /* convolveAlpha= */ false,
1464 /* input= */ nullptr);
1465 SkASSERT(matrixConvIF);
1466 sk_sp<PrecompileImageFilter> convOption = PrecompileImageFilters::MatrixConvolution(
1467 /* input= */ nullptr);
1468
1469 return { std::move(matrixConvIF), std::move(convOption) };
1470 }
1471
morphology_imagefilter(SkRandom * rand)1472 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> morphology_imagefilter(
1473 SkRandom* rand) {
1474 static constexpr float kRadX = 2.0f, kRadY = 4.0f;
1475
1476 sk_sp<SkImageFilter> morphologyIF;
1477
1478 if (rand->nextBool()) {
1479 morphologyIF = SkImageFilters::Erode(kRadX, kRadY, /* input= */ nullptr);
1480 } else {
1481 morphologyIF = SkImageFilters::Dilate(kRadX, kRadY, /* input= */ nullptr);
1482 }
1483 SkASSERT(morphologyIF);
1484 sk_sp<PrecompileImageFilter> option = PrecompileImageFilters::Morphology(/* input= */ nullptr);
1485
1486 return { std::move(morphologyIF), std::move(option) };
1487 }
1488
create_image_filter(Recorder * recorder,SkRandom * rand,ImageFilterType type)1489 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> create_image_filter(
1490 Recorder* recorder,
1491 SkRandom* rand,
1492 ImageFilterType type) {
1493
1494 switch (type) {
1495 case ImageFilterType::kNone:
1496 return {};
1497 case ImageFilterType::kArithmetic:
1498 return arithmetic_imagefilter(rand);
1499 case ImageFilterType::kBlendMode:
1500 return blendmode_imagefilter(rand);
1501 case ImageFilterType::kRuntimeBlender:
1502 return runtime_blender_imagefilter(rand);
1503 case ImageFilterType::kBlur:
1504 return blur_imagefilter(rand);
1505 case ImageFilterType::kColorFilter:
1506 return colorfilter_imagefilter(rand);
1507 case ImageFilterType::kDisplacement:
1508 return displacement_imagefilter(recorder, rand);
1509 case ImageFilterType::kLighting:
1510 return lighting_imagefilter(rand);
1511 case ImageFilterType::kMatrixConvolution:
1512 return matrix_convolution_imagefilter(rand);
1513 case ImageFilterType::kMorphology:
1514 return morphology_imagefilter(rand);
1515 }
1516
1517 SkUNREACHABLE;
1518 }
1519
create_random_image_filter(Recorder * recorder,SkRandom * rand)1520 std::pair<sk_sp<SkImageFilter>, sk_sp<PrecompileImageFilter>> create_random_image_filter(
1521 Recorder* recorder,
1522 SkRandom* rand) {
1523 return create_image_filter(recorder, rand, random_imagefiltertype(rand));
1524 }
1525
create_blur_maskfilter(SkRandom * rand)1526 std::pair<sk_sp<SkMaskFilter>, sk_sp<PrecompileMaskFilter>> create_blur_maskfilter(SkRandom* rand) {
1527 SkBlurStyle style;
1528 switch (rand->nextULessThan(4)) {
1529 case 0: style = kNormal_SkBlurStyle; break;
1530 case 1: style = kSolid_SkBlurStyle; break;
1531 case 2: style = kOuter_SkBlurStyle; break;
1532 case 3: [[fallthrough]];
1533 default: style = kInner_SkBlurStyle; break;
1534 }
1535
1536 float sigma = 1.0f;
1537 switch (rand->nextULessThan(2)) {
1538 case 0: sigma = 1.0f; break;
1539 case 1: sigma = 2.0f; break;
1540 case 2: [[fallthrough]];
1541 default: sigma = 5.0f; break;
1542 }
1543
1544 bool respectCTM = rand->nextBool();
1545
1546 return { SkMaskFilter::MakeBlur(style, sigma, respectCTM), PrecompileMaskFilters::Blur() };
1547 }
1548
create_maskfilter(SkRandom * rand,MaskFilterType type)1549 std::pair<sk_sp<SkMaskFilter>, sk_sp<PrecompileMaskFilter>> create_maskfilter(SkRandom* rand,
1550 MaskFilterType type) {
1551 switch (type) {
1552 case MaskFilterType::kNone: return {nullptr, nullptr};
1553 case MaskFilterType::kBlur: return create_blur_maskfilter(rand);
1554 }
1555
1556 SkUNREACHABLE;
1557 }
1558
1559 //--------------------------------------------------------------------------------------------------
create_paint(SkRandom * rand,Recorder * recorder,ShaderType shaderType,BlenderType blenderType,ColorFilterType colorFilterType,MaskFilterType maskFilterType,ImageFilterType imageFilterType)1560 std::pair<SkPaint, PaintOptions> create_paint(SkRandom* rand,
1561 Recorder* recorder,
1562 ShaderType shaderType,
1563 BlenderType blenderType,
1564 ColorFilterType colorFilterType,
1565 MaskFilterType maskFilterType,
1566 ImageFilterType imageFilterType) {
1567 SkPaint paint;
1568 paint.setColor(random_color(rand, ColorConstraint::kOpaque));
1569
1570 PaintOptions paintOptions;
1571
1572 {
1573 auto [s, o] = create_shader(rand, recorder, shaderType);
1574 SkASSERT(!s == !o);
1575
1576 if (s) {
1577 paint.setShader(std::move(s));
1578 paintOptions.setShaders({o});
1579 }
1580 }
1581
1582 {
1583 auto [cf, o] = create_colorfilter(rand, colorFilterType);
1584 SkASSERT(!cf == !o);
1585
1586 if (cf) {
1587 paint.setColorFilter(std::move(cf));
1588 paintOptions.setColorFilters({o});
1589 }
1590 }
1591
1592 {
1593 auto [mf, o] = create_maskfilter(rand, maskFilterType);
1594 SkASSERT(!mf == !o);
1595
1596 if (mf) {
1597 paint.setMaskFilter(std::move(mf));
1598 paintOptions.setMaskFilters({o});
1599 }
1600 }
1601
1602 {
1603 auto [b, o] = create_blender(rand, blenderType);
1604 SkASSERT(!b == !o);
1605
1606 if (b) {
1607 paint.setBlender(std::move(b));
1608 paintOptions.setBlenders({o});
1609 }
1610 }
1611
1612 {
1613 auto [filter, o] = create_image_filter(recorder, rand, imageFilterType);
1614 SkASSERT(!filter == !o);
1615
1616 if (filter) {
1617 paint.setImageFilter(std::move(filter));
1618 paintOptions.setImageFilters({o});
1619 }
1620 }
1621
1622 if (rand->nextBool()) {
1623 paint.setDither(true);
1624 paintOptions.setDither(true);
1625 }
1626
1627 return { paint, paintOptions };
1628 }
1629
make_path()1630 SkPath make_path() {
1631 SkPathBuilder path;
1632 path.moveTo(0, 0);
1633 path.lineTo(8, 2);
1634 path.lineTo(16, 0);
1635 path.lineTo(14, 8);
1636 path.lineTo(16, 16);
1637 path.lineTo(8, 14);
1638 path.lineTo(0, 16);
1639 path.lineTo(2, 8);
1640 path.close();
1641 return path.detach();
1642 }
1643
1644 struct DrawData {
DrawData__anond67b56bc0111::DrawData1645 DrawData() {
1646 static constexpr int kMaskTextFontSize = 16;
1647 // A large font size can bump text to be drawn as a path.
1648 static constexpr int kPathTextFontSize = 300;
1649
1650 SkFont font(ToolUtils::DefaultPortableTypeface(), kMaskTextFontSize);
1651
1652 SkFont lcdFont(ToolUtils::DefaultPortableTypeface(), kMaskTextFontSize);
1653 lcdFont.setSubpixel(true);
1654 lcdFont.setEdging(SkFont::Edging::kSubpixelAntiAlias);
1655
1656 ToolUtils::EmojiTestSample emojiTestSample =
1657 ToolUtils::EmojiSample(ToolUtils::EmojiFontFormat::ColrV0);
1658 SkFont emojiFont(emojiTestSample.typeface);
1659
1660 SkFont pathFont(ToolUtils::DefaultPortableTypeface(), kPathTextFontSize);
1661
1662 const char text[] = "hambur1";
1663
1664 constexpr int kNumVerts = 4;
1665 constexpr SkPoint kPositions[kNumVerts] { { 0, 0 }, { 0, 16 }, { 16, 16 }, { 16, 0 } };
1666 constexpr SkColor kColors[kNumVerts] = { SK_ColorBLUE, SK_ColorGREEN,
1667 SK_ColorCYAN, SK_ColorYELLOW };
1668
1669 fPath = make_path();
1670 fBlob = SkTextBlob::MakeFromText(text, strlen(text), font);
1671 fLCDBlob = SkTextBlob::MakeFromText(text, strlen(text), lcdFont);
1672 fEmojiBlob = SkTextBlob::MakeFromText(emojiTestSample.sampleText,
1673 strlen(emojiTestSample.sampleText),
1674 emojiFont);
1675 fPathBlob = SkTextBlob::MakeFromText(text, strlen(text), pathFont);
1676
1677 fVertsWithColors = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, kNumVerts,
1678 kPositions, kPositions, kColors);
1679 fVertsWithOutColors = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, kNumVerts,
1680 kPositions, kPositions, /* colors= */ nullptr);
1681 }
1682
1683 SkPath fPath;
1684 sk_sp<SkTextBlob> fBlob;
1685 sk_sp<SkTextBlob> fLCDBlob;
1686 sk_sp<SkTextBlob> fEmojiBlob;
1687 sk_sp<SkTextBlob> fPathBlob;
1688 sk_sp<SkVertices> fVertsWithColors;
1689 sk_sp<SkVertices> fVertsWithOutColors;
1690 };
1691
simple_draws(SkCanvas * canvas,const SkPaint & paint)1692 void simple_draws(SkCanvas* canvas, const SkPaint& paint) {
1693 // TODO: add some drawLine calls
1694 canvas->drawRect(SkRect::MakeWH(16, 16), paint);
1695 canvas->drawRRect(SkRRect::MakeOval({0, 0, 16, 16}), paint);
1696 canvas->drawRRect(SkRRect::MakeRectXY({0, 0, 16, 16}, 4, 4), paint);
1697
1698 // TODO: add a case that uses the SkCanvas::experimental_DrawEdgeAAImageSet entry point
1699 if (!paint.getShader() &&
1700 !paint.getColorFilter() &&
1701 !paint.getImageFilter() &&
1702 paint.asBlendMode().has_value()) {
1703 // The SkPaint reconstructed inside the drawEdgeAAQuad call needs to match 'paint' for
1704 // the precompilation checks to work.
1705 canvas->experimental_DrawEdgeAAQuad(SkRect::MakeWH(16, 16),
1706 /* clip= */ nullptr,
1707 SkCanvas::kAll_QuadAAFlags,
1708 paint.getColor4f(),
1709 paint.asBlendMode().value());
1710 }
1711 }
1712
non_simple_draws(SkCanvas * canvas,const SkPaint & paint,const DrawData & drawData)1713 void non_simple_draws(SkCanvas* canvas, const SkPaint& paint, const DrawData& drawData) {
1714 // TODO: add strokeAndFill draws here as well as a stroked non-circular rrect draw
1715 canvas->drawPath(drawData.fPath, paint);
1716 canvas->drawTextBlob(drawData.fPathBlob, 0, 16, paint);
1717 if (paint.getStyle() == SkPaint::kStroke_Style) {
1718 canvas->drawArc({0, 0, 16, 16}, 0, 90, /* useCenter= */ true, paint);
1719 }
1720 }
1721
1722 #ifdef SK_DEBUG
dump_keys(PrecompileContext * precompileContext,const std::vector<skgpu::UniqueKey> & needleKeys,const std::vector<skgpu::UniqueKey> & hayStackKeys,const char * needleName,const char * haystackName)1723 void dump_keys(PrecompileContext* precompileContext,
1724 const std::vector<skgpu::UniqueKey>& needleKeys,
1725 const std::vector<skgpu::UniqueKey>& hayStackKeys,
1726 const char* needleName,
1727 const char* haystackName) {
1728
1729 SkDebugf("-------------------------- %zu %s pipelines\n", needleKeys.size(), needleName);
1730
1731 int count = 0;
1732 for (const skgpu::UniqueKey& k : needleKeys) {
1733 bool found = std::find(hayStackKeys.begin(), hayStackKeys.end(), k) != hayStackKeys.end();
1734
1735 GraphicsPipelineDesc originalPipelineDesc;
1736 RenderPassDesc originalRenderPassDesc;
1737 UniqueKeyUtils::ExtractKeyDescs(precompileContext, k,
1738 &originalPipelineDesc,
1739 &originalRenderPassDesc);
1740
1741 SkString label;
1742 label.appendf("--- %s key %d (%s in %s):\n",
1743 needleName, count++, found ? "found" : "not-found", haystackName);
1744 k.dump(label.c_str());
1745 UniqueKeyUtils::DumpDescs(precompileContext,
1746 originalPipelineDesc,
1747 originalRenderPassDesc);
1748 }
1749 }
1750 #endif
1751
check_draw(skiatest::Reporter * reporter,Context * context,PrecompileContext * precompileContext,skiatest::graphite::GraphiteTestContext * testContext,Recorder * recorder,const SkPaint & paint,DrawTypeFlags dt,ClipType clip,sk_sp<SkShader> clipShader)1752 void check_draw(skiatest::Reporter* reporter,
1753 Context* context,
1754 PrecompileContext* precompileContext,
1755 skiatest::graphite::GraphiteTestContext* testContext,
1756 Recorder* recorder,
1757 const SkPaint& paint,
1758 DrawTypeFlags dt,
1759 ClipType clip,
1760 sk_sp<SkShader> clipShader) {
1761 static const DrawData kDrawData;
1762
1763 std::vector<skgpu::UniqueKey> precompileKeys, drawKeys;
1764
1765 UniqueKeyUtils::FetchUniqueKeys(precompileContext, &precompileKeys);
1766
1767 precompileContext->priv().globalCache()->resetGraphicsPipelines();
1768
1769 {
1770 // TODO: vary the colorType of the target surface too
1771 SkImageInfo ii = SkImageInfo::Make(16, 16,
1772 kBGRA_8888_SkColorType,
1773 kPremul_SkAlphaType);
1774
1775 SkSurfaceProps props;
1776
1777 if (dt == DrawTypeFlags::kBitmapText_LCD || dt == DrawTypeFlags::kSDFText_LCD) {
1778 props = SkSurfaceProps(/* flags= */ 0x0, SkPixelGeometry::kRGB_H_SkPixelGeometry);
1779 }
1780
1781 sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, ii,
1782 skgpu::Mipmapped::kNo,
1783 &props);
1784 SkCanvas* canvas = surf->getCanvas();
1785
1786 switch (clip) {
1787 case ClipType::kNone:
1788 break;
1789 case ClipType::kShader:
1790 SkASSERT(clipShader);
1791 canvas->clipShader(clipShader, SkClipOp::kIntersect);
1792 break;
1793 case ClipType::kShader_Diff:
1794 SkASSERT(clipShader);
1795 canvas->clipShader(clipShader, SkClipOp::kDifference);
1796 break;
1797 }
1798
1799 switch (dt) {
1800 case DrawTypeFlags::kBitmapText_Mask:
1801 canvas->drawTextBlob(kDrawData.fBlob, 0, 16, paint);
1802 break;
1803 case DrawTypeFlags::kBitmapText_LCD:
1804 canvas->drawTextBlob(kDrawData.fLCDBlob, 0, 16, paint);
1805 break;
1806 case DrawTypeFlags::kBitmapText_Color:
1807 canvas->drawTextBlob(kDrawData.fEmojiBlob, 0, 16, paint);
1808 break;
1809 case DrawTypeFlags::kSDFText: {
1810 SkMatrix perspective;
1811 perspective.setPerspX(0.01f);
1812 perspective.setPerspY(0.001f);
1813 canvas->save();
1814 canvas->concat(perspective);
1815 canvas->drawTextBlob(kDrawData.fBlob, 0, 16, paint);
1816 canvas->restore();
1817 } break;
1818 case DrawTypeFlags::kSDFText_LCD: {
1819 SkMatrix perspective;
1820 perspective.setPerspX(0.01f);
1821 perspective.setPerspY(0.001f);
1822 canvas->save();
1823 canvas->concat(perspective);
1824 canvas->drawTextBlob(kDrawData.fLCDBlob, 0, 16, paint);
1825 canvas->restore();
1826 } break;
1827 case DrawTypeFlags::kDrawVertices:
1828 canvas->drawVertices(kDrawData.fVertsWithColors, SkBlendMode::kDst, paint);
1829 canvas->drawVertices(kDrawData.fVertsWithOutColors, SkBlendMode::kDst, paint);
1830 break;
1831 case DrawTypeFlags::kCircularArc:
1832 canvas->drawArc({0, 0, 16, 16}, 0, 90, /* useCenter= */ false, paint);
1833 if (paint.getStyle() == SkPaint::kFill_Style) {
1834 canvas->drawArc({0, 0, 16, 16}, 0, 90, /* useCenter= */ true, paint);
1835 }
1836 break;
1837 case DrawTypeFlags::kSimpleShape:
1838 simple_draws(canvas, paint);
1839 break;
1840 case DrawTypeFlags::kNonSimpleShape:
1841 non_simple_draws(canvas, paint, kDrawData);
1842 break;
1843 default:
1844 SkASSERT(false);
1845 break;
1846 }
1847
1848 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
1849 context->insertRecording({ recording.get() });
1850 testContext->syncedSubmit(context);
1851 }
1852
1853 UniqueKeyUtils::FetchUniqueKeys(precompileContext, &drawKeys);
1854
1855 // Actually using the SkPaint with the specified type of draw shouldn't have added
1856 // any additional pipelines
1857 int missingPipelines = 0;
1858 for (const skgpu::UniqueKey& k : drawKeys) {
1859 bool found =
1860 std::find(precompileKeys.begin(), precompileKeys.end(), k) != precompileKeys.end();
1861 if (!found) {
1862 ++missingPipelines;
1863 }
1864 }
1865
1866 REPORTER_ASSERT(reporter, missingPipelines == 0,
1867 "precompile pipelines: %zu draw pipelines: %zu - %d missing from precompile",
1868 precompileKeys.size(), drawKeys.size(), missingPipelines);
1869 #ifdef SK_DEBUG
1870 if (missingPipelines) {
1871 dump_keys(precompileContext, drawKeys, precompileKeys, "draw", "precompile");
1872 dump_keys(precompileContext, precompileKeys, drawKeys, "precompile", "draw");
1873 }
1874 #endif // SK_DEBUG
1875
1876 }
1877
create_key_context(Context * context,RuntimeEffectDictionary * rtDict)1878 KeyContext create_key_context(Context* context, RuntimeEffectDictionary* rtDict) {
1879 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1880
1881 SkColorInfo destColorInfo = SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType,
1882 SkColorSpace::MakeSRGB());
1883 return KeyContext(context->priv().caps(),
1884 dict,
1885 rtDict,
1886 destColorInfo);
1887 }
1888
1889 // This subtest compares the output of ExtractPaintData (applied to an SkPaint) and
1890 // PaintOptions::buildCombinations (applied to a matching PaintOptions). The actual check
1891 // performed is that the UniquePaintParamsID created by ExtractPaintData is contained in the
1892 // set of IDs generated by buildCombinations.
1893 [[maybe_unused]]
extract_vs_build_subtest(skiatest::Reporter * reporter,Context * context,skiatest::graphite::GraphiteTestContext *,const KeyContext & precompileKeyContext,Recorder * recorder,const SkPaint & paint,const PaintOptions & paintOptions,ShaderType s,BlenderType bm,ColorFilterType cf,MaskFilterType mf,ImageFilterType imageFilter,ClipType clip,sk_sp<SkShader> clipShader,DrawTypeFlags dt,uint32_t seed,SkRandom * rand,bool verbose)1894 void extract_vs_build_subtest(skiatest::Reporter* reporter,
1895 Context* context,
1896 skiatest::graphite::GraphiteTestContext* /* testContext */,
1897 const KeyContext& precompileKeyContext,
1898 Recorder* recorder,
1899 const SkPaint& paint,
1900 const PaintOptions& paintOptions,
1901 ShaderType s,
1902 BlenderType bm,
1903 ColorFilterType cf,
1904 MaskFilterType mf,
1905 ImageFilterType imageFilter,
1906 ClipType clip,
1907 sk_sp<SkShader> clipShader,
1908 DrawTypeFlags dt,
1909 uint32_t seed,
1910 SkRandom* rand,
1911 bool verbose) {
1912
1913 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
1914
1915 PaintParamsKeyBuilder builder(dict);
1916 PipelineDataGatherer paramsGatherer(Layout::kMetal);
1917 PipelineDataGatherer precompileGatherer(Layout::kMetal);
1918
1919 for (bool withPrimitiveBlender: {false, true}) {
1920
1921 sk_sp<SkBlender> primitiveBlender;
1922 if (withPrimitiveBlender) {
1923 if (dt != DrawTypeFlags::kDrawVertices) {
1924 // Only drawVertices calls need a primitive blender
1925 continue;
1926 }
1927
1928 primitiveBlender = SkBlender::Mode(SkBlendMode::kSrcOver);
1929 }
1930
1931 constexpr Coverage coverageOptions[3] = {
1932 Coverage::kNone, Coverage::kSingleChannel, Coverage::kLCD
1933 };
1934 Coverage coverage = coverageOptions[rand->nextULessThan(3)];
1935
1936 const SkBlenderBase* blender = as_BB(paint.getBlender());
1937 bool dstReadRequired = blender ? IsDstReadRequired(recorder->priv().caps(),
1938 blender->asBlendMode(),
1939 coverage)
1940 : false;
1941
1942 // In the normal API this modification happens in SkDevice::clipShader()
1943 // All clipShaders get wrapped in a CTMShader
1944 sk_sp<SkShader> modifiedClipShader = clipShader
1945 ? as_SB(clipShader)->makeWithCTM(SkMatrix::I())
1946 : nullptr;
1947 if (clip == ClipType::kShader_Diff && modifiedClipShader) {
1948 // The CTMShader gets further wrapped in a ColorFilterShader for kDifference clips
1949 modifiedClipShader = modifiedClipShader->makeWithColorFilter(
1950 SkColorFilters::Blend(0xFFFFFFFF, SkBlendMode::kSrcOut));
1951 }
1952
1953 UniquePaintParamsID paintID =
1954 ExtractPaintData(recorder,
1955 ¶msGatherer,
1956 &builder,
1957 Layout::kMetal,
1958 {},
1959 PaintParams(paint,
1960 primitiveBlender,
1961 {}, // TODO (jvanverth): add analytic clip to test
1962 std::move(modifiedClipShader),
1963 dstReadRequired,
1964 /* skipColorXform= */ false),
1965 {},
1966 precompileKeyContext.dstColorInfo());
1967
1968 RenderPassDesc unusedRenderPassDesc;
1969
1970 std::vector<UniquePaintParamsID> precompileIDs;
1971 paintOptions.priv().buildCombinations(precompileKeyContext,
1972 &precompileGatherer,
1973 DrawTypeFlags::kNone,
1974 withPrimitiveBlender,
1975 coverage,
1976 unusedRenderPassDesc,
1977 [&precompileIDs](UniquePaintParamsID id,
1978 DrawTypeFlags,
1979 bool /* withPrimitiveBlender */,
1980 Coverage,
1981 const RenderPassDesc&) {
1982 precompileIDs.push_back(id);
1983 });
1984
1985 if (verbose) {
1986 SkDebugf("Precompilation generated %zu unique keys\n", precompileIDs.size());
1987 }
1988
1989 // Although we've gathered both sets of uniforms (i.e., from the paint
1990 // params and the precompilation paths) we can't compare the two since the
1991 // precompilation path may have generated multiple sets
1992 // and the last one created may not be the one that matches the paint
1993 // params' set. Additionally, for runtime effects we just skip gathering
1994 // the uniforms in the precompilation path.
1995
1996 // The specific key generated by ExtractPaintData should be one of the
1997 // combinations generated by the combination system.
1998 auto result = std::find(precompileIDs.begin(), precompileIDs.end(), paintID);
1999
2000 if (result == precompileIDs.end()) {
2001 log_run("Failure on case", seed, s, bm, cf, mf, imageFilter, clip, dt);
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
2020 // This subtest verifies that, given an equivalent SkPaint and PaintOptions, the
2021 // Precompile system will, at least, generate all the pipelines a real draw would generate.
precompile_vs_real_draws_subtest(skiatest::Reporter * reporter,Context * context,PrecompileContext * precompileContext,skiatest::graphite::GraphiteTestContext * testContext,Recorder * recorder,const SkPaint & paint,const PaintOptions & paintOptions,ClipType clip,sk_sp<SkShader> clipShader,DrawTypeFlags dt,bool)2022 void precompile_vs_real_draws_subtest(skiatest::Reporter* reporter,
2023 Context* context,
2024 PrecompileContext* precompileContext,
2025 skiatest::graphite::GraphiteTestContext* testContext,
2026 Recorder* recorder,
2027 const SkPaint& paint,
2028 const PaintOptions& paintOptions,
2029 ClipType clip,
2030 sk_sp<SkShader> clipShader,
2031 DrawTypeFlags dt,
2032 bool /* verbose */) {
2033 GlobalCache* globalCache = precompileContext->priv().globalCache();
2034
2035 globalCache->resetGraphicsPipelines();
2036
2037 const skgpu::graphite::Caps* caps = context->priv().caps();
2038
2039 const SkColorType kColorType = kBGRA_8888_SkColorType;
2040
2041 static const RenderPassProperties kDepth_Stencil_4 { DepthStencilFlags::kDepthStencil,
2042 kColorType,
2043 /* dstColorSpace= */ nullptr,
2044 /* requiresMSAA= */ true };
2045 static const RenderPassProperties kDepth_1 { DepthStencilFlags::kDepth,
2046 kColorType,
2047 /* dstColorSpace= */ nullptr,
2048 /* requiresMSAA= */ false };
2049
2050 TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(kColorType,
2051 skgpu::Mipmapped::kNo,
2052 skgpu::Protected::kNo,
2053 skgpu::Renderable::kYes);
2054
2055 TextureInfo msaaTex = caps->getDefaultMSAATextureInfo(textureInfo, Discardable::kYes);
2056
2057 bool vello = false;
2058 #ifdef SK_ENABLE_VELLO_SHADERS
2059 vello = caps->computeSupport();
2060 #endif
2061
2062 // Using Vello skips using MSAA for complex paths. Additionally, Intel Macs avoid MSAA
2063 // in favor of path rendering.
2064 const RenderPassProperties* pathProperties = (msaaTex.numSamples() > 1 && !vello)
2065 ? &kDepth_Stencil_4
2066 : &kDepth_1;
2067
2068 int before = globalCache->numGraphicsPipelines();
2069 Precompile(precompileContext, paintOptions, dt,
2070 dt == kNonSimpleShape ? SkSpan(pathProperties, 1) : SkSpan(&kDepth_1, 1));
2071 if (gNeedSKPPaintOption) {
2072 // The skp draws a rect w/ a default SkPaint and RGBA dst color type
2073 PaintOptions skpPaintOptions;
2074 Precompile(precompileContext, skpPaintOptions, DrawTypeFlags::kSimpleShape,
2075 { { kDepth_1.fDSFlags, kRGBA_8888_SkColorType, kDepth_1.fDstCS,
2076 kDepth_1.fRequiresMSAA } });
2077 }
2078 int after = globalCache->numGraphicsPipelines();
2079
2080 REPORTER_ASSERT(reporter, before == 0);
2081 REPORTER_ASSERT(reporter, after > before);
2082
2083 check_draw(reporter,
2084 context,
2085 precompileContext,
2086 testContext,
2087 recorder,
2088 paint,
2089 dt,
2090 clip,
2091 clipShader);
2092 }
2093
run_test(skiatest::Reporter * reporter,Context * context,PrecompileContext * precompileContext,skiatest::graphite::GraphiteTestContext * testContext,const KeyContext & precompileKeyContext,ShaderType s,BlenderType bm,ColorFilterType cf,MaskFilterType mf,ImageFilterType imageFilter,ClipType clip,DrawTypeFlags dt,uint32_t seed,bool verbose)2094 void run_test(skiatest::Reporter* reporter,
2095 Context* context,
2096 PrecompileContext* precompileContext,
2097 skiatest::graphite::GraphiteTestContext* testContext,
2098 const KeyContext& precompileKeyContext,
2099 ShaderType s,
2100 BlenderType bm,
2101 ColorFilterType cf,
2102 MaskFilterType mf,
2103 ImageFilterType imageFilter,
2104 ClipType clip,
2105 DrawTypeFlags dt,
2106 uint32_t seed,
2107 bool verbose) {
2108 SkRandom rand(seed);
2109
2110 std::unique_ptr<Recorder> recorder = context->makeRecorder();
2111
2112 sk_sp<SkShader> clipShader;
2113 sk_sp<PrecompileShader> clipShaderOption;
2114
2115 if (clip == ClipType::kShader || clip == ClipType::kShader_Diff) {
2116 std::tie(clipShader, clipShaderOption) = create_clip_shader(&rand, recorder.get());
2117 SkASSERT(!clipShader == !clipShaderOption);
2118 }
2119
2120 gNeedSKPPaintOption = false;
2121 auto [paint, paintOptions] = create_paint(&rand, recorder.get(), s, bm, cf, mf, imageFilter);
2122
2123 // The PaintOptions' clipShader can be handled here while the SkPaint's clipShader handling
2124 // must be performed later (in ExtractPaintData or when an SkCanvas is accessible for
2125 // a SkCanvas::clipShader call).
2126 paintOptions.priv().setClipShaders({clipShaderOption});
2127
2128 extract_vs_build_subtest(reporter, context, testContext, precompileKeyContext, recorder.get(),
2129 paint, paintOptions, s, bm, cf, mf, imageFilter, clip, clipShader, dt,
2130 seed, &rand, verbose);
2131 precompile_vs_real_draws_subtest(reporter, context, precompileContext,
2132 testContext, recorder.get(),
2133 paint, paintOptions, clip, clipShader, dt, verbose);
2134 }
2135
2136 } // anonymous namespace
2137
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTestReduced,reporter,context,testContext,true,CtsEnforcement::kNever)2138 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTestReduced,
2139 reporter,
2140 context,
2141 testContext,
2142 true,
2143 CtsEnforcement::kNever) {
2144 std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
2145 std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
2146
2147 #if 1
2148 //----------------------
2149 uint32_t seed = std::time(nullptr) % std::numeric_limits<uint32_t>::max();
2150 SkRandom rand(seed);
2151 ShaderType shaderType = random_shadertype(&rand);
2152 BlenderType blenderType = random_blendertype(&rand);
2153 ColorFilterType colorFilterType = random_colorfiltertype(&rand);
2154 MaskFilterType maskFilterType = random_maskfiltertype(&rand);
2155 ImageFilterType imageFilterType = ImageFilterType::kNone; // random_imagefiltertype(&rand);
2156 ClipType clipType = random_cliptype(&rand);
2157 DrawTypeFlags drawTypeFlags = random_drawtype(&rand);
2158 //----------------------
2159 #else
2160 //------------------------
2161 uint32_t seed = 1721227069;
2162 ShaderType shaderType = ShaderType::kLocalMatrix;
2163 BlenderType blenderType = BlenderType::kArithmetic;
2164 ColorFilterType colorFilterType = ColorFilterType::kRuntime;
2165 MaskFilterType maskFilterType = MaskFilterType::kNone;
2166 ImageFilterType imageFilterType = ImageFilterType::kDisplacement;
2167 ClipType clipType = ClipType::kNone;
2168 DrawTypeFlags drawTypeFlags = DrawTypeFlags::kText;
2169 //-----------------------
2170 #endif
2171
2172 SkString logMsg("Running ");
2173 logMsg += BackendApiToStr(context->backend());
2174
2175 log_run(logMsg.c_str(), seed, shaderType, blenderType, colorFilterType, maskFilterType,
2176 imageFilterType, clipType, drawTypeFlags);
2177
2178 run_test(reporter,
2179 context,
2180 precompileContext.get(),
2181 testContext,
2182 create_key_context(context, rtDict.get()),
2183 shaderType,
2184 blenderType,
2185 colorFilterType,
2186 maskFilterType,
2187 imageFilterType,
2188 clipType,
2189 drawTypeFlags,
2190 seed,
2191 /* verbose= */ true);
2192 }
2193
2194 // This is intended to be a smoke test for the agreement between the two ways of creating a
2195 // PaintParamsKey:
2196 // via ExtractPaintData (i.e., from an SkPaint)
2197 // and via the pre-compilation system
2198 //
2199 // TODO: keep this as a smoke test but add a fuzzer that reuses all the helpers
2200 // TODO(b/306174708): enable in SkQP (if it's feasible)
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTest,reporter,context,testContext,true,CtsEnforcement::kNever)2201 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTest,
2202 reporter,
2203 context,
2204 testContext,
2205 true,
2206 CtsEnforcement::kNever) {
2207 std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
2208 std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
2209
2210 KeyContext precompileKeyContext(create_key_context(context, rtDict.get()));
2211
2212 ShaderType shaders[] = {
2213 ShaderType::kBlend,
2214 ShaderType::kImage,
2215 ShaderType::kRadialGradient,
2216 ShaderType::kSolidColor,
2217 #if EXPANDED_SET
2218 ShaderType::kNone,
2219 ShaderType::kColorFilter,
2220 ShaderType::kCoordClamp,
2221 ShaderType::kConicalGradient,
2222 ShaderType::kLinearGradient,
2223 ShaderType::kLocalMatrix,
2224 ShaderType::kPerlinNoise,
2225 ShaderType::kPicture,
2226 ShaderType::kRuntime,
2227 ShaderType::kSweepGradient,
2228 ShaderType::kYUVImage,
2229 ShaderType::kWorkingColorSpace,
2230 #endif
2231 };
2232
2233 BlenderType blenders[] = {
2234 BlenderType::kPorterDuff,
2235 BlenderType::kShaderBased,
2236 BlenderType::kRuntime,
2237 #if EXPANDED_SET
2238 BlenderType::kNone,
2239 BlenderType::kArithmetic,
2240 #endif
2241 };
2242
2243 ColorFilterType colorFilters[] = {
2244 ColorFilterType::kNone,
2245 ColorFilterType::kBlendMode,
2246 ColorFilterType::kMatrix,
2247 #if EXPANDED_SET
2248 ColorFilterType::kColorSpaceXform,
2249 ColorFilterType::kCompose,
2250 ColorFilterType::kGaussian,
2251 ColorFilterType::kHighContrast,
2252 ColorFilterType::kHSLAMatrix,
2253 ColorFilterType::kLerp,
2254 ColorFilterType::kLighting,
2255 ColorFilterType::kLinearToSRGB,
2256 ColorFilterType::kLuma,
2257 ColorFilterType::kOverdraw,
2258 ColorFilterType::kRuntime,
2259 ColorFilterType::kSRGBToLinear,
2260 ColorFilterType::kTable,
2261 ColorFilterType::kWorkingFormat,
2262 #endif
2263 };
2264
2265 MaskFilterType maskFilters[] = {
2266 MaskFilterType::kNone,
2267 #if EXPANDED_SET
2268 MaskFilterType::kBlur,
2269 #endif
2270 };
2271
2272 ImageFilterType imageFilters[] = {
2273 ImageFilterType::kNone,
2274 #if EXPANDED_SET
2275 ImageFilterType::kArithmetic,
2276 ImageFilterType::kBlendMode,
2277 ImageFilterType::kRuntimeBlender,
2278 ImageFilterType::kBlur,
2279 ImageFilterType::kColorFilter,
2280 ImageFilterType::kDisplacement,
2281 ImageFilterType::kLighting,
2282 ImageFilterType::kMatrixConvolution,
2283 ImageFilterType::kMorphology,
2284 #endif
2285 };
2286
2287 ClipType clips[] = {
2288 ClipType::kNone,
2289 #if EXPANDED_SET
2290 ClipType::kShader, // w/ a SkClipOp::kIntersect
2291 ClipType::kShader_Diff, // w/ a SkClipOp::kDifference
2292 #endif
2293 };
2294
2295 static const DrawTypeFlags kDrawTypeFlags[] = {
2296 DrawTypeFlags::kBitmapText_Mask,
2297 DrawTypeFlags::kBitmapText_LCD,
2298 DrawTypeFlags::kBitmapText_Color,
2299 DrawTypeFlags::kSDFText,
2300 DrawTypeFlags::kSDFText_LCD,
2301 DrawTypeFlags::kDrawVertices,
2302 DrawTypeFlags::kCircularArc,
2303 DrawTypeFlags::kSimpleShape,
2304 DrawTypeFlags::kNonSimpleShape,
2305 };
2306
2307 #if EXPANDED_SET
2308 size_t kExpected = std::size(shaders) * std::size(blenders) * std::size(colorFilters) *
2309 std::size(maskFilters) * std::size(imageFilters) * std::size(clips) *
2310 std::size(kDrawTypeFlags);
2311 int current = 0;
2312 #endif
2313
2314 for (auto shader : shaders) {
2315 for (auto blender : blenders) {
2316 for (auto cf : colorFilters) {
2317 for (auto mf : maskFilters) {
2318 for (auto imageFilter : imageFilters) {
2319 for (auto clip : clips) {
2320 for (DrawTypeFlags dt : kDrawTypeFlags) {
2321 #if EXPANDED_SET
2322 SkDebugf("%d/%zu\n", current, kExpected);
2323 ++current;
2324 #endif
2325
2326 run_test(reporter, context, precompileContext.get(),
2327 testContext, precompileKeyContext,
2328 shader, blender, cf, mf, imageFilter, clip, dt,
2329 kDefaultSeed, /* verbose= */ false);
2330 }
2331 }
2332 }
2333 }
2334 }
2335 }
2336 }
2337
2338 #if EXPANDED_SET
2339 SkASSERT(current == (int) kExpected);
2340 #endif
2341 }
2342
2343 #endif // SK_GRAPHITE
2344