1 /*
2 * Copyright 2022 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/SkColorSpace.h"
13 #include "include/effects/SkRuntimeEffect.h"
14 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
15 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
16 #include "include/gpu/graphite/precompile/PrecompileRuntimeEffect.h"
17 #include "include/gpu/graphite/precompile/PrecompileShader.h"
18 #include "src/gpu/graphite/ContextPriv.h"
19 #include "src/gpu/graphite/KeyContext.h"
20 #include "src/gpu/graphite/PipelineData.h"
21 #include "src/gpu/graphite/PrecompileInternal.h"
22 #include "src/gpu/graphite/RenderPassDesc.h"
23 #include "src/gpu/graphite/Renderer.h"
24 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
25 #include "src/gpu/graphite/precompile/PaintOptionsPriv.h"
26
27 #include <array>
28
29 using namespace::skgpu::graphite;
30
31 namespace {
32
33 // colorfilters
34 static constexpr int kExpectedBlendCFCombos = 15;
35 static constexpr int kExpectedColorSpaceCFCombos = 1;
36 static constexpr int kExpectedHighContrastCFCombos = 1;
37 static constexpr int kExpectedLightingCFCombos = 1;
38 static constexpr int kExpectedLumaCFCombos = 1;
39 static constexpr int kExpectedMatrixCFCombos = 1;
40 static constexpr int kExpectedOverdrawCFCombos = 1;
41 static constexpr int kExpectedTableCFCombos = 1;
42
43 // shaders
44 static constexpr int kExpectedGradientCombos = 3;
45 static constexpr int kExpectedImageCombos = 16;
46 static constexpr int kExpectedPerlinNoiseCombos = 1;
47 static constexpr int kExpectedPictureCombos = 32;
48 static constexpr int kExpectedRawImageCombos = 6;
49 static constexpr int kExpectedSolidColorCombos = 1;
50
51
52 // A default kSrcOver blend mode will be supplied if no other blend options are added
no_blend_mode_option_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)53 void no_blend_mode_option_test(const KeyContext& keyContext,
54 PipelineDataGatherer* gatherer,
55 const RenderPassDesc& renderPassDesc,
56 skiatest::Reporter* reporter) {
57 PaintOptions paintOptions;
58 paintOptions.setShaders({ PrecompileShaders::Color() });
59
60 REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1);
61
62 std::vector<UniquePaintParamsID> precompileIDs;
63 paintOptions.priv().buildCombinations(keyContext,
64 gatherer,
65 DrawTypeFlags::kNone,
66 /* withPrimitiveBlender= */ false,
67 Coverage::kNone,
68 renderPassDesc,
69 [&precompileIDs](UniquePaintParamsID id,
70 DrawTypeFlags,
71 bool /* withPrimitiveBlender */,
72 Coverage,
73 const RenderPassDesc&) {
74 precompileIDs.push_back(id);
75 });
76
77 SkASSERT(precompileIDs.size() == 1);
78 }
79
80 // This test checks that the 'PaintOptions::numCombinations' method and the number actually
81 // generated by 'buildCombinations' agree with the expected number of combinations.
run_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter,const PaintOptions & paintOptions,int expectedNumOptions)82 void run_test(const KeyContext& keyContext,
83 PipelineDataGatherer* gatherer,
84 const RenderPassDesc& renderPassDesc,
85 skiatest::Reporter* reporter,
86 const PaintOptions& paintOptions,
87 int expectedNumOptions) {
88 REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == expectedNumOptions,
89 "expected %d, but was %d",
90 expectedNumOptions, paintOptions.priv().numCombinations());
91
92 std::vector<UniquePaintParamsID> precompileIDs;
93 paintOptions.priv().buildCombinations(keyContext,
94 gatherer,
95 DrawTypeFlags::kNone,
96 /* withPrimitiveBlender= */ false,
97 Coverage::kNone,
98 renderPassDesc,
99 [&precompileIDs](UniquePaintParamsID id,
100 DrawTypeFlags,
101 bool /* withPrimitiveBlender */,
102 Coverage,
103 const RenderPassDesc&) {
104 precompileIDs.push_back(id);
105 });
106
107 SkASSERT(static_cast<int>(precompileIDs.size()) == expectedNumOptions);
108 }
109
big_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)110 void big_test(const KeyContext& keyContext,
111 PipelineDataGatherer* gatherer,
112 const RenderPassDesc& renderPassDesc,
113 skiatest::Reporter* reporter) {
114
115 static constexpr int kNumExpected = 1084;
116 // paintOptions (1084 = 4*271)
117 // |- (271 = 3+268) sweepGrad_0 (3) |
118 // | blendShader_0 (268 = 1*4*67)
119 // | |- 0: (1) kSrc (1)
120 // | |- 1: (4=3+1) (dsts) linearGrad_0 (3) | solid_0 (1)
121 // | |- 2: (67=3+64) (srcs) linearGrad_1 (3) |
122 // | blendShader_1 (64=1*4*16)
123 // | |- 0: (1) kDst (1)
124 // | |- 1: (4=3+1) (dsts) radGrad_0 (3) | solid_1 (1)
125 // | |- 2: (16) (srcs) imageShader_0 (16)
126 // |
127 // |- (4) 4-built-in-blend-modes
128
129 PaintOptions paintOptions;
130
131 // first, shaders. First top-level option (sweepGrad_0)
132 sk_sp<PrecompileShader> sweepGrad_0 = PrecompileShaders::SweepGradient();
133
134 std::array<SkBlendMode, 1> blendModes{ SkBlendMode::kSrc };
135
136 std::vector<SkBlendMode> moreBlendModes{ SkBlendMode::kDst };
137
138 // Second top-level option (blendShader_0)
139 auto blendShader_0 = PrecompileShaders::Blend(
140 SkSpan<const SkBlendMode>(blendModes), // std::array
141 { // initializer_list
142 PrecompileShaders::LinearGradient(),
143 PrecompileShaders::Color()
144 },
145 {
146 PrecompileShaders::LinearGradient(),
147 PrecompileShaders::Blend(
148 SkSpan<const SkBlendMode>(moreBlendModes),// std::vector
149 {
150 PrecompileShaders::RadialGradient(),
151 PrecompileShaders::Color()
152 },
153 {
154 PrecompileShaders::Image()
155 })
156 });
157
158 paintOptions.setShaders({ sweepGrad_0, blendShader_0 });
159
160 static const SkBlendMode kEvenMoreBlendModes[] = {
161 SkBlendMode::kSrcOver,
162 SkBlendMode::kSrc,
163 SkBlendMode::kDstOver,
164 SkBlendMode::kDst
165 };
166
167 // now, blend modes
168 paintOptions.setBlendModes(kEvenMoreBlendModes); // c array
169
170 REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == kNumExpected,
171 "Actual # of combinations %d", paintOptions.priv().numCombinations());
172
173 std::vector<UniquePaintParamsID> precompileIDs;
174 paintOptions.priv().buildCombinations(keyContext,
175 gatherer,
176 DrawTypeFlags::kNone,
177 /* withPrimitiveBlender= */ false,
178 Coverage::kNone,
179 renderPassDesc,
180 [&precompileIDs](UniquePaintParamsID id,
181 DrawTypeFlags,
182 bool /* withPrimitiveBlender */,
183 Coverage,
184 const RenderPassDesc&) {
185 precompileIDs.push_back(id);
186 });
187
188 SkASSERT(precompileIDs.size() == kNumExpected);
189 }
190
191 template <typename T>
create_runtime_combos(skiatest::Reporter * reporter,SkRuntimeEffect::Result effectFactory (SkString),sk_sp<T> precompileFactory (sk_sp<SkRuntimeEffect>,SkSpan<const PrecompileChildOptions> childOptions),const char * redCode,const char * greenCode,const char * blueCode,const char * combineCode)192 std::vector<sk_sp<T>> create_runtime_combos(
193 skiatest::Reporter* reporter,
194 SkRuntimeEffect::Result effectFactory(SkString),
195 sk_sp<T> precompileFactory(sk_sp<SkRuntimeEffect>,
196 SkSpan<const PrecompileChildOptions> childOptions),
197 const char* redCode,
198 const char* greenCode,
199 const char* blueCode,
200 const char* combineCode) {
201 auto [redEffect, error1] = effectFactory(SkString(redCode));
202 REPORTER_ASSERT(reporter, redEffect, "%s", error1.c_str());
203 auto [greenEffect, error2] = effectFactory(SkString(greenCode));
204 REPORTER_ASSERT(reporter, greenEffect, "%s", error2.c_str());
205 auto [blueEffect, error3] = effectFactory(SkString(blueCode));
206 REPORTER_ASSERT(reporter, blueEffect, "%s", error3.c_str());
207 auto [combineEffect, error4] = effectFactory(SkString(combineCode));
208 REPORTER_ASSERT(reporter, combineEffect, "%s", error4.c_str());
209
210 sk_sp<T> red = precompileFactory(redEffect, {});
211 REPORTER_ASSERT(reporter, red);
212
213 sk_sp<T> green = precompileFactory(greenEffect, {});
214 REPORTER_ASSERT(reporter, green);
215
216 sk_sp<T> blue = precompileFactory(blueEffect, {});
217 REPORTER_ASSERT(reporter, blue);
218
219 sk_sp<T> combine = precompileFactory(combineEffect, { { red, green },
220 { blue, sk_sp<T>(nullptr) } });
221 REPORTER_ASSERT(reporter, combine);
222
223 return { combine };
224 }
225
runtime_effect_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)226 void runtime_effect_test(const KeyContext& keyContext,
227 PipelineDataGatherer* gatherer,
228 const RenderPassDesc& renderPassDesc,
229 skiatest::Reporter* reporter) {
230 // paintOptions (64 = 4*4*4)
231 // |- combineShader (4)
232 // | 0: redShader | greenShader
233 // | 1: blueShader | nullptr
234 // |
235 // |- combineColorFilter (4)
236 // | 0: redColorFilter | greenColorFilter
237 // | 1: blueColorFilter | nullptr
238 // |
239 // |- combineBlender (4)
240 // | 0: redBlender | greenBlender
241 // | 1: blueBlender | nullptr
242
243 PaintOptions paintOptions;
244
245 // shaders
246 {
247 static const char* kRedS = R"(
248 half4 main(vec2 fragcoord) { return half4(.5, 0, 0, .5); }
249 )";
250 static const char* kGreenS = R"(
251 half4 main(vec2 fragcoord) { return half4(0, .5, 0, .5); }
252 )";
253 static const char* kBlueS = R"(
254 half4 main(vec2 fragcoord) { return half4(0, 0, .5, .5); }
255 )";
256
257 static const char* kCombineS = R"(
258 uniform shader first;
259 uniform shader second;
260 half4 main(vec2 fragcoords) {
261 return first.eval(fragcoords) + second.eval(fragcoords);
262 }
263 )";
264
265 std::vector<sk_sp<PrecompileShader>> combinations =
266 create_runtime_combos<PrecompileShader>(reporter,
267 SkRuntimeEffect::MakeForShader,
268 PrecompileRuntimeEffects::MakePrecompileShader,
269 kRedS,
270 kGreenS,
271 kBlueS,
272 kCombineS);
273 paintOptions.setShaders(combinations);
274 }
275
276 // color filters
277 {
278 static const char* kRedCF = R"(
279 half4 main(half4 color) { return half4(.5, 0, 0, .5); }
280 )";
281 static const char* kGreenCF = R"(
282 half4 main(half4 color) { return half4(0, .5, 0, .5); }
283 )";
284 static const char* kBlueCF = R"(
285 half4 main(half4 color) { return half4(0, 0, .5, .5); }
286 )";
287
288 static const char* kCombineCF = R"(
289 uniform colorFilter first;
290 uniform colorFilter second;
291 half4 main(half4 color) { return first.eval(color) + second.eval(color); }
292 )";
293
294 std::vector<sk_sp<PrecompileColorFilter>> combinations =
295 create_runtime_combos<PrecompileColorFilter>(
296 reporter,
297 SkRuntimeEffect::MakeForColorFilter,
298 PrecompileRuntimeEffects::MakePrecompileColorFilter,
299 kRedCF,
300 kGreenCF,
301 kBlueCF,
302 kCombineCF);
303 paintOptions.setColorFilters(combinations);
304 }
305
306 // blenders
307 {
308 static const char* kRedB = R"(
309 half4 main(half4 src, half4 dst) { return half4(.5, 0, 0, .5); }
310 )";
311 static const char* kGreenB = R"(
312 half4 main(half4 src, half4 dst) { return half4(0, .5, 0, .5); }
313 )";
314 static const char* kBlueB = R"(
315 half4 main(half4 src, half4 dst) { return half4(0, 0, .5, .5); }
316 )";
317
318 static const char* kCombineB = R"(
319 uniform blender first;
320 uniform blender second;
321 half4 main(half4 src, half4 dst) {
322 return first.eval(src, dst) + second.eval(src, dst);
323 }
324 )";
325
326 std::vector<sk_sp<PrecompileBlender>> combinations =
327 create_runtime_combos<PrecompileBlender>(
328 reporter,
329 SkRuntimeEffect::MakeForBlender,
330 PrecompileRuntimeEffects::MakePrecompileBlender,
331 kRedB,
332 kGreenB,
333 kBlueB,
334 kCombineB);
335 paintOptions.setBlenders(combinations);
336 }
337
338 REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 64);
339
340 std::vector<UniquePaintParamsID> precompileIDs;
341 paintOptions.priv().buildCombinations(keyContext,
342 gatherer,
343 DrawTypeFlags::kNone,
344 /* withPrimitiveBlender= */ false,
345 Coverage::kNone,
346 renderPassDesc,
347 [&precompileIDs](UniquePaintParamsID id,
348 DrawTypeFlags,
349 bool /* withPrimitiveBlender */,
350 Coverage,
351 const RenderPassDesc&) {
352 precompileIDs.push_back(id);
353 });
354
355 SkASSERT(precompileIDs.size() == 64);
356 }
357
358 // Exercise all the PrecompileBlenders factories
blend_subtest(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)359 void blend_subtest(const KeyContext& keyContext,
360 PipelineDataGatherer* gatherer,
361 const RenderPassDesc& renderPassDesc,
362 skiatest::Reporter* reporter) {
363 // The BlendMode PrecompileBlender only ever has 1 combination
364 {
365 PaintOptions paintOptions;
366 paintOptions.setBlenders({ PrecompileBlenders::Mode(SkBlendMode::kColorDodge) });
367
368 run_test(keyContext, gatherer, renderPassDesc,
369 reporter, paintOptions, /* expectedNumOptions= */ 1);
370 }
371
372 // Specifying the BlendMode PrecompileBlender by SkBlendMode should also only ever
373 // yield 1 combination.
374 {
375 PaintOptions paintOptions;
376 paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
377
378 run_test(keyContext, gatherer, renderPassDesc,
379 reporter, paintOptions, /* expectedNumOptions= */ 1);
380 }
381
382 // The Arithmetic PrecompileBlender only ever has 1 combination
383 {
384 PaintOptions paintOptions;
385 paintOptions.setBlenders({ PrecompileBlenders::Arithmetic() });
386
387 run_test(keyContext, gatherer, renderPassDesc,
388 reporter, paintOptions, /* expectedNumOptions= */ 1);
389 }
390 }
391
392 // Exercise all the PrecompileShaders factories
shader_subtest(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)393 void shader_subtest(const KeyContext& keyContext,
394 PipelineDataGatherer* gatherer,
395 const RenderPassDesc& renderPassDesc,
396 skiatest::Reporter* reporter) {
397 {
398 PaintOptions paintOptions;
399 paintOptions.setShaders({ PrecompileShaders::Empty() });
400
401 run_test(keyContext, gatherer, renderPassDesc,
402 reporter, paintOptions, /* expectedNumOptions= */ 1);
403 }
404
405 // The solid color shader only ever generates one combination. Because it is constant
406 // everywhere it can cause other shaders to be elided (e.g., the LocalMatrix shader -
407 // see the LocalMatrix test(s) below).
408 {
409 PaintOptions paintOptions;
410 paintOptions.setShaders({ PrecompileShaders::Color() });
411
412 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
413 /* expectedNumOptions= */ kExpectedSolidColorCombos);
414 }
415
416 // In general, the blend shader generates the product of the options in each of its slots.
417 // The rules for how many combinations the SkBlendModes yield are:
418 // all Porter-Duff SkBlendModes collapse to one option (see GetPorterDuffBlendConstants))
419 // all HSCL SkBlendModes collapse to another option
420 // all other SkBlendModes produce unique options
421 {
422 const SkBlendMode kBlendModes[] = {
423 SkBlendMode::kSrcOut, // Porter-Duff
424 SkBlendMode::kSrcOver, // Porter-Duff
425 SkBlendMode::kHue, // HSLC
426 SkBlendMode::kColor, // HSLC
427 SkBlendMode::kScreen, // Fixed Screen
428 SkBlendMode::kDarken, // fixed Darken
429 };
430 PaintOptions paintOptions;
431 paintOptions.setShaders(
432 { PrecompileShaders::Blend(SkSpan<const SkBlendMode>(kBlendModes),
433 { PrecompileShaders::Color() },
434 { PrecompileShaders::MakeFractalNoise() }) });
435
436 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
437 /* expectedNumOptions= */ 4 * // Porter-Duff, HSLC, Screen, Darken
438 kExpectedSolidColorCombos *
439 kExpectedPerlinNoiseCombos);
440 }
441
442 // The ImageShaders have 16 combinations
443 // (4 sampling/tiling x 4 color space xform)
444 // The CoordClamp shader doesn't add any additional combinations to its wrapped shader.
445 {
446 PaintOptions paintOptions;
447 paintOptions.setShaders({ PrecompileShaders::CoordClamp({ PrecompileShaders::Image() }) });
448
449 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
450 /* expectedNumOptions= */ kExpectedImageCombos);
451 }
452
453 // RawImageShaders only have 6 combinations since they never do cubic filtering and only have
454 // two possible color space xform variants.
455 {
456 PaintOptions paintOptions;
457 paintOptions.setShaders({ PrecompileShaders::RawImage() });
458
459 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
460 /* expectedNumOptions= */ kExpectedRawImageCombos);
461 }
462
463 // Each Perlin noise shader only has one combination
464 {
465 PaintOptions paintOptions;
466 paintOptions.setShaders({ PrecompileShaders::MakeFractalNoise(),
467 PrecompileShaders::MakeTurbulence() });
468
469 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
470 /* expectedNumOptions= */ kExpectedPerlinNoiseCombos + kExpectedPerlinNoiseCombos);
471 }
472
473 // Each gradient shader generates 3 combinations
474 {
475 PaintOptions paintOptions;
476 paintOptions.setShaders({ PrecompileShaders::LinearGradient(),
477 PrecompileShaders::RadialGradient(),
478 PrecompileShaders::TwoPointConicalGradient(),
479 PrecompileShaders::SweepGradient() });
480
481 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
482 /* expectedNumOptions= */ kExpectedGradientCombos + kExpectedGradientCombos +
483 kExpectedGradientCombos + kExpectedGradientCombos);
484 }
485
486 // Each picture shader generates 32 combinations:
487 // 2 (pictureShader LM) x 16 (imageShader variations)
488 {
489 PaintOptions paintOptions;
490 paintOptions.setShaders({ PrecompileShaders::Picture() });
491
492 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
493 /* expectedNumOptions= */ kExpectedPictureCombos);
494 }
495
496 // In general, the local matrix shader just generates however many options its wrapped
497 // shader generates.
498 {
499 PaintOptions paintOptions;
500 paintOptions.setShaders(
501 { PrecompileShaders::LocalMatrix({ PrecompileShaders::LinearGradient() }) });
502
503 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
504 /* expectedNumOptions= */ kExpectedGradientCombos);
505 }
506
507 // The ColorFilter shader just creates the cross product of its child options
508 {
509 PaintOptions paintOptions;
510 paintOptions.setShaders(
511 { PrecompileShaders::ColorFilter({ PrecompileShaders::LinearGradient() },
512 { PrecompileColorFilters::Blend() }) });
513
514 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
515 /* expectedNumOptions= */ kExpectedGradientCombos * kExpectedBlendCFCombos);
516 }
517
518 {
519 PaintOptions paintOptions;
520 paintOptions.setShaders(
521 { PrecompileShaders::WorkingColorSpace({ PrecompileShaders::LinearGradient() },
522 { SkColorSpace::MakeSRGBLinear() }) });
523
524 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
525 /* expectedNumOptions= */ kExpectedGradientCombos *
526 1 /* only one colorSpace */);
527 }
528 }
529
530 // Exercise all the PrecompileColorFilters factories. The impact of colorfilters on the number
531 // of combinations is very predictable. Except for the Compose and Lerp color filters, all the
532 // color filters only ever have one combination. The Compose and Lerp color filters also just
533 // simply generate the cross product of their children.
colorfilter_subtest(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)534 void colorfilter_subtest(const KeyContext& keyContext,
535 PipelineDataGatherer* gatherer,
536 const RenderPassDesc& renderPassDesc,
537 skiatest::Reporter* reporter) {
538
539
540 {
541 // The compose colorfilter just generates the cross product of its children.
542 static constexpr int kExpectedNumOptions =
543 kExpectedTableCFCombos * (kExpectedHighContrastCFCombos + kExpectedLumaCFCombos) +
544 kExpectedLightingCFCombos * (kExpectedHighContrastCFCombos + kExpectedLumaCFCombos);
545
546 PaintOptions paintOptions;
547 paintOptions.setColorFilters(
548 { PrecompileColorFilters::Compose(
549 { PrecompileColorFilters::Table(), PrecompileColorFilters::Lighting() },
550 { PrecompileColorFilters::HighContrast(), PrecompileColorFilters::Luma() }) });
551
552 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
553 }
554
555 {
556 PaintOptions paintOptions;
557 paintOptions.setColorFilters({ PrecompileColorFilters::Blend() });
558
559 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
560 kExpectedBlendCFCombos);
561 }
562
563 {
564 PaintOptions paintOptions;
565 paintOptions.setColorFilters({ PrecompileColorFilters::Matrix(),
566 PrecompileColorFilters::HSLAMatrix() });
567
568 // HSLAMatrix and Matrix map to the same color filter
569 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
570 kExpectedMatrixCFCombos + kExpectedMatrixCFCombos);
571 }
572
573 {
574 PaintOptions paintOptions;
575 paintOptions.setColorFilters({ PrecompileColorFilters::LinearToSRGBGamma(),
576 PrecompileColorFilters::SRGBToLinearGamma() });
577
578 // LinearToSRGB and SRGBToLinear both map to the colorspace colorfilter
579 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
580 kExpectedColorSpaceCFCombos + kExpectedColorSpaceCFCombos);
581 }
582
583 {
584 // The lerp colorfilter just generates the cross product of its children.
585 static constexpr int kExpectedNumOptions =
586 kExpectedMatrixCFCombos * (kExpectedBlendCFCombos + kExpectedOverdrawCFCombos) +
587 kExpectedLumaCFCombos * (kExpectedBlendCFCombos + kExpectedOverdrawCFCombos);
588
589 PaintOptions paintOptions;
590 paintOptions.setColorFilters(
591 { PrecompileColorFilters::Lerp(
592 { PrecompileColorFilters::Matrix(), PrecompileColorFilters::Luma() },
593 { PrecompileColorFilters::Blend(), PrecompileColorFilters::Overdraw() }) });
594
595 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
596 }
597 }
598
599 } // anonymous namespace
600
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest,reporter,context,CtsEnforcement::kNever)601 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest, reporter, context,
602 CtsEnforcement::kNever) {
603 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
604
605 auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
606
607 SkColorInfo ci(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
608 KeyContext keyContext(context->priv().caps(), dict, rtEffectDict.get(), ci);
609
610 PipelineDataGatherer gatherer(Layout::kMetal);
611
612 RenderPassDesc unusedRenderPassDesc;
613
614 // The default PaintOptions should create a single combination with a solid color shader and
615 // kSrcOver blending
616 {
617 PaintOptions paintOptions;
618
619 run_test(keyContext, &gatherer, unusedRenderPassDesc, reporter, paintOptions,
620 /* expectedNumOptions= */ 1);
621 }
622
623 blend_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
624 shader_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
625 colorfilter_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
626
627 no_blend_mode_option_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
628 big_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
629 runtime_effect_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
630 }
631
632 #endif // SK_GRAPHITE
633