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