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