blob: 4da2f1c1a6aa676ca875be3d4fa3aee6d5594c2c [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;
Kevin Lubickbd719362021-06-25 11:04:11 -040031 const WARM_UP_FRAMES = 0; // No warmup, so that the jank of initial frames gets 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 Lubick8fd0ccf2021-06-28 09:59:39 -040034 const MAX_SAMPLE_MS = 50 * 1000; // in case something takes a while, stop after 50 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 () => {
Nathaniel Nifong1436d722020-07-07 17:13:31 -040089 const startTime = Date.now();
Kevin Lubickf8823b52020-09-03 10:02:10 -040090 const damageRect = Float32Array.of(0, 0, 0, 0);
Nathaniel Nifong1436d722020-07-07 17:13:31 -040091
92 function draw() {
93 const seek = ((Date.now() - startTime) / duration) % 1.0;
Kevin Lubickf8823b52020-09-03 10:02:10 -040094 const damage = animation.seek(seek, damageRect);
Kevin Lubick5443bb32020-05-01 14:16:27 -040095
Kevin Lubickf8823b52020-09-03 10:02:10 -040096 if (damage[2] > damage[0] && damage[3] > damage[1]) {
Kevin Lubick5443bb32020-05-01 14:16:27 -040097 animation.render(canvas, bounds);
98 }
Kevin Lubick5443bb32020-05-01 14:16:27 -040099 }
Nathaniel Nifong1436d722020-07-07 17:13:31 -0400100
Kevin Lubick6df5cd22020-11-12 09:11:47 -0500101 startTimingFrames(draw, surface, WARM_UP_FRAMES, MAX_FRAMES, MAX_SAMPLE_MS).then((results) => {
102 Object.assign(window._perfData, results);
103 window._perfDone = true;
104 }).catch((error) => {
105 window._error = error;
106 });
107
Kevin Lubick5443bb32020-05-01 14:16:27 -0400108 });
109 console.log('Perf is ready');
110 window._perfReady = true;
111 });
112 })();
113
Kevin Lubick5443bb32020-05-01 14:16:27 -0400114 function loadFonts(fonts) {
115 const promises = [];
116 if (!fonts || !fonts.list) {
117 return promises;
118 }
119 for (const font of fonts.list) {
120 if (font.fName) {
121 promises.push(fetch(`${ASSETS_PATH}/${font.fName}.ttf`).then((resp) => {
122 // fetch does not reject on 404
123 if (!resp.ok) {
124 console.error(`Could not load ${font.fName}.ttf: status ${resp.status}`);
125 return null;
126 }
127 return resp.arrayBuffer().then((buffer) => {
128 return {
129 'name': font.fName,
130 'bytes': buffer
131 };
132 });
133 })
134 );
135 }
136 }
137 return promises;
138 }
139
140 function loadAssets(assets) {
141 const promises = [];
Kevin Lubick8fd0ccf2021-06-28 09:59:39 -0400142 if (!assets) {
143 return [];
144 }
Kevin Lubick5443bb32020-05-01 14:16:27 -0400145 for (const asset of assets) {
146 // asset.p is the filename, if it's an image.
147 // Don't try to load inline/dataURI images.
148 const should_load = asset.p && asset.p.startsWith && !asset.p.startsWith('data:');
149 if (should_load) {
150 promises.push(fetch(`${ASSETS_PATH}/${asset.p}`)
151 .then((resp) => {
152 // fetch does not reject on 404
153 if (!resp.ok) {
154 console.error(`Could not load ${asset.p}: status ${resp.status}`);
155 return null;
156 }
157 return resp.arrayBuffer().then((buffer) => {
158 return {
159 'name': asset.p,
160 'bytes': buffer
161 };
162 });
163 })
164 );
165 }
166 }
167 return promises;
168 }
169 </script>
170</body>
171</html>