1 /*
2 * Copyright 2024 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/gpu/graphite/Context.h"
13 #include "include/gpu/graphite/PrecompileContext.h"
14 #include "include/gpu/graphite/precompile/PaintOptions.h"
15 #include "include/gpu/graphite/precompile/Precompile.h"
16 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
17 #include "include/gpu/graphite/precompile/PrecompileShader.h"
18 #include "src/gpu/graphite/ContextPriv.h"
19 #include "src/gpu/graphite/ContextUtils.h"
20 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
21 #include "src/gpu/graphite/PrecompileContextPriv.h"
22 #include "src/gpu/graphite/RenderPassDesc.h"
23 #include "src/gpu/graphite/RendererProvider.h"
24 #include "tools/graphite/UniqueKeyUtils.h"
25
26 using namespace::skgpu::graphite;
27
28 namespace {
29
30 // "SolidColor SrcOver"
solid_srcover()31 PaintOptions solid_srcover() {
32 PaintOptions paintOptions;
33 paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
34 return paintOptions;
35 }
36
37 // "SolidColor Src"
solid_src()38 PaintOptions solid_src() {
39 PaintOptions paintOptions;
40 paintOptions.setBlendModes({ SkBlendMode::kSrc });
41 return paintOptions;
42 }
43
44 // "LocalMatrix [ Compose [ HardwareImage(0) ColorSpaceTransform ] ] SrcOver"
image_srcover()45 PaintOptions image_srcover() {
46 PaintOptions paintOptions;
47 paintOptions.setShaders({ PrecompileShaders::Image() });
48 paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
49 return paintOptions;
50 }
51
52 // "LocalMatrix [ Compose [ HardwareImage(0) ColorSpaceTransform ] ] Src"
image_src()53 PaintOptions image_src() {
54 PaintOptions paintOptions;
55 paintOptions.setShaders({ PrecompileShaders::Image() });
56 paintOptions.setBlendModes({ SkBlendMode::kSrc });
57 return paintOptions;
58 }
59
60 // "LocalMatrix [ Compose [ LinearGradient4 ColorSpaceTransform ] ] SrcOver"
lineargrad_srcover()61 PaintOptions lineargrad_srcover() {
62 PaintOptions paintOptions;
63 paintOptions.setShaders({ PrecompileShaders::LinearGradient() });
64 paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
65 return paintOptions;
66 }
67
68 // "Compose [ LocalMatrix [ Compose [ LinearGradient4 ColorSpaceTransform ] ] Dither ] SrcOver"
lineargrad_srcover_dithered()69 PaintOptions lineargrad_srcover_dithered() {
70 PaintOptions paintOptions;
71 paintOptions.setShaders({ PrecompileShaders::LinearGradient() });
72 paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
73 paintOptions.setDither(/* dither= */ true);
74 return paintOptions;
75 }
76
77 // "Compose [ SolidColor Blend [ SolidColor Passthrough BlendModeBlender ] ] SrcOver"
blend_color_filter_srcover()78 [[maybe_unused]] PaintOptions blend_color_filter_srcover() {
79 PaintOptions paintOptions;
80 paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
81 paintOptions.setColorFilters({ PrecompileColorFilters::Blend() });
82 return paintOptions;
83 }
84
85 // "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba)"
86 // Single sampled BGRA w/ just depth
bgra_1_depth()87 RenderPassProperties bgra_1_depth() {
88 return { DepthStencilFlags::kDepth, kBGRA_8888_SkColorType, /* requiresMSAA= */ false };
89 }
90
91 // "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=39,s=4), samples: 4, swizzle: rgba)"
92 // MSAA BGRA w/ just depth
bgra_4_depth()93 RenderPassProperties bgra_4_depth() {
94 return { DepthStencilFlags::kDepth, kBGRA_8888_SkColorType, /* requiresMSAA= */ true };
95 }
96
97 // "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba)"
98 // MSAA BGRA w/ depth and stencil
bgra_4_depth_stencil()99 RenderPassProperties bgra_4_depth_stencil() {
100 return { DepthStencilFlags::kDepthStencil, kBGRA_8888_SkColorType, /* requiresMSAA= */ true };
101 }
102
103 // Precompile with the provided paintOptions, drawType, and RenderPassSettings then verify that
104 // the expected string is in the generated set.
105 // Additionally, verify that overgeneration is within expected tolerances.
106 // If you add an additional RenderStep you may need to increase the tolerance values.
run_test(PrecompileContext * precompileContext,skiatest::Reporter * reporter,const char * expectedString,size_t caseID,const PaintOptions & paintOptions,DrawTypeFlags drawType,const RenderPassProperties & renderPassSettings,unsigned int allowedOvergeneration)107 void run_test(PrecompileContext* precompileContext,
108 skiatest::Reporter* reporter,
109 const char* expectedString, size_t caseID,
110 const PaintOptions& paintOptions,
111 DrawTypeFlags drawType,
112 const RenderPassProperties& renderPassSettings,
113 unsigned int allowedOvergeneration) {
114
115 precompileContext->priv().globalCache()->resetGraphicsPipelines();
116
117 Precompile(precompileContext, paintOptions, drawType, { &renderPassSettings, 1 });
118
119 std::vector<std::string> generated;
120
121 {
122 const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
123 const ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
124
125 std::vector<skgpu::UniqueKey> generatedKeys;
126
127 UniqueKeyUtils::FetchUniqueKeys(precompileContext, &generatedKeys);
128
129 for (const skgpu::UniqueKey& key : generatedKeys) {
130 GraphicsPipelineDesc pipelineDesc;
131 RenderPassDesc renderPassDesc;
132 UniqueKeyUtils::ExtractKeyDescs(precompileContext, key, &pipelineDesc, &renderPassDesc);
133
134 const RenderStep* renderStep = rendererProvider->lookup(pipelineDesc.renderStepID());
135 generated.push_back(GetPipelineLabel(dict, renderPassDesc, renderStep,
136 pipelineDesc.paintParamsID()));
137 }
138 }
139
140 bool correctGenerationAmt = generated.size() == allowedOvergeneration;
141 REPORTER_ASSERT(reporter, correctGenerationAmt,
142 "case %zu overgenerated - %zu > %d\n",
143 caseID, generated.size(), allowedOvergeneration);
144
145 const size_t len = strlen(expectedString);
146
147 bool foundIt = false;
148 for (size_t i = 0; i < generated.size(); ++i) {
149 // The generated strings have trailing whitespace
150 if (!strncmp(expectedString, generated[i].c_str(), len)) {
151 foundIt = true;
152 break;
153 }
154 }
155
156 REPORTER_ASSERT(reporter, foundIt);
157
158 #ifdef SK_DEBUG
159 if (foundIt && correctGenerationAmt) {
160 return;
161 }
162
163 SkDebugf("Expected string:\n%s\n%s in %zu strings:\n",
164 expectedString,
165 foundIt ? "found" : "NOT found",
166 generated.size());
167
168 for (size_t i = 0; i < generated.size(); ++i) {
169 SkDebugf("%zu: %s\n", i, generated[i].c_str());
170 }
171 #endif
172 }
173
174 // The pipeline strings were created using the Dawn Metal backend so that is the only viable
175 // comparison
is_dawn_metal_context_type(skgpu::ContextType type)176 bool is_dawn_metal_context_type(skgpu::ContextType type) {
177 return type == skgpu::ContextType::kDawn_Metal;
178 }
179
180 } // anonymous namespace
181
182
183 DEF_GRAPHITE_TEST_FOR_CONTEXTS(ChromePrecompileTest, is_dawn_metal_context_type,
184 reporter, context, /* testContext */, CtsEnforcement::kNever) {
185
186 std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
187 const skgpu::graphite::Caps* caps = precompileContext->priv().caps();
188
189 TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(kBGRA_8888_SkColorType,
190 skgpu::Mipmapped::kNo,
191 skgpu::Protected::kNo,
192 skgpu::Renderable::kYes);
193
194 TextureInfo msaaTex = caps->getDefaultMSAATextureInfo(textureInfo, Discardable::kYes);
195
196 if (msaaTex.numSamples() <= 1) {
197 // The following pipelines rely on having MSAA
198 return;
199 }
200
201 #ifdef SK_ENABLE_VELLO_SHADERS
202 if (caps->computeSupport()) {
203 // The following pipelines rely on not utilizing Vello
204 return;
205 }
206 #endif
207
208 // In the following, here is the Dawn mapping from surface type to ID
209 // RGBA8Unorm = 18
210 // BGRA8Unorm = 23
211 // Depth16Unorm = 39
212 // Depth24PlusStencil8 = 41
213
214 const char* kCases[] = {
215 // Wikipedia 2018 - these are reordered from the spreadsheet
216 /* 0 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
217 "TessellateWedgesRenderStep[winding] + "
218 "(empty)",
219 /* 1 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
220 "TessellateWedgesRenderStep[evenodd] + "
221 "(empty)",
222 /* 2 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
223 "CoverBoundsRenderStep[non-aa-fill] + "
224 "SolidColor SrcOver",
225 /* 3 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
226 "CoverBoundsRenderStep[non-aa-fill] + "
227 "SolidColor Src",
228 /* 4 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
229 "PerEdgeAAQuadRenderStep + "
230 "LocalMatrix [ Compose [ Image(0) ColorSpaceTransform ] ] SrcOver",
231 /* 5 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
232 "PerEdgeAAQuadRenderStep + "
233 "LocalMatrix [ Compose [ HardwareImage(0) ColorSpaceTransform ] ] SrcOver",
234 /* 6 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
235 "CoverBoundsRenderStep[non-aa-fill] + "
236 "LocalMatrix [ Compose [ HardwareImage(0) ColorSpaceTransform ] ] SrcOver",
237 /* 7 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
238 "AnalyticRRectRenderStep + "
239 "Compose [ LocalMatrix [ Compose [ LinearGradient4 ColorSpaceTransform ] ] Dither ] SrcOver",
240 /* 8 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
241 "CoverBoundsRenderStep[non-aa-fill] + "
242 "Compose [ LocalMatrix [ Compose [ LinearGradient4 ColorSpaceTransform ] ] Dither ] SrcOver",
243 /* 9 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
244 "BitmapTextRenderStep[mask] + "
245 "LocalMatrix [ Compose [ LinearGradient4 ColorSpaceTransform ] ] SrcOver",
246 /* 10 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=41,s=4), samples: 4, swizzle: rgba) + "
247 "BitmapTextRenderStep[mask] + "
248 "SolidColor SrcOver",
249 /* 11 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
250 "AnalyticRRectRenderStep + "
251 "SolidColor SrcOver",
252 /* 12 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
253 "CoverBoundsRenderStep[non-aa-fill] + "
254 "SolidColor SrcOver",
255 /* 13 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
256 "PerEdgeAAQuadRenderStep + "
257 "LocalMatrix [ Compose [ HardwareImage(0) ColorSpaceTransform ] ] Src",
258 /* 14 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
259 "CoverBoundsRenderStep[non-aa-fill] + "
260 "LocalMatrix [ Compose [ HardwareImage(0) ColorSpaceTransform ] ] SrcOver",
261 /* 15 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=39,s=4), samples: 4, swizzle: rgba) + "
262 "TessellateWedgesRenderStep[convex] + "
263 "SolidColor SrcOver",
264 /* 16 */ "RP(color: Dawn(f=23,s=4), resolve: Dawn(f=23,s=1), ds: Dawn(f=39,s=4), samples: 4, swizzle: rgba) + "
265 "TessellateStrokesRenderStep + "
266 "SolidColor SrcOver",
267 /* 17 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
268 "AnalyticBlurRenderStep + "
269 "Compose [ SolidColor Blend [ SolidColor Passthrough BlendModeBlender ] ] SrcOver",
270 /* 18 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
271 "CoverBoundsRenderStep[non-aa-fill] + "
272 "SolidColor Src",
273 /* 19 */ "RP(color: Dawn(f=23,s=1), resolve: {}, ds: Dawn(f=39,s=1), samples: 1, swizzle: rgba) + "
274 "CoverBoundsRenderStep[non-aa-fill] + "
275 "Compose [ LocalMatrix [ Compose [ LinearGradient4 ColorSpaceTransform ] ] Dither ] SrcOver",
276 };
277
278 for (size_t i = 0; i < std::size(kCases); ++i) {
279 PaintOptions paintOptions;
280 DrawTypeFlags drawTypeFlags = DrawTypeFlags::kSimpleShape;
281 RenderPassProperties renderPassSettings;
282 unsigned int allowedOvergeneration = 0;
283
284 switch (i) {
285 case 0: [[fallthrough]];
286 case 1:
287 paintOptions = solid_srcover();
288 drawTypeFlags = DrawTypeFlags::kNonSimpleShape;
289 renderPassSettings = bgra_4_depth_stencil();
290 allowedOvergeneration = 11;
291 break;
292 case 2:
293 paintOptions = solid_srcover();
294 drawTypeFlags = DrawTypeFlags::kSimpleShape;
295 renderPassSettings = bgra_4_depth_stencil();
296 allowedOvergeneration = 5;
297 break;
298 case 3: // only differs from 18 by MSAA and depth vs depth-stencil
299 paintOptions = solid_src();
300 drawTypeFlags = DrawTypeFlags::kSimpleShape;
301 renderPassSettings = bgra_4_depth_stencil();
302 allowedOvergeneration = 5; // a lot for a rectangle clear - all RenderSteps
303 break;
304 case 4: // 4 is part of an AA image rect draw that can't use HW tiling
305 case 5: // 5 & 6 together make up an AA image rect draw w/ a filled center
306 case 6:
307 paintOptions = image_srcover();
308 drawTypeFlags = DrawTypeFlags::kSimpleShape;
309 renderPassSettings = bgra_4_depth_stencil();
310 allowedOvergeneration = 30;
311 break;
312 case 7: // 7 & 8 are combined pair
313 case 8:
314 paintOptions = lineargrad_srcover_dithered();
315 drawTypeFlags = DrawTypeFlags::kSimpleShape;
316 renderPassSettings = bgra_4_depth_stencil();
317 allowedOvergeneration = 15; // 3x from gradient, 12x from RenderSteps
318 break;
319 case 9:
320 paintOptions = lineargrad_srcover();
321 drawTypeFlags = DrawTypeFlags::kBitmapText_Mask;
322 renderPassSettings = bgra_4_depth_stencil();
323 allowedOvergeneration = 3; // from the 3 internal gradient alternatives
324 break;
325 case 10:
326 paintOptions = solid_srcover();
327 drawTypeFlags = DrawTypeFlags::kBitmapText_Mask;
328 renderPassSettings = bgra_4_depth_stencil();
329 allowedOvergeneration = 1;
330 break;
331 case 11: // 11 & 12 are a pair - an RRect draw w/ a non-aa-fill center
332 case 12:
333 paintOptions = solid_srcover();
334 drawTypeFlags = DrawTypeFlags::kSimpleShape;
335 renderPassSettings = bgra_1_depth();
336 allowedOvergeneration = 5; // all from RenderSteps
337 break;
338 case 13:
339 paintOptions = image_src();
340 drawTypeFlags = DrawTypeFlags::kSimpleShape;
341 renderPassSettings = bgra_1_depth();
342 // This is a lot for a kSrc image draw:
343 allowedOvergeneration = 30; // 3x of this are the paint combos,
344 // the rest are the RenderSteps!!
345 break;
346 case 14:
347 paintOptions = image_srcover();
348 drawTypeFlags = DrawTypeFlags::kSimpleShape;
349 renderPassSettings = bgra_1_depth();
350 allowedOvergeneration = 30; // !!!! - a lot for just a non-aa image rect draw
351 break;
352 case 15:
353 case 16:
354 paintOptions = solid_srcover();
355 drawTypeFlags = DrawTypeFlags::kNonSimpleShape;
356 renderPassSettings = bgra_4_depth();
357 allowedOvergeneration = 11;
358 break;
359 case 17:
360 // After https://skia-review.googlesource.com/c/skia/+/887476 ([graphite] Split up
361 // universal blend shader snippet) this case no longer exists/is reproducible.
362 //
363 // paintOptions = blend_color_filter_srcover();
364 // drawTypeFlags = DrawTypeFlags::kSimpleShape;
365 // renderPassSettings = bgra_1_depth();
366 // allowedOvergeneration = 4;
367 continue;
368 case 18: // only differs from 3 by MSAA and depth vs depth-stencil
369 paintOptions = solid_src();
370 drawTypeFlags = DrawTypeFlags::kSimpleShape;
371 renderPassSettings = bgra_1_depth();
372 allowedOvergeneration = 5; // a lot for a rectangle clear - all RenderSteps
373 break;
374 case 19:
375 paintOptions = lineargrad_srcover_dithered();
376 drawTypeFlags = DrawTypeFlags::kSimpleShape;
377 renderPassSettings = bgra_1_depth();
378 allowedOvergeneration = 15; // 3x from gradient, rest from RenderSteps
379 break;
380 default:
381 continue;
382 }
383
384 if (renderPassSettings.fRequiresMSAA && caps->loadOpAffectsMSAAPipelines()) {
385 allowedOvergeneration *= 2; // due to ExpandResolveTextureLoadOp
386 }
387
388 run_test(precompileContext.get(), reporter,
389 kCases[i], i,
390 paintOptions, drawTypeFlags, renderPassSettings, allowedOvergeneration);
391 }
392 }
393
394 #endif // SK_GRAPHITE
395