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 ¶msGatherer,
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