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 = 6;
46 static constexpr int kExpectedPerlinNoiseCombos = 1;
47 static constexpr int kExpectedPictureCombos = 12;
48 static constexpr int kExpectedRawImageCombos = 3;
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 = 444;
116 // paintOptions (444 = 4*111)
117 // |- (111 = 3+108) sweepGrad_0 (3) |
118 // | blendShader_0 (108 = 1*4*27)
119 // | |- 0: (1) kSrc (1)
120 // | |- 1: (4=3+1) (dsts) linearGrad_0 (3) | solid_0 (1)
121 // | |- 2: (27=3+24) (srcs) linearGrad_1 (3) |
122 // | blendShader_1 (24=1*4*6)
123 // | |- 0: (1) kDst (1)
124 // | |- 1: (4=3+1) (dsts) radGrad_0 (3) | solid_1 (1)
125 // | |- 2: (6) (srcs) imageShader_0 (6)
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 6 combinations (3 sampling/tiling x 2 alpha/non-alpha)
443 // The CoordClamp shader doesn't add any additional combinations to its wrapped shader.
444 {
445 PaintOptions paintOptions;
446 paintOptions.setShaders({ PrecompileShaders::CoordClamp({ PrecompileShaders::Image() }) });
447
448 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
449 /* expectedNumOptions= */ kExpectedImageCombos);
450 }
451
452 // RawImageShaders only have 3 combinations (since they never incorporate alpha)
453 {
454 PaintOptions paintOptions;
455 paintOptions.setShaders({ PrecompileShaders::RawImage() });
456
457 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
458 /* expectedNumOptions= */ kExpectedRawImageCombos);
459 }
460
461 // Each Perlin noise shader only has one combination
462 {
463 PaintOptions paintOptions;
464 paintOptions.setShaders({ PrecompileShaders::MakeFractalNoise(),
465 PrecompileShaders::MakeTurbulence() });
466
467 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
468 /* expectedNumOptions= */ kExpectedPerlinNoiseCombos + kExpectedPerlinNoiseCombos);
469 }
470
471 // Each gradient shader generates 3 combinations
472 {
473 PaintOptions paintOptions;
474 paintOptions.setShaders({ PrecompileShaders::LinearGradient(),
475 PrecompileShaders::RadialGradient(),
476 PrecompileShaders::TwoPointConicalGradient(),
477 PrecompileShaders::SweepGradient() });
478
479 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
480 /* expectedNumOptions= */ kExpectedGradientCombos + kExpectedGradientCombos +
481 kExpectedGradientCombos + kExpectedGradientCombos);
482 }
483
484 // Each picture shader generates 12 combinations:
485 // 2 (pictureShader LM) x 6 (imageShader variations)
486 {
487 PaintOptions paintOptions;
488 paintOptions.setShaders({ PrecompileShaders::Picture() });
489
490 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
491 /* expectedNumOptions= */ kExpectedPictureCombos);
492 }
493
494 // In general, the local matrix shader just generates however many options its wrapped
495 // shader generates.
496 {
497 PaintOptions paintOptions;
498 paintOptions.setShaders(
499 { PrecompileShaders::LocalMatrix({ PrecompileShaders::LinearGradient() }) });
500
501 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
502 /* expectedNumOptions= */ kExpectedGradientCombos);
503 }
504
505 // The ColorFilter shader just creates the cross product of its child options
506 {
507 PaintOptions paintOptions;
508 paintOptions.setShaders(
509 { PrecompileShaders::ColorFilter({ PrecompileShaders::LinearGradient() },
510 { PrecompileColorFilters::Blend() }) });
511
512 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
513 /* expectedNumOptions= */ kExpectedGradientCombos * kExpectedBlendCFCombos);
514 }
515
516 {
517 PaintOptions paintOptions;
518 paintOptions.setShaders(
519 { PrecompileShaders::WorkingColorSpace({ PrecompileShaders::LinearGradient() },
520 { SkColorSpace::MakeSRGBLinear() }) });
521
522 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
523 /* expectedNumOptions= */ kExpectedGradientCombos *
524 1 /* only one colorSpace */);
525 }
526 }
527
528 // Exercise all the PrecompileColorFilters factories. The impact of colorfilters on the number
529 // of combinations is very predictable. Except for the Compose and Lerp color filters, all the
530 // color filters only ever have one combination. The Compose and Lerp color filters also just
531 // simply generate the cross product of their children.
colorfilter_subtest(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,skiatest::Reporter * reporter)532 void colorfilter_subtest(const KeyContext& keyContext,
533 PipelineDataGatherer* gatherer,
534 const RenderPassDesc& renderPassDesc,
535 skiatest::Reporter* reporter) {
536
537
538 {
539 // The compose colorfilter just generates the cross product of its children.
540 static constexpr int kExpectedNumOptions =
541 kExpectedTableCFCombos * (kExpectedHighContrastCFCombos + kExpectedLumaCFCombos) +
542 kExpectedLightingCFCombos * (kExpectedHighContrastCFCombos + kExpectedLumaCFCombos);
543
544 PaintOptions paintOptions;
545 paintOptions.setColorFilters(
546 { PrecompileColorFilters::Compose(
547 { PrecompileColorFilters::Table(), PrecompileColorFilters::Lighting() },
548 { PrecompileColorFilters::HighContrast(), PrecompileColorFilters::Luma() }) });
549
550 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
551 }
552
553 {
554 PaintOptions paintOptions;
555 paintOptions.setColorFilters({ PrecompileColorFilters::Blend() });
556
557 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
558 kExpectedBlendCFCombos);
559 }
560
561 {
562 PaintOptions paintOptions;
563 paintOptions.setColorFilters({ PrecompileColorFilters::Matrix(),
564 PrecompileColorFilters::HSLAMatrix() });
565
566 // HSLAMatrix and Matrix map to the same color filter
567 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
568 kExpectedMatrixCFCombos + kExpectedMatrixCFCombos);
569 }
570
571 {
572 PaintOptions paintOptions;
573 paintOptions.setColorFilters({ PrecompileColorFilters::LinearToSRGBGamma(),
574 PrecompileColorFilters::SRGBToLinearGamma() });
575
576 // LinearToSRGB and SRGBToLinear both map to the colorspace colorfilter
577 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions,
578 kExpectedColorSpaceCFCombos + kExpectedColorSpaceCFCombos);
579 }
580
581 {
582 // The lerp colorfilter just generates the cross product of its children.
583 static constexpr int kExpectedNumOptions =
584 kExpectedMatrixCFCombos * (kExpectedBlendCFCombos + kExpectedOverdrawCFCombos) +
585 kExpectedLumaCFCombos * (kExpectedBlendCFCombos + kExpectedOverdrawCFCombos);
586
587 PaintOptions paintOptions;
588 paintOptions.setColorFilters(
589 { PrecompileColorFilters::Lerp(
590 { PrecompileColorFilters::Matrix(), PrecompileColorFilters::Luma() },
591 { PrecompileColorFilters::Blend(), PrecompileColorFilters::Overdraw() }) });
592
593 run_test(keyContext, gatherer, renderPassDesc, reporter, paintOptions, kExpectedNumOptions);
594 }
595 }
596
597 } // anonymous namespace
598
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest,reporter,context,CtsEnforcement::kNextRelease)599 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest, reporter, context,
600 CtsEnforcement::kNextRelease) {
601 ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
602
603 auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
604
605 SkColorInfo ci(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
606 KeyContext keyContext(context->priv().caps(), dict, rtEffectDict.get(), ci);
607
608 PipelineDataGatherer gatherer(Layout::kMetal);
609
610 RenderPassDesc unusedRenderPassDesc;
611
612 // The default PaintOptions should create a single combination with a solid color shader and
613 // kSrcOver blending
614 {
615 PaintOptions paintOptions;
616
617 run_test(keyContext, &gatherer, unusedRenderPassDesc, reporter, paintOptions,
618 /* expectedNumOptions= */ 1);
619 }
620
621 blend_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
622 shader_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
623 colorfilter_subtest(keyContext, &gatherer, unusedRenderPassDesc, reporter);
624
625 no_blend_mode_option_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
626 big_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
627 runtime_effect_test(keyContext, &gatherer, unusedRenderPassDesc, reporter);
628 }
629
630 #endif // SK_GRAPHITE
631