• 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 "src/gpu/graphite/ContextPriv.h"
15 #include "src/gpu/graphite/FactoryFunctions.h"
16 #include "src/gpu/graphite/KeyContext.h"
17 #include "src/gpu/graphite/PaintOptionsPriv.h"
18 #include "src/gpu/graphite/Precompile.h"
19 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
20 
21 #include <array>
22 
23 using namespace::skgpu::graphite;
24 
25 namespace {
26 
27 // The default PaintOptions should create a single combination with a solid color shader and
28 // kSrcOver blending
empty_test(const KeyContext & keyContext,skiatest::Reporter * reporter)29 void empty_test(const KeyContext& keyContext, skiatest::Reporter* reporter) {
30     PaintOptions paintOptions;
31 
32     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1);
33 
34     std::vector<UniquePaintParamsID> precompileIDs;
35     paintOptions.priv().buildCombinations(keyContext,
36                                           /* addPrimitiveBlender= */ false,
37                                           [&](UniquePaintParamsID id) {
38                                               precompileIDs.push_back(id);
39                                           });
40 
41     SkASSERT(precompileIDs.size() == 1);
42 }
43 
44 // A PaintOptions will supply a default solid color shader if needed.
no_shader_option_test(const KeyContext & keyContext,skiatest::Reporter * reporter)45 void no_shader_option_test(const KeyContext& keyContext, skiatest::Reporter* reporter) {
46     SkBlendMode blendModes[] = { SkBlendMode::kSrcOver };
47 
48     PaintOptions paintOptions;
49     paintOptions.setBlendModes(blendModes);
50 
51     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1);
52 
53     std::vector<UniquePaintParamsID> precompileIDs;
54     paintOptions.priv().buildCombinations(keyContext,
55                                           /* addPrimitiveBlender= */ false,
56                                           [&](UniquePaintParamsID id) {
57                                               precompileIDs.push_back(id);
58                                           });
59 
60     SkASSERT(precompileIDs.size() == 1);
61 }
62 
63 // A default kSrcOver blend mode will be supplied if no other blend options are added
no_blend_mode_option_test(const KeyContext & keyContext,skiatest::Reporter * reporter)64 void no_blend_mode_option_test(const KeyContext& keyContext, skiatest::Reporter* reporter) {
65     PaintOptions paintOptions;
66     paintOptions.setShaders({ PrecompileShaders::Color() });
67 
68     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1);
69 
70     std::vector<UniquePaintParamsID> precompileIDs;
71     paintOptions.priv().buildCombinations(keyContext,
72                                           /* addPrimitiveBlender= */ false,
73                                           [&](UniquePaintParamsID id) {
74                                               precompileIDs.push_back(id);
75                                           });
76 
77     SkASSERT(precompileIDs.size() == 1);
78 }
79 
big_test(const KeyContext & keyContext,skiatest::Reporter * reporter)80 void big_test(const KeyContext& keyContext, skiatest::Reporter* reporter) {
81     // paintOptions (17)
82     //  |- sweepGrad_0 (2) | blendShader_0 (15)
83     //  |                     0: kSrc (1)
84     //  |                     1: (dsts) linearGrad_0 (2) | solid_0 (1)
85     //  |                     2: (srcs) linearGrad_1 (2) | blendShader_1 (3)
86     //  |                                            0: kDst (1)
87     //  |                                            1: (dsts) radGrad_0 (2) | solid_1 (1)
88     //  |                                            2: (srcs) imageShader_0 (1)
89     //  |
90     //  |- 4-built-in-blend-modes (just 1 since all are PorterDuff)
91 
92     PaintOptions paintOptions;
93 
94     // first, shaders. First top-level option (sweepGrad_0)
95     sk_sp<PrecompileShader> sweepGrad_0 = PrecompileShaders::SweepGradient();
96 
97     std::array<SkBlendMode, 1> blendModes{ SkBlendMode::kSrc };
98 
99     std::vector<SkBlendMode> moreBlendModes{ SkBlendMode::kDst };
100 
101     // Second top-level option (blendShader_0)
102     auto blendShader_0 = PrecompileShaders::Blend(
103                                 SkSpan<SkBlendMode>(blendModes),                // std::array
104                                 {                                               // initializer_list
105                                     PrecompileShaders::LinearGradient(),
106                                     PrecompileShaders::Color()
107                                 },
108                                 {
109                                     PrecompileShaders::LinearGradient(),
110                                     PrecompileShaders::Blend(
111                                             SkSpan<SkBlendMode>(moreBlendModes),// std::vector
112                                             {
113                                                 PrecompileShaders::RadialGradient(),
114                                                 PrecompileShaders::Color()
115                                             },
116                                             {
117                                                 PrecompileShaders::Image()
118                                             })
119                                 });
120 
121     paintOptions.setShaders({ sweepGrad_0, blendShader_0 });
122 
123     SkBlendMode evenMoreBlendModes[] = {
124         SkBlendMode::kSrcOver,
125         SkBlendMode::kSrc,
126         SkBlendMode::kDstOver,
127         SkBlendMode::kDst
128     };
129 
130     // now, blend modes
131     paintOptions.setBlendModes(evenMoreBlendModes);                             // c array
132 
133     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 17);
134 
135     std::vector<UniquePaintParamsID> precompileIDs;
136     paintOptions.priv().buildCombinations(keyContext,
137                                           /* addPrimitiveBlender= */ false,
138                                           [&](UniquePaintParamsID id) {
139                                               precompileIDs.push_back(id);
140                                           });
141 
142     SkASSERT(precompileIDs.size() == 17);
143 }
144 
145 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)146 std::vector<sk_sp<T>> create_runtime_combos(
147         skiatest::Reporter* reporter,
148         SkRuntimeEffect::Result effectFactory(SkString),
149         sk_sp<T> precompileFactory(sk_sp<SkRuntimeEffect>,
150                                    SkSpan<const PrecompileChildOptions> childOptions),
151         const char* redCode,
152         const char* greenCode,
153         const char* combineCode) {
154     auto [redEffect, error1] = effectFactory(SkString(redCode));
155     REPORTER_ASSERT(reporter, redEffect, "%s", error1.c_str());
156     auto [greenEffect, error2] = effectFactory(SkString(greenCode));
157     REPORTER_ASSERT(reporter, greenEffect, "%s", error2.c_str());
158     auto [combineEffect, error3] = effectFactory(SkString(combineCode));
159     REPORTER_ASSERT(reporter, combineEffect, "%s", error3.c_str());
160 
161     sk_sp<T> red = precompileFactory(redEffect, {});
162     REPORTER_ASSERT(reporter, red);
163 
164     sk_sp<T> green = precompileFactory(greenEffect, {});
165     REPORTER_ASSERT(reporter, green);
166 
167     sk_sp<T> combine = precompileFactory(combineEffect, { { red, green }, { green, red } });
168     REPORTER_ASSERT(reporter, combine);
169 
170     return { combine };
171 }
172 
runtime_effect_test(const KeyContext & keyContext,skiatest::Reporter * reporter)173 void runtime_effect_test(const KeyContext& keyContext, skiatest::Reporter* reporter) {
174     // paintOptions (8)
175     //  |- combineShader (2)
176     //  |       0: redShader   | greenShader
177     //  |       1: greenShader | redShader
178     //  |
179     //  |- combineColorFilter (2)
180     //  |       0: redColorFilter   | greenColorFilter
181     //  |       1: greenColorFilter | redColorFilter
182     //  |
183     //  |- combineBlender (2)
184     //  |       0: redBlender   | greenBlender
185     //  |       1: greenBlender | redBlender
186 
187     PaintOptions paintOptions;
188 
189     // shaders
190     {
191         static const char* kRedS = R"(
192             half4 main(vec2 fragcoord) { return half4(.5, 0, 0, .5); }
193         )";
194         static const char* kGreenS = R"(
195             half4 main(vec2 fragcoord) { return half4(0, .5, 0, .5); }
196         )";
197 
198         static const char* kCombineS = R"(
199             uniform shader first;
200             uniform shader second;
201             half4 main(vec2 fragcoords) {
202                 return first.eval(fragcoords) + second.eval(fragcoords);
203             }
204         )";
205 
206         std::vector<sk_sp<PrecompileShader>> combinations =
207                 create_runtime_combos<PrecompileShader>(reporter,
208                                                         SkRuntimeEffect::MakeForShader,
209                                                         MakePrecompileShader,
210                                                         kRedS,
211                                                         kGreenS,
212                                                         kCombineS);
213         paintOptions.setShaders(combinations);
214     }
215 
216     // color filters
217     {
218         static const char* kRedCF = R"(
219             half4 main(half4 color) { return half4(.5, 0, 0, .5); }
220         )";
221         static const char* kGreenCF = R"(
222             half4 main(half4 color) { return half4(0, .5, 0, .5); }
223         )";
224 
225         static const char* kCombineCF = R"(
226             uniform colorFilter first;
227             uniform colorFilter second;
228             half4 main(half4 color) { return first.eval(color) + second.eval(color); }
229         )";
230 
231         std::vector<sk_sp<PrecompileColorFilter>> combinations =
232                 create_runtime_combos<PrecompileColorFilter>(reporter,
233                                                              SkRuntimeEffect::MakeForColorFilter,
234                                                              MakePrecompileColorFilter,
235                                                              kRedCF,
236                                                              kGreenCF,
237                                                              kCombineCF);
238         paintOptions.setColorFilters(combinations);
239     }
240 
241     // blenders
242     {
243         static const char* kRedB = R"(
244             half4 main(half4 src, half4 dst) { return half4(.5, 0, 0, .5); }
245         )";
246         static const char* kGreenB = R"(
247             half4 main(half4 src, half4 dst) { return half4(0, .5, 0, .5); }
248         )";
249 
250         static const char* kCombineB = R"(
251             uniform blender first;
252             uniform blender second;
253             half4 main(half4 src, half4 dst) {
254                 return first.eval(src, dst) + second.eval(src, dst);
255             }
256         )";
257 
258         std::vector<sk_sp<PrecompileBlender>> combinations =
259                 create_runtime_combos<PrecompileBlender>(reporter,
260                                                          SkRuntimeEffect::MakeForBlender,
261                                                          MakePrecompileBlender,
262                                                          kRedB,
263                                                          kGreenB,
264                                                          kCombineB);
265         paintOptions.setBlenders(combinations);
266     }
267 
268     REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 8);
269 
270     std::vector<UniquePaintParamsID> precompileIDs;
271     paintOptions.priv().buildCombinations(keyContext,
272                                           /* addPrimitiveBlender= */ false,
273                                           [&](UniquePaintParamsID id) {
274                                               precompileIDs.push_back(id);
275                                           });
276 
277     SkASSERT(precompileIDs.size() == 8);
278 }
279 
280 } // anonymous namespace
281 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest,reporter,context)282 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest, reporter, context) {
283     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
284 
285     auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
286 
287     SkColorInfo ci(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
288     KeyContext keyContext(dict, rtEffectDict.get(), ci);
289 
290     empty_test(keyContext, reporter);
291     no_shader_option_test(keyContext, reporter);
292     no_blend_mode_option_test(keyContext, reporter);
293     big_test(keyContext, reporter);
294     runtime_effect_test(keyContext, reporter);
295 }
296 
297 #endif // SK_GRAPHITE
298