172 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			HTML
		
	
	
	
| <!-- This benchmark aims to accurately measure the time it takes for Skottie to load the JSON and
 | |
| turn it into an animation, as well as the times for the first hundred frames (and, as a subcomponent
 | |
| of that, the seek times of the first hundred frames). This is set to mimic how a real-world user
 | |
| would display the animation (e.g. using clock time to determine where to seek, not frame numbers).
 | |
| -->
 | |
| <!DOCTYPE html>
 | |
| <html>
 | |
| <head>
 | |
|   <title>Skottie-WASM Perf</title>
 | |
|   <meta charset="utf-8" />
 | |
|   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 | |
|   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | |
|   <script src="/static/canvaskit.js" type="text/javascript" charset="utf-8"></script>
 | |
|   <script src="/static/benchmark.js" type="text/javascript" charset="utf-8"></script>
 | |
|   <style type="text/css" media="screen">
 | |
|     body {
 | |
|       margin: 0;
 | |
|       padding: 0;
 | |
|     }
 | |
|   </style>
 | |
| </head>
 | |
| <body>
 | |
|   <main>
 | |
|     <button id="start_bench">Start Benchmark</button>
 | |
|     <br>
 | |
|     <canvas id=anim width=1000 height=1000 style="height: 1000px; width: 1000px;"></canvas>
 | |
|   </main>
 | |
|   <script type="text/javascript" charset="utf-8">
 | |
|     const WIDTH  = 1000;
 | |
|     const HEIGHT = 1000;
 | |
|     const WARM_UP_FRAMES = 0; // No warmup, so that the jank of initial frames gets measured.
 | |
|     // We sample MAX_FRAMES or until MAX_SAMPLE_SECONDS has elapsed.
 | |
|     const MAX_FRAMES = 600; // ~10s at 60fps
 | |
|     const MAX_SAMPLE_MS = 50 * 1000; // in case something takes a while, stop after 50 seconds.
 | |
|     const LOTTIE_JSON_PATH = '/static/lottie.json';
 | |
|     const ASSETS_PATH = '/static/assets/';
 | |
|     (function() {
 | |
| 
 | |
|       const loadKit = CanvasKitInit({
 | |
|         locateFile: (file) => '/static/' + file,
 | |
|       });
 | |
| 
 | |
|       const loadLottie = fetch(LOTTIE_JSON_PATH).then((resp) => {
 | |
|         return resp.text();
 | |
|       });
 | |
| 
 | |
|       const loadFontsAndAssets = loadLottie.then((jsonStr) => {
 | |
|         const lottie = JSON.parse(jsonStr);
 | |
|         const promises = [];
 | |
|         promises.push(...loadFonts(lottie.fonts));
 | |
|         promises.push(...loadAssets(lottie.assets));
 | |
|         return Promise.all(promises);
 | |
|       });
 | |
| 
 | |
|       Promise.all([loadKit, loadLottie, loadFontsAndAssets]).then((values) => {
 | |
|         const [CanvasKit, json, externalAssets] = values;
 | |
|         console.log(externalAssets);
 | |
|         const assets = {};
 | |
|         for (const asset of externalAssets) {
 | |
|           if (asset) {
 | |
|             assets[asset.name] = asset.bytes;
 | |
|           }
 | |
|         }
 | |
|         const loadStart = performance.now();
 | |
|         const animation = CanvasKit.MakeManagedAnimation(json, assets);
 | |
|         const loadTime = performance.now() - loadStart;
 | |
| 
 | |
|         window._perfData = {
 | |
|           json_load_ms: loadTime,
 | |
|         };
 | |
| 
 | |
|         const duration = animation.duration() * 1000;
 | |
|         const bounds = CanvasKit.LTRBRect(0, 0, WIDTH, HEIGHT);
 | |
| 
 | |
|         const urlSearchParams = new URLSearchParams(window.location.search);
 | |
|         let glversion = 2;
 | |
|         if (urlSearchParams.has('webgl1')) {
 | |
|           glversion = 1;
 | |
|         }
 | |
| 
 | |
|         const surface = getSurface(CanvasKit, glversion);
 | |
|         if (!surface) {
 | |
|           console.error('Could not make surface', window._error);
 | |
|           return;
 | |
|         }
 | |
|         const canvas = surface.getCanvas();
 | |
| 
 | |
|         document.getElementById('start_bench').addEventListener('click', async () => {
 | |
|           const startTime = Date.now();
 | |
|           const damageRect = Float32Array.of(0, 0, 0, 0);
 | |
| 
 | |
|           function draw() {
 | |
|             const seek = ((Date.now() - startTime) / duration) % 1.0;
 | |
|             const damage = animation.seek(seek, damageRect);
 | |
| 
 | |
|             if (damage[2] > damage[0] && damage[3] > damage[1]) {
 | |
|               animation.render(canvas, bounds);
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           startTimingFrames(draw, surface, WARM_UP_FRAMES, MAX_FRAMES, MAX_SAMPLE_MS).then((results) => {
 | |
|             Object.assign(window._perfData, results);
 | |
|             window._perfDone = true;
 | |
|           }).catch((error) => {
 | |
|             window._error = error;
 | |
|           });
 | |
| 
 | |
|         });
 | |
|         console.log('Perf is ready');
 | |
|         window._perfReady = true;
 | |
|       });
 | |
|     })();
 | |
| 
 | |
|   function loadFonts(fonts) {
 | |
|     const promises = [];
 | |
|     if (!fonts || !fonts.list) {
 | |
|       return promises;
 | |
|     }
 | |
|     for (const font of fonts.list) {
 | |
|       if (font.fName) {
 | |
|         promises.push(fetch(`${ASSETS_PATH}/${font.fName}.ttf`).then((resp) => {
 | |
|             // fetch does not reject on 404
 | |
|             if (!resp.ok) {
 | |
|               console.error(`Could not load ${font.fName}.ttf: status ${resp.status}`);
 | |
|               return null;
 | |
|             }
 | |
|             return resp.arrayBuffer().then((buffer) => {
 | |
|               return {
 | |
|                 'name': font.fName,
 | |
|                 'bytes': buffer
 | |
|               };
 | |
|             });
 | |
|           })
 | |
|         );
 | |
|       }
 | |
|     }
 | |
|     return promises;
 | |
|   }
 | |
| 
 | |
|   function loadAssets(assets) {
 | |
|     const promises = [];
 | |
|     if (!assets) {
 | |
|       return [];
 | |
|     }
 | |
|     for (const asset of assets) {
 | |
|       // asset.p is the filename, if it's an image.
 | |
|       // Don't try to load inline/dataURI images.
 | |
|       const should_load = asset.p && asset.p.startsWith && !asset.p.startsWith('data:');
 | |
|       if (should_load) {
 | |
|         promises.push(fetch(`${ASSETS_PATH}/${asset.p}`)
 | |
|           .then((resp) => {
 | |
|             // fetch does not reject on 404
 | |
|             if (!resp.ok) {
 | |
|               console.error(`Could not load ${asset.p}: status ${resp.status}`);
 | |
|               return null;
 | |
|             }
 | |
|             return resp.arrayBuffer().then((buffer) => {
 | |
|               return {
 | |
|                 'name': asset.p,
 | |
|                 'bytes': buffer
 | |
|               };
 | |
|             });
 | |
|           })
 | |
|         );
 | |
|       }
 | |
|     }
 | |
|     return promises;
 | |
|   }
 | |
|   </script>
 | |
| </body>
 | |
| </html>
 |