• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 #include "bench/Benchmark.h"
8 #include "bench/ResultsWriter.h"
9 #include "bench/SkSLBench.h"
10 #include "include/core/SkCanvas.h"
11 #include "src/gpu/ganesh/GrCaps.h"
12 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
13 #include "src/gpu/ganesh/mock/GrMockCaps.h"
14 #include "src/sksl/SkSLCompiler.h"
15 #include "src/sksl/SkSLModuleLoader.h"
16 #include "src/sksl/SkSLParser.h"
17 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
18 #include "src/sksl/ir/SkSLProgram.h"
19 
20 #include <regex>
21 
22 #include "src/sksl/generated/sksl_shared.minified.sksl"
23 #include "src/sksl/generated/sksl_compute.minified.sksl"
24 #include "src/sksl/generated/sksl_frag.minified.sksl"
25 #include "src/sksl/generated/sksl_gpu.minified.sksl"
26 #include "src/sksl/generated/sksl_public.minified.sksl"
27 #include "src/sksl/generated/sksl_rt_shader.minified.sksl"
28 #include "src/sksl/generated/sksl_vert.minified.sksl"
29 #if defined(SK_GRAPHITE)
30 #include "src/sksl/generated/sksl_graphite_frag.minified.sksl"
31 #include "src/sksl/generated/sksl_graphite_vert.minified.sksl"
32 #endif
33 
34 class SkSLCompilerStartupBench : public Benchmark {
35 protected:
onGetName()36     const char* onGetName() override {
37         return "sksl_compiler_startup";
38     }
39 
isSuitableFor(Backend backend)40     bool isSuitableFor(Backend backend) override {
41         return backend == kNonRendering_Backend;
42     }
43 
onDraw(int loops,SkCanvas *)44     void onDraw(int loops, SkCanvas*) override {
45         GrShaderCaps caps;
46         for (int i = 0; i < loops; i++) {
47             SkSL::Compiler compiler(&caps);
48         }
49     }
50 };
51 
52 DEF_BENCH(return new SkSLCompilerStartupBench();)
53 
54 enum class Output {
55     kNone,
56     kGLSL,
57     kMetal,
58     kSPIRV,
59     kSkVM,     // raw SkVM bytecode
60     kSkVMOpt,  // optimized SkVM bytecode
61     kSkVMJIT,  // optimized native assembly code
62 };
63 
64 class SkSLCompileBench : public Benchmark {
65 public:
output_string(Output output)66     static const char* output_string(Output output) {
67         switch (output) {
68             case Output::kNone:    return "";
69             case Output::kGLSL:    return "glsl_";
70             case Output::kMetal:   return "metal_";
71             case Output::kSPIRV:   return "spirv_";
72             case Output::kSkVM:    return "skvm_";
73             case Output::kSkVMOpt: return "skvm_opt_";
74             case Output::kSkVMJIT: return "skvm_jit_";
75         }
76         SkUNREACHABLE;
77     }
78 
SkSLCompileBench(std::string name,const char * src,bool optimize,Output output)79     SkSLCompileBench(std::string name, const char* src, bool optimize, Output output)
80             : fName(std::string("sksl_") + (optimize ? "" : "unoptimized_") +
81                     output_string(output) + name)
82             , fSrc(src)
83             , fCaps(GrContextOptions(), GrMockOptions())
84             , fCompiler(fCaps.shaderCaps())
85             , fOutput(output) {
86         fSettings.fOptimize = optimize;
87         // The test programs we compile don't follow Vulkan rules and thus produce invalid SPIR-V.
88         // This is harmless, so long as we don't try to validate them.
89         fSettings.fValidateSPIRV = false;
90 
91         this->fixUpSource();
92     }
93 
94 protected:
onGetName()95     const char* onGetName() override {
96         return fName.c_str();
97     }
98 
isSuitableFor(Backend backend)99     bool isSuitableFor(Backend backend) override {
100         return backend == kNonRendering_Backend;
101     }
102 
usesRuntimeShader() const103     bool usesRuntimeShader() const {
104         return fOutput >= Output::kSkVM;
105     }
106 
fixUpSource()107     void fixUpSource() {
108         auto fixup = [this](const char* input, const char* replacement) {
109             fSrc = std::regex_replace(fSrc, std::regex(input), replacement);
110         };
111 
112         // Runtime shaders which have slightly different conventions than fragment shaders.
113         // Perform a handful of fixups to compensate. These are hand-tuned for our current set of
114         // test shaders and will probably need to be updated if we add more.
115         if (this->usesRuntimeShader()) {
116             fixup(R"(void main\(\))",                              "half4 main(float2 xy)");
117             fixup(R"(sk_FragColor =)",                             "return");
118             fixup(R"(sk_FragCoord)",                               "_FragCoord");
119             fixup(R"(uniform sampler2D )",                         "uniform shader ");
120             fixup(R"((flat |noperspective |)in )",                 "uniform ");
121             fixup(R"(sample\(([A-Za-z0-9_]+), ([A-Za-z0-9_]+)\))", "$01.eval($02)");
122             fSrc = "#version 300\nuniform float4 _FragCoord;\n" + fSrc;
123         }
124     }
125 
onDraw(int loops,SkCanvas * canvas)126     void onDraw(int loops, SkCanvas* canvas) override {
127         const SkSL::ProgramKind kind = this->usesRuntimeShader() ? SkSL::ProgramKind::kRuntimeShader
128                                                                  : SkSL::ProgramKind::kFragment;
129         for (int i = 0; i < loops; i++) {
130             std::unique_ptr<SkSL::Program> program = fCompiler.convertProgram(kind, fSrc,
131                                                                               fSettings);
132             if (fCompiler.errorCount()) {
133                 SK_ABORT("shader compilation failed: %s\n", fCompiler.errorText().c_str());
134             }
135             std::string result;
136             switch (fOutput) {
137                 case Output::kNone:    break;
138                 case Output::kGLSL:    SkAssertResult(fCompiler.toGLSL(*program,  &result)); break;
139                 case Output::kMetal:   SkAssertResult(fCompiler.toMetal(*program, &result)); break;
140                 case Output::kSPIRV:   SkAssertResult(fCompiler.toSPIRV(*program, &result)); break;
141                 case Output::kSkVM:
142                 case Output::kSkVMOpt:
143                 case Output::kSkVMJIT: SkAssertResult(CompileToSkVM(*program, fOutput)); break;
144             }
145         }
146     }
147 
CompileToSkVM(const SkSL::Program & program,Output mode)148     static bool CompileToSkVM(const SkSL::Program& program, Output mode) {
149         const bool optimize = (mode >= Output::kSkVMOpt);
150         const bool allowJIT = (mode >= Output::kSkVMJIT);
151         skvm::Builder builder{skvm::Features{}};
152         if (!SkSL::testingOnly_ProgramToSkVMShader(program, &builder, /*debugTrace=*/nullptr)) {
153             return false;
154         }
155         if (optimize) {
156             builder.done("SkSLBench", allowJIT);
157         }
158         return true;
159     }
160 
161 private:
162     std::string fName;
163     std::string fSrc;
164     GrMockCaps fCaps;
165     SkSL::Compiler fCompiler;
166     SkSL::ProgramSettings fSettings;
167     Output fOutput;
168 
169     using INHERITED = Benchmark;
170 };
171 
172 ///////////////////////////////////////////////////////////////////////////////
173 
174 #define COMPILER_BENCH(name, text)                                                                 \
175 static constexpr char name ## _SRC[] = text;                                                       \
176 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/false, Output::kNone);)    \
177 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kNone);)    \
178 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kGLSL);)    \
179 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kMetal);)   \
180 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kSPIRV);)   \
181 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kSkVM);)    \
182 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kSkVMOpt);) \
183 DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kSkVMJIT);)
184 
185 // This fragment shader is from the third tile on the top row of GM_gradients_2pt_conical_outside.
186 // To get an ES2 compatible shader, nonconstantArrayIndexSupport in GrShaderCaps is forced off.
187 COMPILER_BENCH(large, R"(
188 uniform float3x3 umatrix_S1_c0;
189 uniform half4 uthresholds1_7_S1_c1_c0_c0;
190 uniform half4 uthresholds9_13_S1_c1_c0_c0;
191 uniform float4 uscale_S1_c1_c0_c0[4];
192 uniform float4 ubias_S1_c1_c0_c0[4];
193 uniform half uinvR1_S1_c1_c0_c1_c0;
194 uniform half ufx_S1_c1_c0_c1_c0;
195 uniform float3x3 umatrix_S1_c1_c0_c1;
196 uniform half4 uleftBorderColor_S1_c1_c0;
197 uniform half4 urightBorderColor_S1_c1_c0;
198 uniform half urange_S1;
199 uniform sampler2D uTextureSampler_0_S1;
200 flat in half4 vcolor_S0;
201 noperspective in float2 vTransformedCoords_8_S0;
202 half4 TextureEffect_S1_c0_c0(half4 _input, float2 _coords)
203 {
204 	return sample(uTextureSampler_0_S1, _coords).000r;
205 }
206 half4 MatrixEffect_S1_c0(half4 _input, float2 _coords)
207 {
208 	return TextureEffect_S1_c0_c0(_input, float3x2(umatrix_S1_c0) * _coords.xy1);
209 }
210 half4 UnrolledBinaryColorizer_S1_c1_c0_c0(half4 _input, float2 _coords)
211 {
212 	half4 _tmp_0_inColor = _input;
213 	float2 _tmp_1_coords = _coords;
214 	half t = half(_tmp_1_coords.x);
215 	float4 s;
216 	float4 b;
217 	{
218 		if (t < uthresholds1_7_S1_c1_c0_c0.y)
219 		{
220 			if (t < uthresholds1_7_S1_c1_c0_c0.x)
221 			{
222 				s = uscale_S1_c1_c0_c0[0];
223 				b = ubias_S1_c1_c0_c0[0];
224 			}
225 			else
226 			{
227 				s = uscale_S1_c1_c0_c0[1];
228 				b = ubias_S1_c1_c0_c0[1];
229 			}
230 		}
231 		else
232 		{
233 			if (t < uthresholds1_7_S1_c1_c0_c0.z)
234 			{
235 				s = uscale_S1_c1_c0_c0[2];
236 				b = ubias_S1_c1_c0_c0[2];
237 			}
238 			else
239 			{
240 				s = uscale_S1_c1_c0_c0[3];
241 				b = ubias_S1_c1_c0_c0[3];
242 			}
243 		}
244 	}
245 	return half4(half4(float(t) * s + b));
246 }
247 half4 TwoPointConicalFocalLayout_S1_c1_c0_c1_c0(half4 _input)
248 {
249 	half4 _tmp_2_inColor = _input;
250 	float2 _tmp_3_coords = vTransformedCoords_8_S0;
251 	float t = -1.0;
252 	half v = 1.0;
253 	float x_t = -1.0;
254 	if (bool(int(0)))
255 	{
256 		x_t = dot(_tmp_3_coords, _tmp_3_coords) / _tmp_3_coords.x;
257 	}
258 	else if (bool(int(0)))
259 	{
260 		x_t = length(_tmp_3_coords) - _tmp_3_coords.x * float(uinvR1_S1_c1_c0_c1_c0);
261 	}
262 	else
263 	{
264 		float temp = _tmp_3_coords.x * _tmp_3_coords.x - _tmp_3_coords.y * _tmp_3_coords.y;
265 		if (temp >= 0.0)
266 		{
267 			if (bool(int(0)) || !bool(int(1)))
268 			{
269 				x_t = -sqrt(temp) - _tmp_3_coords.x * float(uinvR1_S1_c1_c0_c1_c0);
270 			}
271 			else
272 			{
273 				x_t = sqrt(temp) - _tmp_3_coords.x * float(uinvR1_S1_c1_c0_c1_c0);
274 			}
275 		}
276 	}
277 	if (!bool(int(0)))
278 	{
279 		if (x_t <= 0.0)
280 		{
281 			v = -1.0;
282 		}
283 	}
284 	if (bool(int(1)))
285 	{
286 		if (bool(int(0)))
287 		{
288 			t = x_t;
289 		}
290 		else
291 		{
292 			t = x_t + float(ufx_S1_c1_c0_c1_c0);
293 		}
294 	}
295 	else
296 	{
297 		if (bool(int(0)))
298 		{
299 			t = -x_t;
300 		}
301 		else
302 		{
303 			t = -x_t + float(ufx_S1_c1_c0_c1_c0);
304 		}
305 	}
306 	if (bool(int(0)))
307 	{
308 		t = 1.0 - t;
309 	}
310 	return half4(half4(half(t), v, 0.0, 0.0));
311 }
312 half4 MatrixEffect_S1_c1_c0_c1(half4 _input)
313 {
314 	return TwoPointConicalFocalLayout_S1_c1_c0_c1_c0(_input);
315 }
316 half4 ClampedGradient_S1_c1_c0(half4 _input)
317 {
318 	half4 _tmp_4_inColor = _input;
319 	half4 t = MatrixEffect_S1_c1_c0_c1(_tmp_4_inColor);
320 	half4 outColor;
321 	if (!bool(int(0)) && t.y < 0.0)
322 	{
323 		outColor = half4(0.0);
324 	}
325 	else if (t.x < 0.0)
326 	{
327 		outColor = uleftBorderColor_S1_c1_c0;
328 	}
329 	else if (t.x > 1.0)
330 	{
331 		outColor = urightBorderColor_S1_c1_c0;
332 	}
333 	else
334 	{
335 		outColor = UnrolledBinaryColorizer_S1_c1_c0_c0(_tmp_4_inColor, float2(half2(t.x, 0.0)));
336 	}
337 	if (bool(int(0)))
338 	{
339 		outColor.xyz *= outColor.w;
340 	}
341 	return half4(outColor);
342 }
343 half4 DisableCoverageAsAlpha_S1_c1(half4 _input)
344 {
345 	_input = ClampedGradient_S1_c1_c0(_input);
346 	half4 _tmp_5_inColor = _input;
347 	return half4(_input);
348 }
349 half4 Dither_S1(half4 _input)
350 {
351 	_input = DisableCoverageAsAlpha_S1_c1(_input);
352 	half4 _tmp_6_inColor = _input;
353 	half value = MatrixEffect_S1_c0(_tmp_6_inColor, sk_FragCoord.xy).w - 0.5;
354 	return half4(half4(clamp(_input.xyz + value * urange_S1, 0.0, _input.w), _input.w));
355 }
356 void main()
357 {
358 	// Stage 0, QuadPerEdgeAAGeometryProcessor
359 	half4 outputColor_S0;
360 	outputColor_S0 = vcolor_S0;
361 	const half4 outputCoverage_S0 = half4(1);
362 	half4 output_S1;
363 	output_S1 = Dither_S1(outputColor_S0);
364 	{
365 		// Xfer Processor: Porter Duff
366 		sk_FragColor = output_S1 * outputCoverage_S0;
367 	}
368 }
369 )");
370 
371 // This fragment shader is taken from GM_BlurDrawImage.
372 COMPILER_BENCH(medium, R"(
373 uniform float3x3 umatrix_S1_c0;
374 uniform float3x3 umatrix_S2_c0_c0;
375 uniform float4 urect_S2_c0;
376 uniform sampler2D uTextureSampler_0_S1;
377 uniform sampler2D uTextureSampler_0_S2;
378 flat in half4 vcolor_S0;
379 noperspective in float2 vTransformedCoords_3_S0;
380 half4 TextureEffect_S1_c0_c0(half4 _input)
381 {
382 	return sample(uTextureSampler_0_S1, vTransformedCoords_3_S0);
383 }
384 half4 MatrixEffect_S1_c0(half4 _input)
385 {
386 	return TextureEffect_S1_c0_c0(_input);
387 }
388 half4 DisableCoverageAsAlpha_S1(half4 _input)
389 {
390 	_input = MatrixEffect_S1_c0(_input);
391 	half4 _tmp_0_inColor = _input;
392 	return half4(_input);
393 }
394 half4 TextureEffect_S2_c0_c0_c0(half4 _input, float2 _coords)
395 {
396 	return sample(uTextureSampler_0_S2, _coords).000r;
397 }
398 half4 MatrixEffect_S2_c0_c0(half4 _input, float2 _coords)
399 {
400 	return TextureEffect_S2_c0_c0_c0(_input, float3x2(umatrix_S2_c0_c0) * _coords.xy1);
401 }
402 half4 RectBlur_S2_c0(half4 _input, float2 _coords)
403 {
404 	half4 _tmp_1_inColor = _input;
405 	float2 _tmp_2_coords = _coords;
406 	half xCoverage;
407 	half yCoverage;
408 	if (bool(int(1)))
409 	{
410 		half2 xy = max(half2(urect_S2_c0.xy - _tmp_2_coords), half2(_tmp_2_coords - urect_S2_c0.zw));
411 		xCoverage = MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(xy.x, 0.5))).w;
412 		yCoverage = MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(xy.y, 0.5))).w;
413 	}
414 	else
415 	{
416 		half4 rect = half4(half2(urect_S2_c0.xy - _tmp_2_coords), half2(_tmp_2_coords - urect_S2_c0.zw));
417 		xCoverage = (1.0 - MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(rect.x, 0.5))).w) - MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(rect.z, 0.5))).w;
418 		yCoverage = (1.0 - MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(rect.y, 0.5))).w) - MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(rect.w, 0.5))).w;
419 	}
420 	return half4((_input * xCoverage) * yCoverage);
421 }
422 half4 DeviceSpace_S2(half4 _input)
423 {
424 	return RectBlur_S2_c0(_input, sk_FragCoord.xy);
425 }
426 void main()
427 {
428 	// Stage 0, QuadPerEdgeAAGeometryProcessor
429 	half4 outputColor_S0;
430 	outputColor_S0 = vcolor_S0;
431 	const half4 outputCoverage_S0 = half4(1);
432 	half4 output_S1;
433 	output_S1 = DisableCoverageAsAlpha_S1(outputColor_S0);
434 	half4 output_S2;
435 	output_S2 = DeviceSpace_S2(outputCoverage_S0);
436 	{
437 		// Xfer Processor: Porter Duff
438 		sk_FragColor = output_S1 * output_S2;
439 	}
440 }
441 )");
442 
443 // This fragment shader is taken from GM_lcdtext.
444 COMPILER_BENCH(small, R"(
445 uniform sampler2D uTextureSampler_0_S0;
446 noperspective in float2 vTextureCoords_S0;
447 flat in float vTexIndex_S0;
448 noperspective in half4 vinColor_S0;
449 void main()
450 {
451 	// Stage 0, BitmapText
452 	half4 outputColor_S0;
453 	outputColor_S0 = vinColor_S0;
454 	half4 texColor;
455 	{
456 		texColor = sample(uTextureSampler_0_S0, vTextureCoords_S0).rrrr;
457 	}
458 	half4 outputCoverage_S0 = texColor;
459 	{
460 		// Xfer Processor: Porter Duff
461 		sk_FragColor = outputColor_S0 * outputCoverage_S0;
462 	}
463 }
464 )");
465 
466 COMPILER_BENCH(tiny, "void main() { sk_FragColor = half4(1); }");
467 
468 #if defined(SK_BUILD_FOR_UNIX)
469 
470 #include <malloc.h>
heap_bytes_used()471 static int64_t heap_bytes_used() {
472     return (int64_t)mallinfo().uordblks;
473 }
474 
475 #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
476 
477 #include <malloc/malloc.h>
heap_bytes_used()478 static int64_t heap_bytes_used() {
479     malloc_statistics_t stats;
480     malloc_zone_pressure_relief(malloc_default_zone(), 0);
481     malloc_zone_statistics(malloc_default_zone(), &stats);
482     return (int64_t)stats.size_in_use;
483 }
484 
485 #else
486 
heap_bytes_used()487 static int64_t heap_bytes_used() {
488     return -1;
489 }
490 
491 #endif
492 
bench(NanoJSONResultsWriter * log,const char * name,int bytes)493 static void bench(NanoJSONResultsWriter* log, const char* name, int bytes) {
494     SkDEBUGCODE(SkDebugf("%s: %d bytes\n", name, bytes);)
495     log->beginObject(name);          // test
496     log->beginObject("meta");        //   config
497     log->appendS32("bytes", bytes);  //     sub_result
498     log->endObject();                //   config
499     log->endObject();                // test
500 }
501 
502 // These benchmarks aren't timed, they produce memory usage statistics. They run standalone, and
503 // directly add their results to the nanobench log.
RunSkSLModuleBenchmarks(NanoJSONResultsWriter * log)504 void RunSkSLModuleBenchmarks(NanoJSONResultsWriter* log) {
505     // Heap used by a default compiler (with no modules loaded)
506     int64_t before = heap_bytes_used();
507     GrShaderCaps caps;
508     SkSL::Compiler compiler(&caps);
509     int baselineBytes = heap_bytes_used();
510     if (baselineBytes >= 0) {
511         baselineBytes = (baselineBytes - before);
512         bench(log, "sksl_compiler_baseline", baselineBytes);
513     }
514 
515     // Heap used by a compiler with the two main GPU modules (fragment + vertex) and runtime effects
516     // (shader + color filter + blender) loaded. Ganesh will load all of these in regular usage.
517     before = heap_bytes_used();
518     compiler.moduleForProgramKind(SkSL::ProgramKind::kVertex);
519     compiler.moduleForProgramKind(SkSL::ProgramKind::kFragment);
520     compiler.moduleForProgramKind(SkSL::ProgramKind::kRuntimeColorFilter);
521     compiler.moduleForProgramKind(SkSL::ProgramKind::kRuntimeShader);
522     compiler.moduleForProgramKind(SkSL::ProgramKind::kRuntimeBlender);
523     compiler.moduleForProgramKind(SkSL::ProgramKind::kPrivateRuntimeColorFilter);
524     compiler.moduleForProgramKind(SkSL::ProgramKind::kPrivateRuntimeShader);
525     compiler.moduleForProgramKind(SkSL::ProgramKind::kPrivateRuntimeBlender);
526     int64_t gpuBytes = heap_bytes_used();
527     if (gpuBytes >= 0) {
528         gpuBytes = (gpuBytes - before) + baselineBytes;
529         bench(log, "sksl_compiler_gpu", gpuBytes);
530     }
531 
532 #if defined(SK_GRAPHITE)
533     // Heap used by a compiler with the Graphite modules loaded.
534     before = heap_bytes_used();
535     compiler.moduleForProgramKind(SkSL::ProgramKind::kGraphiteVertex);
536     compiler.moduleForProgramKind(SkSL::ProgramKind::kGraphiteFragment);
537     int64_t graphiteBytes = heap_bytes_used();
538     if (graphiteBytes >= 0) {
539         graphiteBytes = (graphiteBytes - before) + gpuBytes;
540         bench(log, "sksl_compiler_graphite", graphiteBytes);
541     }
542 #endif
543 
544     // Heap used by a compiler with compute-shader support loaded.
545     before = heap_bytes_used();
546     compiler.moduleForProgramKind(SkSL::ProgramKind::kCompute);
547     int64_t computeBytes = heap_bytes_used();
548     if (computeBytes >= 0) {
549         computeBytes = (computeBytes - before) + baselineBytes;
550         bench(log, "sksl_compiler_compute", computeBytes);
551     }
552 
553     // Report the minified module sizes.
554     int compilerGPUBinarySize = std::size(SKSL_MINIFIED_sksl_shared) +
555                                 std::size(SKSL_MINIFIED_sksl_gpu) +
556                                 std::size(SKSL_MINIFIED_sksl_vert) +
557                                 std::size(SKSL_MINIFIED_sksl_frag) +
558                                 std::size(SKSL_MINIFIED_sksl_public) +
559                                 std::size(SKSL_MINIFIED_sksl_rt_shader);
560     bench(log, "sksl_binary_size_gpu", compilerGPUBinarySize);
561 
562 #if defined(SK_GRAPHITE)
563     int compilerGraphiteBinarySize = std::size(SKSL_MINIFIED_sksl_graphite_frag) +
564                                      std::size(SKSL_MINIFIED_sksl_graphite_vert);
565     bench(log, "sksl_binary_size_graphite", compilerGraphiteBinarySize);
566 #endif
567 
568     int compilerComputeBinarySize = std::size(SKSL_MINIFIED_sksl_compute);
569     bench(log, "sksl_binary_size_compute", compilerComputeBinarySize);
570 }
571 
572 class SkSLModuleLoaderBench : public Benchmark {
573 public:
SkSLModuleLoaderBench(const char * name,std::vector<SkSL::ProgramKind> moduleList)574     SkSLModuleLoaderBench(const char* name, std::vector<SkSL::ProgramKind> moduleList)
575             : fName(name), fModuleList(std::move(moduleList)) {}
576 
onGetName()577     const char* onGetName() override {
578         return fName;
579     }
580 
isSuitableFor(Backend backend)581     bool isSuitableFor(Backend backend) override {
582         return backend == kNonRendering_Backend;
583     }
584 
calculateLoops(int defaultLoops) const585     int calculateLoops(int defaultLoops) const override {
586         return 1;
587     }
588 
onPreDraw(SkCanvas *)589     void onPreDraw(SkCanvas*) override {
590         SkSL::ModuleLoader::Get().unloadModules();
591     }
592 
onDraw(int loops,SkCanvas *)593     void onDraw(int loops, SkCanvas*) override {
594         SkASSERT(loops == 1);
595         GrShaderCaps caps;
596         SkSL::Compiler compiler(&caps);
597         for (SkSL::ProgramKind kind : fModuleList) {
598             compiler.moduleForProgramKind(kind);
599         }
600     }
601 
602     const char* fName;
603     std::vector<SkSL::ProgramKind> fModuleList;
604 };
605 
606 DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_ganesh",
607                                            {
608                                                    SkSL::ProgramKind::kVertex,
609                                                    SkSL::ProgramKind::kFragment,
610                                                    SkSL::ProgramKind::kRuntimeColorFilter,
611                                                    SkSL::ProgramKind::kRuntimeShader,
612                                                    SkSL::ProgramKind::kRuntimeBlender,
613                                                    SkSL::ProgramKind::kPrivateRuntimeColorFilter,
614                                                    SkSL::ProgramKind::kPrivateRuntimeShader,
615                                                    SkSL::ProgramKind::kPrivateRuntimeBlender,
616                                                    SkSL::ProgramKind::kCompute,
617                                            });)
618 
619 DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_graphite",
620                                            {
621                                                    SkSL::ProgramKind::kVertex,
622                                                    SkSL::ProgramKind::kFragment,
623                                                    SkSL::ProgramKind::kRuntimeColorFilter,
624                                                    SkSL::ProgramKind::kRuntimeShader,
625                                                    SkSL::ProgramKind::kRuntimeBlender,
626                                                    SkSL::ProgramKind::kPrivateRuntimeColorFilter,
627                                                    SkSL::ProgramKind::kPrivateRuntimeShader,
628                                                    SkSL::ProgramKind::kPrivateRuntimeBlender,
629                                                    SkSL::ProgramKind::kCompute,
630                                                    SkSL::ProgramKind::kGraphiteVertex,
631                                                    SkSL::ProgramKind::kGraphiteFragment,
632                                            });)
633