Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 1 | <!-- This benchmark aims to accurately measure the time it takes for Skottie to load the JSON and |
| 2 | turn it into an animation, as well as the times for the first hundred frames (and, as a subcomponent |
| 3 | of that, the seek times of the first hundred frames). This is set to mimic how a real-world user |
| 4 | would 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 Nifong | 1436d72 | 2020-07-07 17:13:31 -0400 | [diff] [blame] | 14 | <script src="/static/benchmark.js" type="text/javascript" charset="utf-8"></script> |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 15 | <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 Lubick | bd71936 | 2021-06-25 11:04:11 -0400 | [diff] [blame] | 31 | const WARM_UP_FRAMES = 0; // No warmup, so that the jank of initial frames gets measured. |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 32 | // We sample MAX_FRAMES or until MAX_SAMPLE_SECONDS has elapsed. |
| 33 | const MAX_FRAMES = 600; // ~10s at 60fps |
Kevin Lubick | 8fd0ccf | 2021-06-28 09:59:39 -0400 | [diff] [blame] | 34 | const MAX_SAMPLE_MS = 50 * 1000; // in case something takes a while, stop after 50 seconds. |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 35 | 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 Lubick | 4ad6b50 | 2020-05-21 10:51:35 -0400 | [diff] [blame] | 41 | }); |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 42 | |
| 43 | const loadLottie = fetch(LOTTIE_JSON_PATH).then((resp) => { |
Nathaniel Nifong | 1436d72 | 2020-07-07 17:13:31 -0400 | [diff] [blame] | 44 | return resp.text(); |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 45 | }); |
| 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 Nifong | 1436d72 | 2020-07-07 17:13:31 -0400 | [diff] [blame] | 68 | window._perfData = { |
| 69 | json_load_ms: loadTime, |
| 70 | }; |
| 71 | |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 72 | const duration = animation.duration() * 1000; |
Kevin Lubick | f8823b5 | 2020-09-03 10:02:10 -0400 | [diff] [blame] | 73 | const bounds = CanvasKit.LTRBRect(0, 0, WIDTH, HEIGHT); |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 74 | |
Nathaniel Nifong | a237f9e | 2020-07-17 15:20:44 -0400 | [diff] [blame] | 75 | 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 Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 82 | if (!surface) { |
| 83 | console.error('Could not make surface', window._error); |
| 84 | return; |
| 85 | } |
| 86 | const canvas = surface.getCanvas(); |
| 87 | |
Nathaniel Nifong | 7839a25 | 2020-07-29 11:01:55 -0400 | [diff] [blame] | 88 | document.getElementById('start_bench').addEventListener('click', async () => { |
Nathaniel Nifong | 1436d72 | 2020-07-07 17:13:31 -0400 | [diff] [blame] | 89 | const startTime = Date.now(); |
Kevin Lubick | f8823b5 | 2020-09-03 10:02:10 -0400 | [diff] [blame] | 90 | const damageRect = Float32Array.of(0, 0, 0, 0); |
Nathaniel Nifong | 1436d72 | 2020-07-07 17:13:31 -0400 | [diff] [blame] | 91 | |
| 92 | function draw() { |
| 93 | const seek = ((Date.now() - startTime) / duration) % 1.0; |
Kevin Lubick | f8823b5 | 2020-09-03 10:02:10 -0400 | [diff] [blame] | 94 | const damage = animation.seek(seek, damageRect); |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 95 | |
Kevin Lubick | f8823b5 | 2020-09-03 10:02:10 -0400 | [diff] [blame] | 96 | if (damage[2] > damage[0] && damage[3] > damage[1]) { |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 97 | animation.render(canvas, bounds); |
| 98 | } |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 99 | } |
Nathaniel Nifong | 1436d72 | 2020-07-07 17:13:31 -0400 | [diff] [blame] | 100 | |
Kevin Lubick | 6df5cd2 | 2020-11-12 09:11:47 -0500 | [diff] [blame] | 101 | 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 Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 108 | }); |
| 109 | console.log('Perf is ready'); |
| 110 | window._perfReady = true; |
| 111 | }); |
| 112 | })(); |
| 113 | |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 114 | 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 Lubick | 8fd0ccf | 2021-06-28 09:59:39 -0400 | [diff] [blame] | 142 | if (!assets) { |
| 143 | return []; |
| 144 | } |
Kevin Lubick | 5443bb3 | 2020-05-01 14:16:27 -0400 | [diff] [blame] | 145 | 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> |