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