1cb93a386Sopenharmony_ci// Shared benchmarking functions such as surface creation, measurement, publishing to perf.skia.org 2cb93a386Sopenharmony_ci 3cb93a386Sopenharmony_cifunction getSurface(CanvasKit, webglversion) { 4cb93a386Sopenharmony_ci let surface; 5cb93a386Sopenharmony_ci if (window.location.hash.indexOf('gpu') !== -1) { 6cb93a386Sopenharmony_ci surface = CanvasKit.MakeWebGLCanvasSurface('anim', null /* colorspace */, {'majorVersion': webglversion}); 7cb93a386Sopenharmony_ci if (!surface) { 8cb93a386Sopenharmony_ci window._error = 'Could not make GPU surface'; 9cb93a386Sopenharmony_ci return null; 10cb93a386Sopenharmony_ci } 11cb93a386Sopenharmony_ci let c = document.getElementById('anim'); 12cb93a386Sopenharmony_ci // If CanvasKit was unable to instantiate a WebGL context, it will fallback 13cb93a386Sopenharmony_ci // to CPU and add a ck-replaced class to the canvas element. 14cb93a386Sopenharmony_ci if (c.classList.contains('ck-replaced')) { 15cb93a386Sopenharmony_ci window._error = 'fell back to CPU'; 16cb93a386Sopenharmony_ci return null; 17cb93a386Sopenharmony_ci } 18cb93a386Sopenharmony_ci } else { 19cb93a386Sopenharmony_ci surface = CanvasKit.MakeSWCanvasSurface('anim'); 20cb93a386Sopenharmony_ci if (!surface) { 21cb93a386Sopenharmony_ci window._error = 'Could not make CPU surface'; 22cb93a386Sopenharmony_ci return null; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci return surface; 26cb93a386Sopenharmony_ci} 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci// Time the drawing and flushing of a frame drawing function on a given surface. 29cb93a386Sopenharmony_ci// drawFn is expected to be a zero arg function making draw calls to a canvas 30cb93a386Sopenharmony_ci// warmupFrames - Run this number of frames before starting to measure things. 31cb93a386Sopenharmony_ci// This allows us to make sure the noise from the first few renders (e.g shader 32cb93a386Sopenharmony_ci// compilation, caches) is removed from the data we capture. 33cb93a386Sopenharmony_ci// Stops after timeoutMillis if provided 34cb93a386Sopenharmony_ci// Teturns a promise that resolves with the dict of measurements. 35cb93a386Sopenharmony_cifunction startTimingFrames(drawFn, surface, warmupFrames, maxFrames, timeoutMillis) { 36cb93a386Sopenharmony_ci return new Promise((resolve, reject) => { 37cb93a386Sopenharmony_ci const totalFrame = new Float32Array(maxFrames); 38cb93a386Sopenharmony_ci const withFlush = new Float32Array(maxFrames); 39cb93a386Sopenharmony_ci const withoutFlush = new Float32Array(maxFrames); 40cb93a386Sopenharmony_ci let warmUp = warmupFrames > 0; 41cb93a386Sopenharmony_ci let idx = -1; 42cb93a386Sopenharmony_ci let previousFrame; 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci function drawFrame() { 45cb93a386Sopenharmony_ci let start, afterDraw, end; 46cb93a386Sopenharmony_ci try { 47cb93a386Sopenharmony_ci start = performance.now(); 48cb93a386Sopenharmony_ci drawFn(); 49cb93a386Sopenharmony_ci afterDraw = performance.now(); 50cb93a386Sopenharmony_ci surface.flush(); 51cb93a386Sopenharmony_ci end = performance.now(); 52cb93a386Sopenharmony_ci } catch (e) { 53cb93a386Sopenharmony_ci console.error(e); 54cb93a386Sopenharmony_ci window._error = e.stack || e.toString(); 55cb93a386Sopenharmony_ci return; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci if (warmUp) { 59cb93a386Sopenharmony_ci idx++; 60cb93a386Sopenharmony_ci if (idx >= warmupFrames) { 61cb93a386Sopenharmony_ci idx = -1; 62cb93a386Sopenharmony_ci warmUp = false; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci window.requestAnimationFrame(drawFrame); 65cb93a386Sopenharmony_ci return; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci if (idx >= 0) { 68cb93a386Sopenharmony_ci // Fill out total time the previous frame took to draw. 69cb93a386Sopenharmony_ci totalFrame[idx] = start - previousFrame; 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci previousFrame = start; 72cb93a386Sopenharmony_ci idx++; 73cb93a386Sopenharmony_ci // If we have maxed out the frames we are measuring or have completed the animation, 74cb93a386Sopenharmony_ci // we stop benchmarking. 75cb93a386Sopenharmony_ci if (!window._perfData) { 76cb93a386Sopenharmony_ci window._perfData = {}; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci if (idx >= withFlush.length) { 79cb93a386Sopenharmony_ci resolve({ 80cb93a386Sopenharmony_ci // The total time elapsed between the same point during the drawing of each frame. 81cb93a386Sopenharmony_ci // This is the most relevant measurement for normal drawing tests. 82cb93a386Sopenharmony_ci 'total_frame_ms': Array.from(totalFrame).slice(0, idx), 83cb93a386Sopenharmony_ci // The time taken to run the code under test and call surface.flush() 84cb93a386Sopenharmony_ci 'with_flush_ms': Array.from(withFlush).slice(0, idx), 85cb93a386Sopenharmony_ci // The time taken to run the code under test 86cb93a386Sopenharmony_ci // This is the most relevant measurement for non-drawing tests such as matrix inversion. 87cb93a386Sopenharmony_ci 'without_flush_ms': Array.from(withoutFlush).slice(0, idx), 88cb93a386Sopenharmony_ci }); 89cb93a386Sopenharmony_ci return; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci // We can fill out this frame's intermediate steps. 93cb93a386Sopenharmony_ci withFlush[idx] = end - start; 94cb93a386Sopenharmony_ci withoutFlush[idx] = afterDraw - start; 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci if (timeoutMillis && ((beginTest + timeoutMillis) < performance.now())) { 97cb93a386Sopenharmony_ci console.log(`test aborted due to timeout after ${idx} frames`); 98cb93a386Sopenharmony_ci reject(`test aborted due to timeout after ${idx} frames`); 99cb93a386Sopenharmony_ci return; 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci window.requestAnimationFrame(drawFrame); 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci const beginTest = performance.now(); 104cb93a386Sopenharmony_ci window.requestAnimationFrame(drawFrame); 105cb93a386Sopenharmony_ci }); // new promise 106cb93a386Sopenharmony_ci} 107