Flutter Engine
The Flutter Engine
SkSLBench.cpp
Go to the documentation of this file.
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"
9#include "bench/SkSLBench.h"
18#include "src/sksl/SkSLParser.h"
27
28#include <regex>
29
30#include "src/sksl/generated/sksl_shared.minified.sksl"
31#include "src/sksl/generated/sksl_compute.minified.sksl"
32#include "src/sksl/generated/sksl_frag.minified.sksl"
33#include "src/sksl/generated/sksl_gpu.minified.sksl"
34#include "src/sksl/generated/sksl_public.minified.sksl"
35#include "src/sksl/generated/sksl_rt_shader.minified.sksl"
36#include "src/sksl/generated/sksl_vert.minified.sksl"
37#include "src/sksl/generated/sksl_graphite_frag.minified.sksl"
38#include "src/sksl/generated/sksl_graphite_vert.minified.sksl"
39#include "src/sksl/generated/sksl_graphite_frag_es2.minified.sksl"
40#include "src/sksl/generated/sksl_graphite_vert_es2.minified.sksl"
41
43protected:
44 const char* onGetName() override {
45 return "sksl_compiler_startup";
46 }
47
48 bool isSuitableFor(Backend backend) override {
50 }
51
52 void onDraw(int loops, SkCanvas*) override {
53 for (int i = 0; i < loops; i++) {
55 }
56 }
57};
58
60
61enum class Output {
62 kNone,
63 kGLSL,
64 kMetal,
65 kSPIRV,
66 kSkRP,
67 kGrMtl,
68 kGrWGSL,
69};
70
72public:
73 static const char* output_string(Output output) {
74 switch (output) {
75 case Output::kNone: return "";
76 case Output::kGLSL: return "glsl_";
77 case Output::kMetal: return "metal_";
78 case Output::kSPIRV: return "spirv_";
79 case Output::kGrMtl: return "grmtl_";
80 case Output::kGrWGSL: return "grwgsl_";
81 case Output::kSkRP: return "skrp_";
82 }
84 }
85
86 SkSLCompileBench(std::string name, const char* src, bool optimize, Output output)
87 : fName(std::string("sksl_") + (optimize ? "" : "unoptimized_") +
89 , fSrc(src)
91 , fOutput(output) {
92 fSettings.fOptimize = optimize;
93 // The test programs we compile don't follow Vulkan rules and thus produce invalid SPIR-V.
94 // This is harmless, so long as we don't try to validate them.
95 fSettings.fValidateSPIRV = false;
96
97 this->fixUpSource();
98 }
99
100protected:
101 const char* onGetName() override {
102 return fName.c_str();
103 }
104
106#if !defined(SK_GRAPHITE)
107 if (this->usesGraphite()) {
108 return false;
109 }
110#endif
111 return backend == Backend::kNonRendering;
112 }
113
114 bool usesRuntimeShader() const {
115 return fOutput == Output::kSkRP;
116 }
117
118 bool usesGraphite() const {
119 return fOutput == Output::kGrMtl || fOutput == Output::kGrWGSL;
120 }
121
122 void fixUpSource() {
123 auto fixup = [this](const char* input, const char* replacement) {
124 fSrc = std::regex_replace(fSrc, std::regex(input), replacement);
125 };
126
127 // Runtime shaders have slightly different conventions than fragment shaders.
128 // Perform a handful of fixups to compensate. These are hand-tuned for our current set of
129 // test shaders and will probably need to be updated if we add more.
130 if (this->usesRuntimeShader()) {
131 fixup(R"(void main\‍(\))", "half4 main(float2 xy)");
132 fixup(R"(sk_FragColor =)", "return");
133 fixup(R"(sk_FragCoord)", "_FragCoord");
134 fixup(R"(sampler2D )", "uniform shader ");
135 fixup(R"((flat |noperspective |)in )", "uniform ");
136 fixup(R"(sample\‍(([A-Za-z0-9_]+), ([A-Za-z0-9_]+)\))", "$01.eval($02)");
137 fSrc = "#version 300\nuniform float4 _FragCoord;\n" + fSrc;
138 }
139 }
140
141 void onDraw(int loops, SkCanvas* canvas) override {
143 if (this->usesRuntimeShader()) {
145 } else if (this->usesGraphite()) {
147 } else {
149 }
150 for (int i = 0; i < loops; i++) {
151 std::unique_ptr<SkSL::Program> program = fCompiler.convertProgram(kind, fSrc,
152 fSettings);
153 if (fCompiler.errorCount()) {
154 SK_ABORT("shader compilation failed: %s\n", fCompiler.errorText().c_str());
155 }
156 std::string result;
157 switch (fOutput) {
158 case Output::kNone:
159 break;
160
161 case Output::kGLSL:
162 SkAssertResult(SkSL::ToGLSL(*program, fCaps.shaderCaps(), &result));
163 break;
164
165 case Output::kMetal:
166 case Output::kGrMtl:
167 SkAssertResult(SkSL::ToMetal(*program, fCaps.shaderCaps(), &result));
168 break;
169
170 case Output::kSPIRV:
171 SkAssertResult(SkSL::ToSPIRV(*program, fCaps.shaderCaps(), &result));
172 break;
173
174 case Output::kGrWGSL:
175 SkAssertResult(SkSL::ToWGSL(*program, fCaps.shaderCaps(), &result));
176 break;
177
178 case Output::kSkRP:
179 SkAssertResult(CompileToSkRP(*program));
180 break;
181 }
182 }
183 }
184
185 static bool CompileToSkRP(const SkSL::Program& program) {
186 const SkSL::FunctionDeclaration* main = program.getFunction("main");
187 if (!main) {
188 return false;
189 }
190
191 // Compile our program.
192 std::unique_ptr<SkSL::RP::Program> rasterProg = SkSL::MakeRasterPipelineProgram(
193 program, *main->definition(), /*debugTrace=*/nullptr, /*writeTraceOps=*/false);
194 if (!rasterProg) {
195 return false;
196 }
197
198 // We need to supply a valid uniform range, but the uniform values inside don't actually
199 // matter, since we aren't going to run the shader.
200 float uniformBuffer[1024];
201 if (rasterProg->numUniforms() > (int)std::size(uniformBuffer)) {
202 return false;
203 }
204
205 // Append the program to a raster pipeline.
207 SkRasterPipeline pipeline(&alloc);
208 rasterProg->appendStages(&pipeline,
209 &alloc,
210 /*callbacks=*/nullptr,
211 /*uniforms=*/SkSpan{uniformBuffer, rasterProg->numUniforms()});
212 return true;
213 }
214
215private:
216 std::string fName;
217 std::string fSrc;
218 GrMockCaps fCaps;
219 SkSL::Compiler fCompiler;
220 SkSL::ProgramSettings fSettings;
221 Output fOutput;
222
223 using INHERITED = Benchmark;
224};
225
226///////////////////////////////////////////////////////////////////////////////
227
228#define COMPILER_BENCH(name, text) \
229 static constexpr char name ## _SRC[] = text; \
230 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/false, Output::kNone);) \
231 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kNone);) \
232 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kGLSL);) \
233 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kMetal);) \
234 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kSPIRV);) \
235 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kSkRP);)
236
237// This fragment shader is from the third tile on the top row of GM_gradients_2pt_conical_outside.
238// To get an ES2 compatible shader, nonconstantArrayIndexSupport in GrShaderCaps is forced off.
240uniform half4 uthresholds1_7_S1_c0_c0_c0;
241uniform half4 uthresholds9_13_S1_c0_c0_c0;
242uniform float4 uscale_S1_c0_c0_c0[4];
243uniform float4 ubias_S1_c0_c0_c0[4];
244uniform half uinvR1_S1_c0_c0_c1_c0;
245uniform half ufx_S1_c0_c0_c1_c0;
246uniform float3x3 umatrix_S1_c0_c0_c1;
247uniform half4 uleftBorderColor_S1_c0_c0;
248uniform half4 urightBorderColor_S1_c0_c0;
249uniform float3x3 umatrix_S1_c1;
250uniform half urange_S1;
251sampler2D uTextureSampler_0_S1;
252flat in half4 vcolor_S0;
253noperspective in float2 vTransformedCoords_6_S0;
254half4 UnrolledBinaryColorizer_S1_c0_c0_c0(half4 _input, float2 _coords)
256 half4 _tmp_0_inColor = _input;
257 float2 _tmp_1_coords = _coords;
258 half t = half(_tmp_1_coords.x);
259 float4 s;
260 float4 b;
261 {
262 if (t < uthresholds1_7_S1_c0_c0_c0.y)
263 {
264 if (t < uthresholds1_7_S1_c0_c0_c0.x)
265 {
266 s = uscale_S1_c0_c0_c0[0];
267 b = ubias_S1_c0_c0_c0[0];
268 }
269 else
270 {
271 s = uscale_S1_c0_c0_c0[1];
272 b = ubias_S1_c0_c0_c0[1];
273 }
274 }
275 else
276 {
277 if (t < uthresholds1_7_S1_c0_c0_c0.z)
278 {
279 s = uscale_S1_c0_c0_c0[2];
280 b = ubias_S1_c0_c0_c0[2];
281 }
282 else
283 {
284 s = uscale_S1_c0_c0_c0[3];
285 b = ubias_S1_c0_c0_c0[3];
286 }
287 }
288 }
289 return half4(half4(float(t) * s + b));
290}
291half4 TwoPointConicalFocalLayout_S1_c0_c0_c1_c0(half4 _input)
292{
293 half4 _tmp_2_inColor = _input;
294 float2 _tmp_3_coords = vTransformedCoords_6_S0;
295 float t = -1.0;
296 half v = 1.0;
297 float x_t = -1.0;
298 if (bool(int(0)))
299 {
300 x_t = dot(_tmp_3_coords, _tmp_3_coords) / _tmp_3_coords.x;
301 }
302 else if (bool(int(0)))
303 {
304 x_t = length(_tmp_3_coords) - _tmp_3_coords.x * float(uinvR1_S1_c0_c0_c1_c0);
305 }
306 else
307 {
308 float temp = _tmp_3_coords.x * _tmp_3_coords.x - _tmp_3_coords.y * _tmp_3_coords.y;
309 if (temp >= 0.0)
310 {
311 if (bool(int(0)) || !bool(int(1)))
312 {
313 x_t = -sqrt(temp) - _tmp_3_coords.x * float(uinvR1_S1_c0_c0_c1_c0);
314 }
315 else
316 {
317 x_t = sqrt(temp) - _tmp_3_coords.x * float(uinvR1_S1_c0_c0_c1_c0);
318 }
319 }
320 }
321 if (!bool(int(0)))
322 {
323 if (x_t <= 0.0)
324 {
325 v = -1.0;
326 }
327 }
328 if (bool(int(1)))
329 {
330 if (bool(int(0)))
331 {
332 t = x_t;
333 }
334 else
335 {
336 t = x_t + float(ufx_S1_c0_c0_c1_c0);
337 }
338 }
339 else
340 {
341 if (bool(int(0)))
342 {
343 t = -x_t;
344 }
345 else
346 {
347 t = -x_t + float(ufx_S1_c0_c0_c1_c0);
348 }
349 }
350 if (bool(int(0)))
351 {
352 t = 1.0 - t;
353 }
354 return half4(half4(half(t), v, 0.0, 0.0));
355}
356half4 MatrixEffect_S1_c0_c0_c1(half4 _input)
357{
358 return TwoPointConicalFocalLayout_S1_c0_c0_c1_c0(_input);
359}
360half4 ClampedGradient_S1_c0_c0(half4 _input)
361{
362 half4 _tmp_4_inColor = _input;
363 half4 t = MatrixEffect_S1_c0_c0_c1(_tmp_4_inColor);
364 half4 outColor;
365 if (!bool(int(0)) && t.y < 0.0)
366 {
367 outColor = half4(0.0);
368 }
369 else if (t.x < 0.0)
371 outColor = uleftBorderColor_S1_c0_c0;
372 }
373 else if (t.x > 1.0)
375 outColor = urightBorderColor_S1_c0_c0;
376 }
377 else
379 outColor = UnrolledBinaryColorizer_S1_c0_c0_c0(_tmp_4_inColor, float2(half2(t.x, 0.0)));
380 }
381 return half4(outColor);
383half4 DisableCoverageAsAlpha_S1_c0(half4 _input)
384{
385 _input = ClampedGradient_S1_c0_c0(_input);
386 half4 _tmp_5_inColor = _input;
387 return half4(_input);
388}
389half4 TextureEffect_S1_c1_c0(half4 _input, float2 _coords)
390{
391 return sample(uTextureSampler_0_S1, _coords).000r;
392}
393half4 MatrixEffect_S1_c1(half4 _input, float2 _coords)
395 return TextureEffect_S1_c1_c0(_input, float3x2(umatrix_S1_c1) * _coords.xy1);
396}
397half4 Dither_S1(half4 _input)
399 half4 _tmp_6_inColor = _input;
400 half4 color = DisableCoverageAsAlpha_S1_c0(_tmp_6_inColor);
401 half value = MatrixEffect_S1_c1(_tmp_6_inColor, sk_FragCoord.xy).w - 0.5;
402 return half4(half4(clamp(color.xyz + value * urange_S1, 0.0, color.w), color.w));
403}
404void main()
405{
406 // Stage 0, QuadPerEdgeAAGeometryProcessor
407 half4 outputColor_S0;
408 outputColor_S0 = vcolor_S0;
409 const half4 outputCoverage_S0 = half4(1);
410 half4 output_S1;
411 output_S1 = Dither_S1(outputColor_S0);
412 {
413 // Xfer Processor: Porter Duff
414 sk_FragColor = output_S1 * outputCoverage_S0;
415 }
416}
417)");
418
419// This fragment shader is taken from GM_BlurDrawImage.
420COMPILER_BENCH(medium, R"(
421uniform float3x3 umatrix_S1_c0;
422uniform float3x3 umatrix_S2_c0_c0;
423uniform float4 urect_S2_c0;
424sampler2D uTextureSampler_0_S1;
425sampler2D uTextureSampler_0_S2;
426flat in half4 vcolor_S0;
427noperspective in float2 vTransformedCoords_3_S0;
428half4 TextureEffect_S1_c0_c0(half4 _input)
429{
430 return sample(uTextureSampler_0_S1, vTransformedCoords_3_S0);
431}
432half4 MatrixEffect_S1_c0(half4 _input)
433{
434 return TextureEffect_S1_c0_c0(_input);
435}
436half4 DisableCoverageAsAlpha_S1(half4 _input)
437{
438 _input = MatrixEffect_S1_c0(_input);
439 half4 _tmp_0_inColor = _input;
440 return half4(_input);
441}
442half4 TextureEffect_S2_c0_c0_c0(half4 _input, float2 _coords)
443{
444 return sample(uTextureSampler_0_S2, _coords).000r;
445}
446half4 MatrixEffect_S2_c0_c0(half4 _input, float2 _coords)
447{
448 return TextureEffect_S2_c0_c0_c0(_input, float3x2(umatrix_S2_c0_c0) * _coords.xy1);
449}
450half4 RectBlur_S2_c0(half4 _input, float2 _coords)
451{
452 half4 _tmp_1_inColor = _input;
453 float2 _tmp_2_coords = _coords;
454 half xCoverage;
455 half yCoverage;
456 if (bool(int(1)))
457 {
458 half2 xy = max(half2(urect_S2_c0.xy - _tmp_2_coords), half2(_tmp_2_coords - urect_S2_c0.zw));
459 xCoverage = MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(xy.x, 0.5))).w;
460 yCoverage = MatrixEffect_S2_c0_c0(_tmp_1_inColor, float2(half2(xy.y, 0.5))).w;
461 }
462 else
463 {
464 half4 rect = half4(half2(urect_S2_c0.xy - _tmp_2_coords), half2(_tmp_2_coords - urect_S2_c0.zw));
465 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;
466 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;
467 }
468 return half4((_input * xCoverage) * yCoverage);
469}
470half4 DeviceSpace_S2(half4 _input)
471{
472 return RectBlur_S2_c0(_input, sk_FragCoord.xy);
473}
474void main()
475{
476 // Stage 0, QuadPerEdgeAAGeometryProcessor
477 half4 outputColor_S0;
478 outputColor_S0 = vcolor_S0;
479 const half4 outputCoverage_S0 = half4(1);
480 half4 output_S1;
481 output_S1 = DisableCoverageAsAlpha_S1(outputColor_S0);
482 half4 output_S2;
483 output_S2 = DeviceSpace_S2(outputCoverage_S0);
484 {
485 // Xfer Processor: Porter Duff
486 sk_FragColor = output_S1 * output_S2;
487 }
488}
489)");
490
491// This fragment shader is taken from GM_lcdtext.
492COMPILER_BENCH(small, R"(
493sampler2D uTextureSampler_0_S0;
494noperspective in float2 vTextureCoords_S0;
495flat in float vTexIndex_S0;
496noperspective in half4 vinColor_S0;
497void main()
498{
499 // Stage 0, BitmapText
500 half4 outputColor_S0;
501 outputColor_S0 = vinColor_S0;
502 half4 texColor;
503 {
504 texColor = sample(uTextureSampler_0_S0, vTextureCoords_S0).rrrr;
505 }
506 half4 outputCoverage_S0 = texColor;
507 {
508 // Xfer Processor: Porter Duff
509 sk_FragColor = outputColor_S0 * outputCoverage_S0;
510 }
511}
512)");
513
514COMPILER_BENCH(tiny, "void main() { sk_FragColor = half4(1); }");
515
516#define GRAPHITE_BENCH(name, text) \
517 static constexpr char name##_SRC[] = text; \
518 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kGrMtl);) \
519 DEF_BENCH(return new SkSLCompileBench(#name, name##_SRC, /*optimize=*/true, Output::kGrWGSL);)
520
521// This fragment shader is from the third tile on the top row of GM_gradients_2pt_conical_outside.
522GRAPHITE_BENCH(graphite_large, R"(
523layout(location=0) in flat int shadingSsboIndexVar;
524layout(location=1) in float2 localCoordsVar;
525layout(location=2) in float4 jacobian;
526layout(location=3) in float4 edgeDistances;
527layout(location=4) in float4 xRadii;
528layout(location=5) in float4 yRadii;
529layout(location=6) in float2 strokeParams;
530layout(location=7) in float2 perPixelControl;
531struct FSUniformData
532{
533 // 0 - SolidColor uniforms
534 float4 color_0;
535 // 2 - ConicalGradient8 uniforms
536 float4 colors_2[8];
537 float4 offsets_2[2];
538 float2 point0_2;
539 float2 point1_2;
540 float radius0_2;
541 float radius1_2;
542 int tilemode_2;
543 int colorSpace_2;
544 int doUnPremul_2;
545 // 3 - ColorSpaceTransform uniforms
546 int flags_3;
547 int srcKind_3;
548 half3x3 gamutTransform_3;
549 int dstKind_3;
550 half4x4 csXformCoeffs_3;
551 // 4 - DitherShader uniforms
552 half range_4;
553}
554;
555layout (binding=2) buffer FSUniforms
556{
557 FSUniformData fsUniformData[];
558}
559;
560// 4 - DitherShader samplers
561layout(binding=0) sampler2D sampler_4;
562// [1] 1: ColorFilterShader
563half4 ColorFilterShader_1(half4 inColor, half4 destColor, float2 coords)
564{
565 return sk_color_space_transform(sk_conical_grad_8_shader(coords, fsUniformData[shadingSsboIndexVar].colors_2, fsUniformData[shadingSsboIndexVar].offsets_2, fsUniformData[shadingSsboIndexVar].point0_2, fsUniformData[shadingSsboIndexVar].point1_2, fsUniformData[shadingSsboIndexVar].radius0_2, fsUniformData[shadingSsboIndexVar].radius1_2, fsUniformData[shadingSsboIndexVar].tilemode_2, fsUniformData[shadingSsboIndexVar].colorSpace_2, fsUniformData[shadingSsboIndexVar].doUnPremul_2), fsUniformData[shadingSsboIndexVar].flags_3, fsUniformData[shadingSsboIndexVar].srcKind_3, fsUniformData[shadingSsboIndexVar].gamutTransform_3, fsUniformData[shadingSsboIndexVar].dstKind_3, fsUniformData[shadingSsboIndexVar].csXformCoeffs_3);
566}
567void main()
568{
569 half4 initialColor = half4(0);
570 // [0] SolidColor
571 half4 outColor_0 = sk_solid_shader(fsUniformData[shadingSsboIndexVar].color_0);
572 // [1] ColorFilterShader
573 half4 outColor_1 = ColorFilterShader_1(outColor_0, half4(1), localCoordsVar);
574 // [4] DitherShader
575 half4 outColor_4 = sk_dither_shader(outColor_1, localCoordsVar, fsUniformData[shadingSsboIndexVar].range_4, sampler_4);
576 // [5] SrcOver
577 half4 outColor_5 = outColor_4;
578 half4 outputCoverage;
579 outputCoverage = analytic_rrect_coverage_fn(sk_FragCoord, jacobian, edgeDistances, xRadii, yRadii, strokeParams, perPixelControl);
580 sk_FragColor = outColor_5 * outputCoverage;
581}
582)");
583
584// This fragment shader is taken from GM_lcdtext.
585GRAPHITE_BENCH(graphite_small, R"(
586layout(location=0) in flat int shadingSsboIndexVar;
587layout(location=1) in float2 textureCoords;
588layout(location=2) in half texIndex;
589layout(location=3) in half maskFormat;
590layout (binding=1) uniform StepUniforms
591{
592 layout(offset=0) float4x4 subRunDeviceMatrix;
593 layout(offset=64) float4x4 deviceToLocal;
594 layout(offset=128) float2 atlasSizeInv;
595}
596;
597struct FSUniformData
598{
599 // 0 - SolidColor uniforms
600 float4 color_0;
601}
602;
603layout (binding=2) buffer FSUniforms
604{
605 FSUniformData fsUniformData[];
606}
607;
608layout(binding=0) sampler2D text_atlas_0;
609layout(binding=1) sampler2D text_atlas_1;
610layout(binding=2) sampler2D text_atlas_2;
611layout(binding=3) sampler2D text_atlas_3;
612void main()
613{
614 half4 initialColor = half4(0);
615 // [0] SolidColor
616 half4 outColor_0 = sk_solid_shader(fsUniformData[shadingSsboIndexVar].color_0);
617 // [1] SrcOver
618 half4 outColor_1 = outColor_0;
619 half4 outputCoverage;
620 outputCoverage = bitmap_text_coverage_fn(sample_indexed_atlas(textureCoords, int(texIndex), text_atlas_0, text_atlas_1, text_atlas_2, text_atlas_3), int(maskFormat));
621 sk_FragColor = outColor_1 * outputCoverage;
622}
623)");
624
625#if defined(SK_BUILD_FOR_UNIX)
626
627#include <malloc.h>
628static int64_t heap_bytes_used() {
629 return (int64_t)mallinfo().uordblks;
630}
631
632#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
633
634#include <malloc/malloc.h>
635static int64_t heap_bytes_used() {
636 malloc_statistics_t stats;
637 malloc_zone_pressure_relief(malloc_default_zone(), 0);
638 malloc_zone_statistics(malloc_default_zone(), &stats);
639 return (int64_t)stats.size_in_use;
640}
641
642#else
643
644static int64_t heap_bytes_used() {
645 return -1;
646}
647
648#endif
649
650static void bench(NanoJSONResultsWriter* log, const char* name, int bytes) {
651 SkDEBUGCODE(SkDebugf("%s: %d bytes\n", name, bytes);)
652 log->beginObject(name); // test
653 log->beginObject("meta"); // config
654 log->appendS32("bytes", bytes); // sub_result
655 log->endObject(); // config
656 log->endObject(); // test
657}
658
659// These benchmarks aren't timed, they produce memory usage statistics. They run standalone, and
660// directly add their results to the nanobench log.
662 // Heap used by a default compiler (with no modules loaded)
663 int64_t before = heap_bytes_used();
665 int baselineBytes = heap_bytes_used();
666 if (baselineBytes >= 0) {
667 baselineBytes = (baselineBytes - before);
668 bench(log, "sksl_compiler_baseline", baselineBytes);
669 }
670
671 // Heap used by a compiler with the two main GPU modules (fragment + vertex) and runtime effects
672 // (shader + color filter + blender) loaded. Ganesh will load all of these in regular usage.
673 before = heap_bytes_used();
674 compiler.moduleForProgramKind(SkSL::ProgramKind::kVertex);
675 compiler.moduleForProgramKind(SkSL::ProgramKind::kFragment);
677 compiler.moduleForProgramKind(SkSL::ProgramKind::kRuntimeShader);
678 compiler.moduleForProgramKind(SkSL::ProgramKind::kRuntimeBlender);
682 int64_t gpuBytes = heap_bytes_used();
683 if (gpuBytes >= 0) {
684 gpuBytes = (gpuBytes - before) + baselineBytes;
685 bench(log, "sksl_compiler_gpu", gpuBytes);
686 }
687
688#if defined(SK_GRAPHITE)
689 // Heap used by a compiler with the Graphite modules loaded.
690 before = heap_bytes_used();
691 compiler.moduleForProgramKind(SkSL::ProgramKind::kGraphiteVertex);
693 int64_t graphiteBytes = heap_bytes_used();
694 if (graphiteBytes >= 0) {
695 graphiteBytes = (graphiteBytes - before) + gpuBytes;
696 bench(log, "sksl_compiler_graphite", graphiteBytes);
697 }
698
699 // Heap used by a compiler with compute-shader support loaded.
700 before = heap_bytes_used();
701 compiler.moduleForProgramKind(SkSL::ProgramKind::kCompute);
702 int64_t computeBytes = heap_bytes_used();
703 if (computeBytes >= 0) {
704 computeBytes = (computeBytes - before) + baselineBytes;
705 bench(log, "sksl_compiler_compute", computeBytes);
706 }
707#endif
708
709 // Report the minified module sizes.
710 int compilerGPUBinarySize = std::size(SKSL_MINIFIED_sksl_shared) +
711 std::size(SKSL_MINIFIED_sksl_gpu) +
712 std::size(SKSL_MINIFIED_sksl_vert) +
713 std::size(SKSL_MINIFIED_sksl_frag) +
714 std::size(SKSL_MINIFIED_sksl_public) +
715 std::size(SKSL_MINIFIED_sksl_rt_shader);
716 bench(log, "sksl_binary_size_gpu", compilerGPUBinarySize);
717
718 int compilerGraphiteBinarySize = std::size(SKSL_MINIFIED_sksl_graphite_frag) +
719 std::size(SKSL_MINIFIED_sksl_graphite_vert);
720 bench(log, "sksl_binary_size_graphite", compilerGraphiteBinarySize);
721
722 int compilerGraphiteES2BinarySize = std::size(SKSL_MINIFIED_sksl_graphite_frag_es2) +
723 std::size(SKSL_MINIFIED_sksl_graphite_vert_es2);
724 bench(log, "sksl_binary_size_graphite_es2", compilerGraphiteES2BinarySize);
725
726 int compilerComputeBinarySize = std::size(SKSL_MINIFIED_sksl_compute);
727 bench(log, "sksl_binary_size_compute", compilerComputeBinarySize);
728}
729
730class SkSLModuleLoaderBench : public Benchmark {
731public:
732 SkSLModuleLoaderBench(const char* name, std::vector<SkSL::ProgramKind> moduleList)
733 : fName(name), fModuleList(std::move(moduleList)) {}
734
735 const char* onGetName() override {
736 return fName;
737 }
738
739 bool isSuitableFor(Backend backend) override {
741 }
742
743 bool shouldLoop() const override {
744 return false;
745 }
746
747 void onPreDraw(SkCanvas*) override {
749 }
750
751 void onDraw(int loops, SkCanvas*) override {
752 SkASSERT(loops == 1);
754 for (SkSL::ProgramKind kind : fModuleList) {
755 compiler.moduleForProgramKind(kind);
756 }
757 }
758
759 const char* fName;
760 std::vector<SkSL::ProgramKind> fModuleList;
761};
762
763DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_ganesh",
764 {
774 });)
775
776DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_graphite",
777 {
789 });)
const char * backend
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static SkTileMode optimize(SkTileMode tm, int dimension)
void RunSkSLModuleBenchmarks(NanoJSONResultsWriter *log)
Definition: SkSLBench.cpp:296
static int64_t heap_bytes_used()
Definition: SkSLBench.cpp:279
Output
Definition: SkSLBench.cpp:61
#define GRAPHITE_BENCH(name, text)
Definition: SkSLBench.cpp:249
DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_ganesh", { SkSL::ProgramKind::kVertex, SkSL::ProgramKind::kFragment, SkSL::ProgramKind::kRuntimeColorFilter, SkSL::ProgramKind::kRuntimeShader, SkSL::ProgramKind::kRuntimeBlender, SkSL::ProgramKind::kPrivateRuntimeColorFilter, SkSL::ProgramKind::kPrivateRuntimeShader, SkSL::ProgramKind::kPrivateRuntimeBlender, SkSL::ProgramKind::kCompute, });) DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_graphite"
static void bench(NanoJSONResultsWriter *log, const char *name, int bytes)
Definition: SkSLBench.cpp:285
#define COMPILER_BENCH(name, text)
Definition: SkSLBench.cpp:228
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
const GrShaderCaps * shaderCaps() const
Definition: GrCaps.h:63
static const char * output_string(Output output)
Definition: SkSLBench.cpp:73
SkSLCompileBench(std::string name, const char *src, bool optimize, Output output)
Definition: SkSLBench.cpp:86
bool usesGraphite() const
Definition: SkSLBench.cpp:118
void onDraw(int loops, SkCanvas *canvas) override
Definition: SkSLBench.cpp:141
static bool CompileToSkRP(const SkSL::Program &program)
Definition: SkSLBench.cpp:185
const char * onGetName() override
Definition: SkSLBench.cpp:101
bool isSuitableFor(Backend backend) override
Definition: SkSLBench.cpp:105
bool usesRuntimeShader() const
Definition: SkSLBench.cpp:114
const char * onGetName() override
Definition: SkSLBench.cpp:44
void onDraw(int loops, SkCanvas *) override
Definition: SkSLBench.cpp:52
bool isSuitableFor(Backend backend) override
Definition: SkSLBench.cpp:48
void onDraw(int loops, SkCanvas *) override
Definition: SkSLBench.cpp:386
const char * fName
Definition: SkSLBench.cpp:394
bool shouldLoop() const override
Definition: SkSLBench.cpp:378
SkSLModuleLoaderBench(const char *name, std::vector< SkSL::ProgramKind > moduleList)
Definition: SkSLBench.cpp:367
void onPreDraw(SkCanvas *) override
Definition: SkSLBench.cpp:382
const char * onGetName() override
Definition: SkSLBench.cpp:370
bool isSuitableFor(Backend backend) override
Definition: SkSLBench.cpp:374
std::vector< SkSL::ProgramKind > fModuleList
Definition: SkSLBench.cpp:395
std::string errorText(bool showCount=true)
int errorCount() const
Definition: SkSLCompiler.h:134
std::unique_ptr< Program > convertProgram(ProgramKind kind, std::string programSource, const ProgramSettings &settings)
static ModuleLoader Get()
@ kMetal
Definition: embedder.h:85
GAsyncResult * result
bool ToSPIRV(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToWGSL(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToGLSL(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToMetal(Program &program, const ShaderCaps *caps, OutputStream &out)
std::unique_ptr< RP::Program > MakeRasterPipelineProgram(const SkSL::Program &program, const FunctionDefinition &function, DebugTracePriv *debugTrace, bool writeTraceOps)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: main.py:1
dictionary stats
Definition: malisc.py:20
compiler
Definition: malisc.py:17
Definition: ref_ptr.h:256
const FunctionDeclaration * getFunction(const char *functionName) const
Definition: SkSLProgram.cpp:56