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/SkCanvas.h"
14 #include "include/core/SkM44.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPathBuilder.h"
17 #include "include/core/SkShader.h"
18 #include "include/core/SkTextBlob.h"
19 #include "include/core/SkVertices.h"
20 #include "include/effects/SkColorMatrix.h"
21 #include "include/effects/SkGradientShader.h"
22 #include "include/effects/SkRuntimeEffect.h"
23 #include "include/gpu/graphite/Recorder.h"
24 #include "src/base/SkRandom.h"
25 #include "src/core/SkRuntimeEffectPriv.h"
26 #include "src/gpu/graphite/ContextPriv.h"
27 #include "src/gpu/graphite/ContextUtils.h"
28 #include "src/gpu/graphite/FactoryFunctions.h"
29 #include "src/gpu/graphite/KeyContext.h"
30 #include "src/gpu/graphite/KeyHelpers.h"
31 #include "src/gpu/graphite/PaintOptionsPriv.h"
32 #include "src/gpu/graphite/PaintParams.h"
33 #include "src/gpu/graphite/PipelineData.h"
34 #include "src/gpu/graphite/Precompile.h"
35 #include "src/gpu/graphite/PublicPrecompile.h"
36 #include "src/gpu/graphite/RecorderPriv.h"
37 #include "src/gpu/graphite/ResourceProvider.h"
38 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
39 #include "src/gpu/graphite/ShaderCodeDictionary.h"
40 #include "src/gpu/graphite/UniquePaintParamsID.h"
41 #include "src/shaders/SkImageShader.h"
42 #include "tools/ToolUtils.h"
43 
44 using namespace skgpu::graphite;
45 
46 namespace {
47 
48 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom*, Recorder*);
49 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom*);
50 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(SkRandom*);
51 
52 enum class ShaderType {
53     kNone,
54     kSolidColor,
55     kLinearGradient,
56     kRadialGradient,
57     kSweepGradient,
58     kConicalGradient,
59     kLocalMatrix,
60     kColorFilter,
61     kImage,
62     kBlend,
63 
64     kLast          = kBlend
65 };
66 
67 static constexpr int kShaderTypeCount = static_cast<int>(ShaderType::kLast) + 1;
68 
69 // TODO: do we need to add a separable category and/or a category for dstRead requiring blends?
70 enum class BlenderType {
71     kNone,
72     kPorterDuff,
73     kShaderBased,
74     kRuntime,
75 
76     kLast = kRuntime
77 };
78 
79 static constexpr int kBlenderTypeCount = static_cast<int>(BlenderType::kLast) + 1;
80 
81 enum class ColorFilterType {
82     kNone,
83     kBlend,
84     kMatrix,
85     kHSLAMatrix,
86     // TODO: add more color filters
87 
88     kLast = kHSLAMatrix
89 };
90 
91 static constexpr int kColorFilterTypeCount = static_cast<int>(ColorFilterType::kLast) + 1;
92 
93 static constexpr skcms_TransferFunction gTransferFunctions[] = {
94     SkNamedTransferFn::kSRGB,
95     SkNamedTransferFn::k2Dot2,
96     SkNamedTransferFn::kLinear,
97     SkNamedTransferFn::kRec2020,
98     SkNamedTransferFn::kPQ,
99     SkNamedTransferFn::kHLG,
100 };
101 
102 static constexpr int kTransferFunctionCount = std::size(gTransferFunctions);
103 
104 static constexpr skcms_Matrix3x3 gGamuts[] = {
105     SkNamedGamut::kSRGB,
106     SkNamedGamut::kAdobeRGB,
107     SkNamedGamut::kDisplayP3,
108     SkNamedGamut::kRec2020,
109     SkNamedGamut::kXYZ,
110 };
111 
112 static constexpr int kGamutCount = std::size(gGamuts);
113 
114 enum class ColorSpaceType {
115     kNone,
116     kSRGB,
117     kSRGBLinear,
118     kRGB,
119 
120     kLast = kRGB
121 };
122 
123 static constexpr int kColorSpaceTypeCount = static_cast<int>(ColorSpaceType::kLast) + 1;
124 
random_colorspacetype(SkRandom * rand)125 ColorSpaceType random_colorspacetype(SkRandom* rand) {
126     return static_cast<ColorSpaceType>(rand->nextULessThan(kColorSpaceTypeCount));
127 }
128 
random_colorspace(SkRandom * rand)129 sk_sp<SkColorSpace> random_colorspace(SkRandom* rand) {
130     ColorSpaceType cs = random_colorspacetype(rand);
131 
132     switch (cs) {
133         case ColorSpaceType::kNone:
134             return nullptr;
135         case ColorSpaceType::kSRGB:
136             return SkColorSpace::MakeSRGB();
137         case ColorSpaceType::kSRGBLinear:
138             return SkColorSpace::MakeSRGBLinear();
139         case ColorSpaceType::kRGB:
140             return SkColorSpace::MakeRGB(
141                     gTransferFunctions[rand->nextULessThan(kTransferFunctionCount)],
142                     gGamuts[rand->nextULessThan(kGamutCount)]);
143     }
144 
145     SkUNREACHABLE;
146 }
147 
148 
random_opaque_color(SkRandom * rand)149 SkColor random_opaque_color(SkRandom* rand) {
150     return 0xff000000 | rand->nextU();
151 }
152 
random_color(SkRandom * rand)153 SkColor4f random_color(SkRandom* rand) {
154     SkColor4f result = { rand->nextRangeF(0.0f, 1.0f),
155                          rand->nextRangeF(0.0f, 1.0f),
156                          rand->nextRangeF(0.0f, 1.0f),
157                          rand->nextRangeF(0.0f, 1.0f) };
158 
159     if (rand->nextBool()) {
160         result.fA = 1.0f;
161     }
162 
163     return result;
164 }
165 
random_tilemode(SkRandom * rand)166 SkTileMode random_tilemode(SkRandom* rand) {
167     return static_cast<SkTileMode>(rand->nextULessThan(kSkTileModeCount));
168 }
169 
random_shadertype(SkRandom * rand)170 ShaderType random_shadertype(SkRandom* rand) {
171     return static_cast<ShaderType>(rand->nextULessThan(kShaderTypeCount));
172 }
173 
random_porter_duff_bm(SkRandom * rand)174 SkBlendMode random_porter_duff_bm(SkRandom* rand) {
175     return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kClear,
176                                                      (unsigned int) SkBlendMode::kLastCoeffMode));
177 }
178 
random_complex_bm(SkRandom * rand)179 SkBlendMode random_complex_bm(SkRandom* rand) {
180     return static_cast<SkBlendMode>(rand->nextRangeU((unsigned int) SkBlendMode::kLastCoeffMode,
181                                                      (unsigned int) SkBlendMode::kLastMode));
182 }
183 
random_blend_mode(SkRandom * rand)184 SkBlendMode random_blend_mode(SkRandom* rand) {
185     return static_cast<SkBlendMode>(rand->nextULessThan(kSkBlendModeCount));
186 }
187 
random_blendertype(SkRandom * rand)188 BlenderType random_blendertype(SkRandom* rand) {
189     return static_cast<BlenderType>(rand->nextULessThan(kBlenderTypeCount));
190 }
191 
random_colorfiltertype(SkRandom * rand)192 ColorFilterType random_colorfiltertype(SkRandom* rand) {
193     return static_cast<ColorFilterType>(rand->nextULessThan(kColorFilterTypeCount));
194 }
195 
make_image(SkRandom * rand,Recorder * recorder)196 sk_sp<SkImage> make_image(SkRandom* rand, Recorder* recorder) {
197     // TODO: add alpha-only images too
198     SkImageInfo info = SkImageInfo::Make(32, 32,
199                                          SkColorType::kRGBA_8888_SkColorType,
200                                          kPremul_SkAlphaType,
201                                          random_colorspace(rand));
202 
203     SkBitmap bitmap;
204     bitmap.allocPixels(info);
205     bitmap.eraseColor(SK_ColorBLACK);
206 
207     sk_sp<SkImage> img = bitmap.asImage();
208 
209     // TODO: fuzz mipmappedness
210     return img->makeTextureImage(recorder, { skgpu::Mipmapped::kNo });
211 }
212 
213 //--------------------------------------------------------------------------------------------------
create_solid_shader(SkRandom * rand)214 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_solid_shader(SkRandom* rand) {
215     sk_sp<SkShader> s = SkShaders::Color(random_opaque_color(rand));
216     sk_sp<PrecompileShader> o = PrecompileShaders::Color();
217 
218     return { s, o };
219 }
220 
create_gradient_shader(SkRandom * rand,SkShaderBase::GradientType type)221 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_gradient_shader(
222         SkRandom* rand,
223         SkShaderBase::GradientType type) {
224     // TODO: fuzz the gradient parameters - esp. the number of stops & hard stops
225     SkPoint pts[2] = {{-100, -100},
226                       {100,  100}};
227     SkColor colors[2] = {SK_ColorRED, SK_ColorGREEN};
228     SkScalar offsets[2] = {0.0f, 1.0f};
229 
230     sk_sp<SkShader> s;
231     sk_sp<PrecompileShader> o;
232 
233     SkTileMode tm = random_tilemode(rand);
234 
235     switch (type) {
236         case SkShaderBase::GradientType::kLinear:
237             s = SkGradientShader::MakeLinear(pts, colors, offsets, 2, tm);
238             o = PrecompileShaders::LinearGradient();
239             break;
240         case SkShaderBase::GradientType::kRadial:
241             s = SkGradientShader::MakeRadial({0, 0}, 100, colors, offsets, 2, tm);
242             o = PrecompileShaders::RadialGradient();
243             break;
244         case SkShaderBase::GradientType::kSweep:
245             s = SkGradientShader::MakeSweep(0, 0, colors, offsets, 2, tm,
246                                             0, 359, 0, nullptr);
247             o = PrecompileShaders::SweepGradient();
248             break;
249         case SkShaderBase::GradientType::kConical:
250             s = SkGradientShader::MakeTwoPointConical({100, 100}, 100,
251                                                       {-100, -100}, 100,
252                                                       colors, offsets, 2, tm);
253             o = PrecompileShaders::TwoPointConicalGradient();
254             break;
255         case SkShaderBase::GradientType::kNone:
256         case SkShaderBase::GradientType::kColor:
257             SkASSERT(0);
258             break;
259     }
260 
261     return { s, o };
262 }
263 
create_localmatrix_shader(SkRandom * rand,Recorder * recorder)264 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_localmatrix_shader(SkRandom* rand,
265                                                                               Recorder* recorder) {
266     auto [s, o] = create_random_shader(rand, recorder);
267     SkASSERT(!s == !o);
268 
269     if (!s) {
270         return { nullptr, nullptr };
271     }
272 
273     SkMatrix tmp = SkMatrix::Scale(1.5f, 2.0f); // TODO: fuzz
274 
275     return { s->makeWithLocalMatrix(tmp), o->makeWithLocalMatrix() };
276 }
277 
create_colorfilter_shader(SkRandom * rand,Recorder * recorder)278 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_colorfilter_shader(SkRandom* rand,
279                                                                               Recorder* recorder) {
280     auto [s, o] = create_random_shader(rand, recorder);
281     SkASSERT(!s == !o);
282 
283     if (!s) {
284         return { nullptr, nullptr };
285     }
286 
287     auto [cf, cfO] = create_random_colorfilter(rand);
288 
289     return { s->makeWithColorFilter(std::move(cf)), o->makeWithColorFilter(std::move(cfO)) };
290 }
291 
create_image_shader(SkRandom * rand,Recorder * recorder)292 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_image_shader(SkRandom* rand,
293                                                                         Recorder* recorder) {
294     SkTileMode tmX = random_tilemode(rand);
295     SkTileMode tmY = random_tilemode(rand);
296 
297     sk_sp<SkShader> s = SkImageShader::Make(make_image(rand, recorder), tmX, tmY,
298                                             SkSamplingOptions(), nullptr);
299     sk_sp<PrecompileShader> o = PrecompileShaders::Image();
300 
301     return { s, o };
302 }
303 
create_blend_shader(SkRandom * rand,Recorder * recorder)304 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_blend_shader(SkRandom* rand,
305                                                                         Recorder* recorder) {
306     // TODO: add explicit testing of the kClear, kDst and kSrc blend modes since they short
307     // circuit creation of a true blend shader (i.e., in SkShaders::Blend).
308     auto [blender, blenderO] = create_random_blender(rand);
309 
310     auto [dstS, dstO] = create_random_shader(rand, recorder);
311     SkASSERT(!dstS == !dstO);
312     if (!dstS) {
313         return { nullptr, nullptr };
314     }
315 
316     auto [srcS, srcO] = create_random_shader(rand, recorder);
317     SkASSERT(!srcS == !srcO);
318     if (!srcS) {
319         return { nullptr, nullptr };
320     }
321 
322     auto s = SkShaders::Blend(std::move(blender), std::move(dstS), std::move(srcS));
323     auto o = PrecompileShaders::Blend(SkSpan<const sk_sp<PrecompileBlender>>({ blenderO }),
324                                       { dstO }, { srcO });
325 
326     return { s, o };
327 }
328 
create_shader(SkRandom * rand,Recorder * recorder,ShaderType shaderType)329 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>>  create_shader(SkRandom* rand,
330                                                                    Recorder* recorder,
331                                                                    ShaderType shaderType) {
332     switch (shaderType) {
333         case ShaderType::kNone:
334             return { nullptr, nullptr };
335         case ShaderType::kSolidColor:
336             return create_solid_shader(rand);
337         case ShaderType::kLinearGradient:
338             return create_gradient_shader(rand, SkShaderBase::GradientType::kLinear);
339         case ShaderType::kRadialGradient:
340             return create_gradient_shader(rand, SkShaderBase::GradientType::kRadial);
341         case ShaderType::kSweepGradient:
342             return create_gradient_shader(rand, SkShaderBase::GradientType::kSweep);
343         case ShaderType::kConicalGradient:
344             return create_gradient_shader(rand, SkShaderBase::GradientType::kConical);
345         case ShaderType::kLocalMatrix:
346             return create_localmatrix_shader(rand, recorder);
347         case ShaderType::kColorFilter:
348             return create_colorfilter_shader(rand, recorder);
349         case ShaderType::kImage:
350             return create_image_shader(rand, recorder);
351         case ShaderType::kBlend:
352             return create_blend_shader(rand, recorder);
353     }
354 
355     SkUNREACHABLE;
356 }
357 
create_random_shader(SkRandom * rand,Recorder * recorder)358 std::pair<sk_sp<SkShader>, sk_sp<PrecompileShader>> create_random_shader(SkRandom* rand,
359                                                                          Recorder* recorder) {
360     return create_shader(rand, recorder, random_shadertype(rand));
361 }
362 
363 //--------------------------------------------------------------------------------------------------
src_blender()364 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> src_blender() {
365     static SkRuntimeEffect* sSrcEffect = SkMakeRuntimeEffect(
366             SkRuntimeEffect::MakeForBlender,
367             "half4 main(half4 src, half4 dst) {"
368                 "return src;"
369             "}"
370     );
371 
372     sk_sp<SkBlender> b = sSrcEffect->makeBlender(/* uniforms= */ nullptr);
373     sk_sp<PrecompileBlender> o = MakePrecompileBlender(sk_ref_sp(sSrcEffect));
374     return { b , o };
375 }
376 
dest_blender()377 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> dest_blender() {
378     static SkRuntimeEffect* sDestEffect = SkMakeRuntimeEffect(
379             SkRuntimeEffect::MakeForBlender,
380             "half4 main(half4 src, half4 dst) {"
381                 "return dst;"
382             "}"
383     );
384 
385     sk_sp<SkBlender> b = sDestEffect->makeBlender(/* uniforms= */ nullptr);
386     sk_sp<PrecompileBlender> o = MakePrecompileBlender(sk_ref_sp(sDestEffect));
387     return { b , o };
388 }
389 
390 
combo_blender()391 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> combo_blender() {
392     static SkRuntimeEffect* sComboEffect = SkMakeRuntimeEffect(
393             SkRuntimeEffect::MakeForBlender,
394             "uniform float blendFrac;"
395             "uniform blender a;"
396             "uniform blender b;"
397             "half4 main(half4 src, half4 dst) {"
398                 "return (blendFrac * a.eval(src, dst)) + ((1 - blendFrac) * b.eval(src, dst));"
399             "}"
400     );
401 
402     auto [src, srcO] = src_blender();
403     auto [dst, dstO] = dest_blender();
404 
405     SkRuntimeEffect::ChildPtr children[] = { src, dst };
406     const PrecompileChildPtr childOptions[] = { srcO, dstO };
407 
408     const float kUniforms[] = { 1.0f };
409 
410     sk_sp<SkBlender> b = sComboEffect->makeBlender(SkData::MakeWithCopy(kUniforms,
411                                                                         sizeof(kUniforms)),
412                                                    children);
413     sk_sp<PrecompileBlender> o = MakePrecompileBlender(sk_ref_sp(sComboEffect), { childOptions });
414     return { b , o };
415 }
416 
create_bm_blender(SkRandom * rand,SkBlendMode bm)417 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_bm_blender(SkRandom* rand,
418                                                                         SkBlendMode bm) {
419     return { SkBlender::Mode(bm), PrecompileBlender::Mode(bm) };
420 }
421 
create_rt_blender(SkRandom * rand)422 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_rt_blender(SkRandom* rand) {
423     int option = rand->nextULessThan(3);
424 
425     switch (option) {
426         case 0: return src_blender();
427         case 1: return dest_blender();
428         case 2: return combo_blender();
429     }
430 
431     return { nullptr, nullptr };
432 }
433 
create_blender(SkRandom * rand,BlenderType type)434 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_blender(SkRandom* rand,
435                                                                      BlenderType type) {
436     switch (type) {
437         case BlenderType::kNone:
438             return { nullptr, nullptr };
439         case BlenderType::kPorterDuff:
440             return create_bm_blender(rand, random_porter_duff_bm(rand));
441         case BlenderType::kShaderBased:
442             return create_bm_blender(rand, random_complex_bm(rand));
443         case BlenderType::kRuntime:
444             return create_rt_blender(rand);
445     }
446 
447     SkUNREACHABLE;
448 }
449 
create_random_blender(SkRandom * rand)450 std::pair<sk_sp<SkBlender>, sk_sp<PrecompileBlender>> create_random_blender(SkRandom* rand) {
451     return create_blender(rand, random_blendertype(rand));
452 }
453 
454 //--------------------------------------------------------------------------------------------------
create_blend_colorfilter(SkRandom * rand)455 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_blend_colorfilter(
456         SkRandom* rand) {
457 
458     sk_sp<SkColorFilter> cf;
459 
460     // SkColorFilters::Blend is clever and can weed out noop color filters. Loop until we get
461     // a valid color filter.
462     while (!cf) {
463         cf = SkColorFilters::Blend(random_color(rand),
464                                    random_colorspace(rand),
465                                    random_blend_mode(rand));
466     }
467 
468     sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Blend();
469 
470     return { cf, o };
471 }
472 
create_matrix_colorfilter()473 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_matrix_colorfilter() {
474     sk_sp<SkColorFilter> cf = SkColorFilters::Matrix(
475             SkColorMatrix::RGBtoYUV(SkYUVColorSpace::kJPEG_Full_SkYUVColorSpace));
476     sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::Matrix();
477 
478     return { cf, o };
479 }
480 
create_hsla_matrix_colorfilter()481 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_hsla_matrix_colorfilter() {
482     sk_sp<SkColorFilter> cf = SkColorFilters::HSLAMatrix(
483             SkColorMatrix::RGBtoYUV(SkYUVColorSpace::kJPEG_Full_SkYUVColorSpace));
484     sk_sp<PrecompileColorFilter> o = PrecompileColorFilters::HSLAMatrix();
485 
486     return { cf, o };
487 }
488 
create_colorfilter(SkRandom * rand,ColorFilterType type)489 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_colorfilter(
490         SkRandom* rand,
491         ColorFilterType type) {
492 
493     switch (type) {
494         case ColorFilterType::kNone:
495             return { nullptr, nullptr };
496         case ColorFilterType::kBlend:
497             return create_blend_colorfilter(rand);
498         case ColorFilterType::kMatrix:
499             return create_matrix_colorfilter();
500         case ColorFilterType::kHSLAMatrix:
501             return create_hsla_matrix_colorfilter();
502     }
503 
504     SkUNREACHABLE;
505 }
506 
create_random_colorfilter(SkRandom * rand)507 std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(
508         SkRandom* rand) {
509     return create_colorfilter(rand, random_colorfiltertype(rand));
510 }
511 
512 //--------------------------------------------------------------------------------------------------
create_paint(SkRandom * rand,Recorder * recorder,ShaderType shaderType,BlenderType blenderType,ColorFilterType colorFilterType)513 std::pair<SkPaint, PaintOptions> create_paint(SkRandom* rand,
514                                               Recorder* recorder,
515                                               ShaderType shaderType,
516                                               BlenderType blenderType,
517                                               ColorFilterType colorFilterType) {
518     SkPaint paint;
519     paint.setColor(random_opaque_color(rand));
520 
521     PaintOptions paintOptions;
522 
523     {
524         auto [s, o] = create_shader(rand, recorder, shaderType);
525         SkASSERT(!s == !o);
526 
527         if (s) {
528             paint.setShader(std::move(s));
529             paintOptions.setShaders({o});
530         }
531     }
532 
533     {
534         auto [cf, o] = create_colorfilter(rand, colorFilterType);
535         SkASSERT(!cf == !o);
536 
537         if (cf) {
538             paint.setColorFilter(std::move(cf));
539             paintOptions.setColorFilters({o});
540         }
541     }
542 
543     {
544         auto [b, o] = create_blender(rand, blenderType);
545         SkASSERT(!b == !o);
546 
547         if (b) {
548             paint.setBlender(std::move(b));
549             paintOptions.setBlenders({o});
550         }
551     }
552 
553     return { paint, paintOptions };
554 }
555 
556 #ifdef SK_DEBUG
dump(ShaderCodeDictionary * dict,UniquePaintParamsID id)557 void dump(ShaderCodeDictionary* dict, UniquePaintParamsID id) {
558     auto entry = dict->lookup(id);
559     entry->paintParamsKey().dump(dict);
560 }
561 #endif
562 
make_path()563 SkPath make_path() {
564     SkPathBuilder path;
565     path.moveTo(0, 0);
566     path.lineTo(8, 2);
567     path.lineTo(16, 0);
568     path.lineTo(14, 8);
569     path.lineTo(16, 16);
570     path.lineTo(8, 14);
571     path.lineTo(0, 16);
572     path.lineTo(2, 8);
573     path.close();
574     return path.detach();
575 }
576 
577 struct DrawData {
578     SkPath fPath;
579     sk_sp<SkTextBlob> fBlob;
580     sk_sp<SkVertices> fVerts;
581 };
582 
check_draw(skiatest::Reporter * reporter,Context * context,Recorder * recorder,const SkPaint & paint,DrawTypeFlags dt,const DrawData & drawData)583 void check_draw(skiatest::Reporter* reporter,
584                 Context* context,
585                 Recorder* recorder,
586                 const SkPaint& paint,
587                 DrawTypeFlags dt,
588                 const DrawData& drawData) {
589     int before = context->priv().globalCache()->numGraphicsPipelines();
590 
591     {
592         // TODO: vary the colorType of the target surface too
593         SkImageInfo ii = SkImageInfo::Make(16, 16,
594                                            kRGBA_8888_SkColorType,
595                                            kPremul_SkAlphaType);
596 
597         sk_sp<SkSurface> surf = SkSurface::MakeGraphite(recorder, ii);
598         SkCanvas* canvas = surf->getCanvas();
599 
600         switch (dt) {
601             case DrawTypeFlags::kShape:
602                 canvas->drawRect(SkRect::MakeWH(16, 16), paint);
603                 canvas->drawPath(drawData.fPath, paint);
604                 break;
605             case DrawTypeFlags::kText:
606                 canvas->drawTextBlob(drawData.fBlob, 0, 16, paint);
607                 break;
608             case DrawTypeFlags::kDrawVertices:
609                 canvas->drawVertices(drawData.fVerts, SkBlendMode::kDst, paint);
610                 break;
611             default:
612                 SkASSERT(false);
613                 break;
614         }
615 
616         std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
617         context->insertRecording({ recording.get() });
618         context->submit(SyncToCpu::kYes);
619     }
620 
621     int after = context->priv().globalCache()->numGraphicsPipelines();
622 
623     // Actually using the SkPaint with the specified type of draw shouldn't have caused
624     // any additional compilation
625     REPORTER_ASSERT(reporter, before == after);
626 }
627 
628 } // anonymous namespace
629 
630 // This is intended to be a smoke test for the agreement between the two ways of creating a
631 // PaintParamsKey:
632 //    via ExtractPaintData (i.e., from an SkPaint)
633 //    and via the pre-compilation system
634 //
635 // TODO: keep this as a smoke test but add a fuzzer that reuses all the helpers
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTest,reporter,context)636 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTest, reporter, context) {
637     auto recorder = context->makeRecorder();
638     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
639 
640     SkColorInfo ci = SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType,
641                                  SkColorSpace::MakeSRGB());
642 
643     KeyContext extractPaintKeyContext(recorder.get(), {}, ci);
644 
645     std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
646     KeyContext precompileKeyContext(dict, rtDict.get(), ci);
647 
648     SkFont font(ToolUtils::create_portable_typeface(), 16);
649     const char text[] = "hambur";
650 
651     // TODO: add a drawVertices call w/o colors. That impacts whether the RenderSteps emit
652     // a primitive color blender
653     constexpr int kNumVerts = 4;
654     constexpr SkPoint kPositions[kNumVerts] { {0,0}, {0,16}, {16,16}, {16,0} };
655     constexpr SkColor kColors[kNumVerts] = { SK_ColorBLUE, SK_ColorGREEN,
656                                              SK_ColorCYAN, SK_ColorYELLOW };
657 
658     DrawData drawData = {
659             make_path(),
660             SkTextBlob::MakeFromText(text, strlen(text), font),
661             SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, kNumVerts,
662                                  kPositions, kPositions, kColors),
663     };
664 
665     SkRandom rand;
666 
667     PaintParamsKeyBuilder builder(dict);
668     PipelineDataGatherer gatherer(Layout::kMetal);
669 
670     for (auto s : { ShaderType::kNone,
671                     ShaderType::kSolidColor,
672                     ShaderType::kLinearGradient,
673                     ShaderType::kRadialGradient,
674                     ShaderType::kSweepGradient,
675                     ShaderType::kConicalGradient,
676                     ShaderType::kLocalMatrix,
677                     ShaderType::kImage,
678                     ShaderType::kBlend  }) {
679         for (auto bm : { BlenderType::kNone,
680                          BlenderType::kPorterDuff,
681                          BlenderType::kShaderBased,
682                          BlenderType::kRuntime }) {
683             for (auto cf : { ColorFilterType::kNone,
684                              ColorFilterType::kBlend,
685                              ColorFilterType::kMatrix,
686                              ColorFilterType::kHSLAMatrix }) {
687 
688                 auto [paint, paintOptions] = create_paint(&rand, recorder.get(), s, bm, cf);
689 
690                 for (auto dt : { DrawTypeFlags::kShape,
691                                  DrawTypeFlags::kText,
692                                  DrawTypeFlags::kDrawVertices }) {
693 
694                     for (bool withPrimitiveBlender : { false, true }) {
695 
696                         sk_sp<SkBlender> primitiveBlender;
697                         if (withPrimitiveBlender) {
698                             if (dt != DrawTypeFlags::kDrawVertices) {
699                                 // Only drawVertices calls need a primitive blender
700                                 continue;
701                             }
702 
703                             primitiveBlender = SkBlender::Mode(SkBlendMode::kSrcOver);
704                         }
705 
706                         auto [paintID, uData, tData] = ExtractPaintData(
707                                 recorder.get(), &gatherer, &builder, Layout::kMetal, {},
708                                 PaintParams(paint,
709                                             std::move(primitiveBlender),
710                                             /* skipColorXform= */ false),
711                                 extractPaintKeyContext.dstColorInfo());
712 
713                         std::vector<UniquePaintParamsID> precompileIDs;
714                         paintOptions.priv().buildCombinations(precompileKeyContext,
715                                                               withPrimitiveBlender,
716                                                               [&](UniquePaintParamsID id) {
717                                                                   precompileIDs.push_back(id);
718                                                               });
719 
720                         // The specific key generated by ExtractPaintData should be one of the
721                         // combinations generated by the combination system.
722                         auto result = std::find(precompileIDs.begin(), precompileIDs.end(),
723                                                 paintID);
724 
725 #ifdef SK_DEBUG
726                         if (result == precompileIDs.end()) {
727                             SkDebugf("From paint: ");
728                             dump(dict, paintID);
729 
730                             SkDebugf("From combination builder:");
731                             for (auto iter : precompileIDs) {
732                                 dump(dict, iter);
733                             }
734                         }
735 #endif
736 
737                         REPORTER_ASSERT(reporter, result != precompileIDs.end());
738 
739                         {
740                             context->priv().globalCache()->resetGraphicsPipelines();
741 
742                             int before = context->priv().globalCache()->numGraphicsPipelines();
743                             Precompile(context, paintOptions, dt);
744                             int after = context->priv().globalCache()->numGraphicsPipelines();
745 
746                             REPORTER_ASSERT(reporter, before == 0);
747                             REPORTER_ASSERT(reporter, after > before);
748 
749                             check_draw(reporter, context, recorder.get(), paint, dt, drawData);
750                         }
751                     }
752                 }
753             }
754         }
755     }
756 }
757 
758 #endif // SK_GRAPHITE
759