blob: 52973d9ce008db11ef34d2b5a655131a7428106c [file] [log] [blame]
Kevin Lubick5443bb32020-05-01 14:16:27 -04001<!-- This benchmark aims to accurately measure the time it takes for Skottie to load the JSON and
2turn it into an animation, as well as the times for the first hundred frames (and, as a subcomponent
3of that, the seek times of the first hundred frames). This is set to mimic how a real-world user
4would display the animation (e.g. using clock time to determine where to seek, not frame numbers).
5-->
6<!DOCTYPE html>
7<html>
8<head>
9 <title>Skottie-WASM Perf</title>
10 <meta charset="utf-8" />
11 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
12 <meta name="viewport" content="width=device-width, initial-scale=1.0">
13 <script src="/static/canvaskit.js" type="text/javascript" charset="utf-8"></script>
Nathaniel Nifong1436d722020-07-07 17:13:31 -040014 <script src="/static/benchmark.js" type="text/javascript" charset="utf-8"></script>
Kevin Lubick5443bb32020-05-01 14:16:27 -040015 <style type="text/css" media="screen">
16 body {
17 margin: 0;
18 padding: 0;
19 }
20 </style>
21</head>
22<body>
23 <main>
24 <button id="start_bench">Start Benchmark</button>
25 <br>
26 <canvas id=anim width=1000 height=1000 style="height: 1000px; width: 1000px;"></canvas>
27 </main>
28 <script type="text/javascript" charset="utf-8">
29 const WIDTH = 1000;
30 const HEIGHT = 1000;
Nathaniel Nifong1436d722020-07-07 17:13:31 -040031 const WARM_UP_FRAMES = 0; // No warmup, so that the jank of initial frames gets's measured.
Kevin Lubick5443bb32020-05-01 14:16:27 -040032 // We sample MAX_FRAMES or until MAX_SAMPLE_SECONDS has elapsed.
33 const MAX_FRAMES = 600; // ~10s at 60fps
Kevin Lubick6df5cd22020-11-12 09:11:47 -050034 const MAX_SAMPLE_MS = 45 * 1000; // in case something takes a while, stop after 30 seconds.
Kevin Lubick5443bb32020-05-01 14:16:27 -040035 const LOTTIE_JSON_PATH = '/static/lottie.json';
36 const ASSETS_PATH = '/static/assets/';
37 (function() {
38
39 const loadKit = CanvasKitInit({
40 locateFile: (file) => '/static/' + file,
Kevin Lubick4ad6b502020-05-21 10:51:35 -040041 });
Kevin Lubick5443bb32020-05-01 14:16:27 -040042
43 const loadLottie = fetch(LOTTIE_JSON_PATH).then((resp) => {
Nathaniel Nifong1436d722020-07-07 17:13:31 -040044 return resp.text();
Kevin Lubick5443bb32020-05-01 14:16:27 -040045 });
46
47 const loadFontsAndAssets = loadLottie.then((jsonStr) => {
48 const lottie = JSON.parse(jsonStr);
49 const promises = [];
50 promises.push(...loadFonts(lottie.fonts));
51 promises.push(...loadAssets(lottie.assets));
52 return Promise.all(promises);
53 });
54
55 Promise.all([loadKit, loadLottie, loadFontsAndAssets]).then((values) => {
56 const [CanvasKit, json, externalAssets] = values;
57 console.log(externalAssets);
58 const assets = {};
59 for (const asset of externalAssets) {
60 if (asset) {
61 assets[asset.name] = asset.bytes;
62 }
63 }
64 const loadStart = performance.now();
65 const animation = CanvasKit.MakeManagedAnimation(json, assets);
66 const loadTime = performance.now() - loadStart;
67
Nathaniel Nifong1436d722020-07-07 17:13:31 -040068 window._perfData = {
69 json_load_ms: loadTime,
70 };
71
Kevin Lubick5443bb32020-05-01 14:16:27 -040072 const duration = animation.duration() * 1000;
Kevin Lubickf8823b52020-09-03 10:02:10 -040073 const bounds = CanvasKit.LTRBRect(0, 0, WIDTH, HEIGHT);
Kevin Lubick5443bb32020-05-01 14:16:27 -040074
Nathaniel Nifonga237f9e2020-07-17 15:20:44 -040075 const urlSearchParams = new URLSearchParams(window.location.search);
76 let glversion = 2;
77 if (urlSearchParams.has('webgl1')) {
78 glversion = 1;
79 }
80
81 const surface = getSurface(CanvasKit, glversion);
Kevin Lubick5443bb32020-05-01 14:16:27 -040082 if (!surface) {
83 console.error('Could not make surface', window._error);
84 return;
85 }
86 const canvas = surface.getCanvas();
87
Nathaniel Nifong7839a252020-07-29 11:01:55 -040088 document.getElementById('start_bench').addEventListener('click', async () => {
Kevin Lubick5443bb32020-05-01 14:16:27 -040089 const clearColor = CanvasKit.WHITE;
Nathaniel Nifong1436d722020-07-07 17:13:31 -040090 const startTime = Date.now();
Kevin Lubickf8823b52020-09-03 10:02:10 -040091 const damageRect = Float32Array.of(0, 0, 0, 0);
Nathaniel Nifong1436d722020-07-07 17:13:31 -040092
93 function draw() {
94 const seek = ((Date.now() - startTime) / duration) % 1.0;
Kevin Lubickf8823b52020-09-03 10:02:10 -040095 const damage = animation.seek(seek, damageRect);
Kevin Lubick5443bb32020-05-01 14:16:27 -040096
Kevin Lubickf8823b52020-09-03 10:02:10 -040097 if (damage[2] > damage[0] && damage[3] > damage[1]) {
Kevin Lubick5443bb32020-05-01 14:16:27 -040098 canvas.clear(clearColor);
99 animation.render(canvas, bounds);
100 }
Kevin Lubick5443bb32020-05-01 14:16:27 -0400101 }
Nathaniel Nifong1436d722020-07-07 17:13:31 -0400102
Kevin Lubick6df5cd22020-11-12 09:11:47 -0500103 startTimingFrames(draw, surface, WARM_UP_FRAMES, MAX_FRAMES, MAX_SAMPLE_MS).then((results) => {
104 Object.assign(window._perfData, results);
105 window._perfDone = true;
106 }).catch((error) => {
107 window._error = error;
108 });
109
Kevin Lubick5443bb32020-05-01 14:16:27 -0400110 });
111 console.log('Perf is ready');
112 window._perfReady = true;
113 });
114 })();
115
Kevin Lubick5443bb32020-05-01 14:16:27 -0400116 function loadFonts(fonts) {
117 const promises = [];
118 if (!fonts || !fonts.list) {
119 return promises;
120 }
121 for (const font of fonts.list) {
122 if (font.fName) {
123 promises.push(fetch(`${ASSETS_PATH}/${font.fName}.ttf`).then((resp) => {
124 // fetch does not reject on 404
125 if (!resp.ok) {
126 console.error(`Could not load ${font.fName}.ttf: status ${resp.status}`);
127 return null;
128 }
129 return resp.arrayBuffer().then((buffer) => {
130 return {
131 'name': font.fName,
132 'bytes': buffer
133 };
134 });
135 })
136 );
137 }
138 }
139 return promises;
140 }
141
142 function loadAssets(assets) {
143 const promises = [];
144 for (const asset of assets) {
145 // asset.p is the filename, if it's an image.
146 // Don't try to load inline/dataURI images.
147 const should_load = asset.p && asset.p.startsWith && !asset.p.startsWith('data:');
148 if (should_load) {
149 promises.push(fetch(`${ASSETS_PATH}/${asset.p}`)
150 .then((resp) => {
151 // fetch does not reject on 404
152 if (!resp.ok) {
153 console.error(`Could not load ${asset.p}: status ${resp.status}`);
154 return null;
155 }
156 return resp.arrayBuffer().then((buffer) => {
157 return {
158 'name': asset.p,
159 'bytes': buffer
160 };
161 });
162 })
163 );
164 }
165 }
166 return promises;
167 }
168 </script>
169</body>
170</html>