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