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