• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/PrecompileShader.h"
16 #include "src/gpu/graphite/ContextPriv.h"
17 #include "src/gpu/graphite/FactoryFunctions.h"
18 #include "src/gpu/graphite/KeyContext.h"
19 #include "src/gpu/graphite/PipelineData.h"
20 #include "src/gpu/graphite/PrecompileInternal.h"
21 #include "src/gpu/graphite/Renderer.h"
22 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
23 #include "src/gpu/graphite/precompile/PaintOptionsPriv.h"
24 
25 #include <array>
26 
27 using namespace::skgpu::graphite;
28 
29 namespace {
30 
31 // 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,skiatest::Reporter * reporter)32 void no_blend_mode_option_test(const KeyContext& keyContext,
33                                PipelineDataGatherer* gatherer,
34                                skiatest::Reporter* reporter) {
35     PaintOptions paintOptions;
36     paintOptions.setShaders({ PrecompileShaders::Color() });
37 
38     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1);
39 
40     std::vector<UniquePaintParamsID> precompileIDs;
41     paintOptions.priv().buildCombinations(keyContext,
42                                           gatherer,
43                                           DrawTypeFlags::kNone,
44                                           /* withPrimitiveBlender= */ false,
45                                           Coverage::kNone,
46                                           [&precompileIDs](UniquePaintParamsID id,
47                                                            DrawTypeFlags,
48                                                            bool /* withPrimitiveBlender */,
49                                                            Coverage) {
50                                                                precompileIDs.push_back(id);
51                                                            });
52 
53     SkASSERT(precompileIDs.size() == 1);
54 }
55 
56 // This test checks that the 'PaintOptions::numCombinations' method and the number actually
57 // generated by 'buildCombinations' agree with the expected number of combinations.
run_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,skiatest::Reporter * reporter,const PaintOptions & paintOptions,int expectedNumOptions)58 void run_test(const KeyContext& keyContext,
59               PipelineDataGatherer* gatherer,
60               skiatest::Reporter* reporter,
61               const PaintOptions& paintOptions,
62               int expectedNumOptions) {
63 
64     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == expectedNumOptions);
65 
66     std::vector<UniquePaintParamsID> precompileIDs;
67     paintOptions.priv().buildCombinations(keyContext,
68                                           gatherer,
69                                           DrawTypeFlags::kNone,
70                                           /* withPrimitiveBlender= */ false,
71                                           Coverage::kNone,
72                                           [&precompileIDs](UniquePaintParamsID id,
73                                                            DrawTypeFlags,
74                                                            bool /* withPrimitiveBlender */,
75                                                            Coverage) {
76                                               precompileIDs.push_back(id);
77                                           });
78 
79     SkASSERT(static_cast<int>(precompileIDs.size()) == expectedNumOptions);
80 }
81 
big_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,skiatest::Reporter * reporter)82 void big_test(const KeyContext& keyContext,
83               PipelineDataGatherer* gatherer,
84               skiatest::Reporter* reporter) {
85     // paintOptions (248)
86     //  |- sweepGrad_0 (2) | blendShader_0 (60)
87     //  |                     0: kSrc (1)
88     //  |                     1: (dsts) linearGrad_0 (2) | solid_0 (1)
89     //  |                     2: (srcs) linearGrad_1 (2) | blendShader_1 (18)
90     //  |                                                   0: kDst (1)
91     //  |                                                   1: (dsts) radGrad_0 (2) | solid_1 (1)
92     //  |                                                   2: (srcs) imageShader_0 (6)
93     //  |
94     //  |- 4-built-in-blend-modes
95 
96     PaintOptions paintOptions;
97 
98     // first, shaders. First top-level option (sweepGrad_0)
99     sk_sp<PrecompileShader> sweepGrad_0 = PrecompileShaders::SweepGradient();
100 
101     std::array<SkBlendMode, 1> blendModes{ SkBlendMode::kSrc };
102 
103     std::vector<SkBlendMode> moreBlendModes{ SkBlendMode::kDst };
104 
105     // Second top-level option (blendShader_0)
106     auto blendShader_0 = PrecompileShaders::Blend(
107                                 SkSpan<const SkBlendMode>(blendModes),          // std::array
108                                 {                                               // initializer_list
109                                     PrecompileShaders::LinearGradient(),
110                                     PrecompileShaders::Color()
111                                 },
112                                 {
113                                     PrecompileShaders::LinearGradient(),
114                                     PrecompileShaders::Blend(
115                                             SkSpan<const SkBlendMode>(moreBlendModes),// std::vector
116                                             {
117                                                 PrecompileShaders::RadialGradient(),
118                                                 PrecompileShaders::Color()
119                                             },
120                                             {
121                                                 PrecompileShaders::Image()
122                                             })
123                                 });
124 
125     paintOptions.setShaders({ sweepGrad_0, blendShader_0 });
126 
127     static const SkBlendMode kEvenMoreBlendModes[] = {
128         SkBlendMode::kSrcOver,
129         SkBlendMode::kSrc,
130         SkBlendMode::kDstOver,
131         SkBlendMode::kDst
132     };
133 
134     // now, blend modes
135     paintOptions.setBlendModes(kEvenMoreBlendModes);                             // c array
136 
137     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 248,
138                     "Actual # of combinations %d", paintOptions.priv().numCombinations());
139 
140     std::vector<UniquePaintParamsID> precompileIDs;
141     paintOptions.priv().buildCombinations(keyContext,
142                                           gatherer,
143                                           DrawTypeFlags::kNone,
144                                           /* withPrimitiveBlender= */ false,
145                                           Coverage::kNone,
146                                           [&precompileIDs](UniquePaintParamsID id,
147                                                            DrawTypeFlags,
148                                                            bool /* withPrimitiveBlender */,
149                                                            Coverage) {
150                                                                precompileIDs.push_back(id);
151                                                            });
152 
153     SkASSERT(precompileIDs.size() == 248);
154 }
155 
156 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 * combineCode)157 std::vector<sk_sp<T>> create_runtime_combos(
158         skiatest::Reporter* reporter,
159         SkRuntimeEffect::Result effectFactory(SkString),
160         sk_sp<T> precompileFactory(sk_sp<SkRuntimeEffect>,
161                                    SkSpan<const PrecompileChildOptions> childOptions),
162         const char* redCode,
163         const char* greenCode,
164         const char* combineCode) {
165     auto [redEffect, error1] = effectFactory(SkString(redCode));
166     REPORTER_ASSERT(reporter, redEffect, "%s", error1.c_str());
167     auto [greenEffect, error2] = effectFactory(SkString(greenCode));
168     REPORTER_ASSERT(reporter, greenEffect, "%s", error2.c_str());
169     auto [combineEffect, error3] = effectFactory(SkString(combineCode));
170     REPORTER_ASSERT(reporter, combineEffect, "%s", error3.c_str());
171 
172     sk_sp<T> red = precompileFactory(redEffect, {});
173     REPORTER_ASSERT(reporter, red);
174 
175     sk_sp<T> green = precompileFactory(greenEffect, {});
176     REPORTER_ASSERT(reporter, green);
177 
178     sk_sp<T> combine = precompileFactory(combineEffect, { { red, green }, { green, red } });
179     REPORTER_ASSERT(reporter, combine);
180 
181     return { combine };
182 }
183 
runtime_effect_test(const KeyContext & keyContext,PipelineDataGatherer * gatherer,skiatest::Reporter * reporter)184 void runtime_effect_test(const KeyContext& keyContext,
185                          PipelineDataGatherer* gatherer,
186                          skiatest::Reporter* reporter) {
187     // paintOptions (8)
188     //  |- combineShader (2)
189     //  |       0: redShader   | greenShader
190     //  |       1: greenShader | redShader
191     //  |
192     //  |- combineColorFilter (2)
193     //  |       0: redColorFilter   | greenColorFilter
194     //  |       1: greenColorFilter | redColorFilter
195     //  |
196     //  |- combineBlender (2)
197     //  |       0: redBlender   | greenBlender
198     //  |       1: greenBlender | redBlender
199 
200     PaintOptions paintOptions;
201 
202     // shaders
203     {
204         static const char* kRedS = R"(
205             half4 main(vec2 fragcoord) { return half4(.5, 0, 0, .5); }
206         )";
207         static const char* kGreenS = R"(
208             half4 main(vec2 fragcoord) { return half4(0, .5, 0, .5); }
209         )";
210 
211         static const char* kCombineS = R"(
212             uniform shader first;
213             uniform shader second;
214             half4 main(vec2 fragcoords) {
215                 return first.eval(fragcoords) + second.eval(fragcoords);
216             }
217         )";
218 
219         std::vector<sk_sp<PrecompileShader>> combinations =
220                 create_runtime_combos<PrecompileShader>(reporter,
221                                                         SkRuntimeEffect::MakeForShader,
222                                                         MakePrecompileShader,
223                                                         kRedS,
224                                                         kGreenS,
225                                                         kCombineS);
226         paintOptions.setShaders(combinations);
227     }
228 
229     // color filters
230     {
231         static const char* kRedCF = R"(
232             half4 main(half4 color) { return half4(.5, 0, 0, .5); }
233         )";
234         static const char* kGreenCF = R"(
235             half4 main(half4 color) { return half4(0, .5, 0, .5); }
236         )";
237 
238         static const char* kCombineCF = R"(
239             uniform colorFilter first;
240             uniform colorFilter second;
241             half4 main(half4 color) { return first.eval(color) + second.eval(color); }
242         )";
243 
244         std::vector<sk_sp<PrecompileColorFilter>> combinations =
245                 create_runtime_combos<PrecompileColorFilter>(reporter,
246                                                              SkRuntimeEffect::MakeForColorFilter,
247                                                              MakePrecompileColorFilter,
248                                                              kRedCF,
249                                                              kGreenCF,
250                                                              kCombineCF);
251         paintOptions.setColorFilters(combinations);
252     }
253 
254     // blenders
255     {
256         static const char* kRedB = R"(
257             half4 main(half4 src, half4 dst) { return half4(.5, 0, 0, .5); }
258         )";
259         static const char* kGreenB = R"(
260             half4 main(half4 src, half4 dst) { return half4(0, .5, 0, .5); }
261         )";
262 
263         static const char* kCombineB = R"(
264             uniform blender first;
265             uniform blender second;
266             half4 main(half4 src, half4 dst) {
267                 return first.eval(src, dst) + second.eval(src, dst);
268             }
269         )";
270 
271         std::vector<sk_sp<PrecompileBlender>> combinations =
272                 create_runtime_combos<PrecompileBlender>(reporter,
273                                                          SkRuntimeEffect::MakeForBlender,
274                                                          MakePrecompileBlender,
275                                                          kRedB,
276                                                          kGreenB,
277                                                          kCombineB);
278         paintOptions.setBlenders(combinations);
279     }
280 
281     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 8);
282 
283     std::vector<UniquePaintParamsID> precompileIDs;
284     paintOptions.priv().buildCombinations(keyContext,
285                                           gatherer,
286                                           DrawTypeFlags::kNone,
287                                           /* withPrimitiveBlender= */ false,
288                                           Coverage::kNone,
289                                           [&precompileIDs](UniquePaintParamsID id,
290                                                            DrawTypeFlags,
291                                                            bool /* withPrimitiveBlender */,
292                                                            Coverage) {
293                                                                precompileIDs.push_back(id);
294                                                            });
295 
296     SkASSERT(precompileIDs.size() == 8);
297 }
298 
299 } // anonymous namespace
300 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest,reporter,context,CtsEnforcement::kNextRelease)301 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest, reporter, context,
302                                    CtsEnforcement::kNextRelease) {
303     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
304 
305     auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
306 
307     SkColorInfo ci(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
308     KeyContext keyContext(context->priv().caps(),
309                           dict,
310                           rtEffectDict.get(),
311                           ci,
312                           /* dstTexture= */ nullptr,
313                           /* dstOffset= */ {0, 0});
314 
315     PipelineDataGatherer gatherer(context->priv().caps(), Layout::kMetal);
316 
317     // The default PaintOptions should create a single combination with a solid color shader and
318     // kSrcOver blending
319     {
320         PaintOptions paintOptions;
321 
322         run_test(keyContext, &gatherer, reporter, paintOptions, /* expectedNumOptions= */ 1);
323     }
324 
325     // The BlendMode PrecompileBlender only ever has 1 combination
326     {
327         PaintOptions paintOptions;
328         paintOptions.setBlenders({ PrecompileBlenders::Mode(SkBlendMode::kColorDodge) });
329 
330         run_test(keyContext, &gatherer, reporter, paintOptions, /* expectedNumOptions= */ 1);
331     }
332 
333     // Specifying the BlendMode PrecompileBlender by SkBlendMode should also only ever
334     // yield 1 combination.
335     {
336         SkBlendMode blendModes[] = { SkBlendMode::kSrcOver };
337 
338         PaintOptions paintOptions;
339         paintOptions.setBlendModes(blendModes);
340 
341         run_test(keyContext, &gatherer, reporter, paintOptions, /* expectedNumOptions= */ 1);
342     }
343 
344     // The Arithmetic PrecompileBlender only ever has 1 combination
345     {
346         PaintOptions paintOptions;
347         paintOptions.setBlenders({ PrecompileBlenders::Arithmetic() });
348 
349         run_test(keyContext, &gatherer, reporter, paintOptions, /* expectedNumOptions= */ 1);
350     }
351 
352     no_blend_mode_option_test(keyContext, &gatherer, reporter);
353     big_test(keyContext, &gatherer, reporter);
354     runtime_effect_test(keyContext, &gatherer, reporter);
355 }
356 
357 #endif // SK_GRAPHITE
358