| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| 'use strict'; |
| |
| /** |
| * @fileoverview This file provides the RenderingStats object, used |
| * to characterize rendering smoothness. |
| */ |
| (function() { |
| var getTimeMs = (function() { |
| if (window.performance) |
| return (performance.now || |
| performance.mozNow || |
| performance.msNow || |
| performance.oNow || |
| performance.webkitNow).bind(window.performance); |
| else |
| return function() { return new Date().getTime(); }; |
| })(); |
| |
| var requestAnimationFrame = (function() { |
| return window.requestAnimationFrame || |
| window.webkitRequestAnimationFrame || |
| window.mozRequestAnimationFrame || |
| window.oRequestAnimationFrame || |
| window.msRequestAnimationFrame || |
| function(callback) { |
| window.setTimeout(callback, 1000 / 60); |
| }; |
| })().bind(window); |
| |
| /** |
| * Tracks rendering performance using the gpuBenchmarking.renderingStats API. |
| * @constructor |
| */ |
| function GpuBenchmarkingRenderingStats() { |
| } |
| |
| GpuBenchmarkingRenderingStats.prototype.start = function() { |
| this.startTime_ = getTimeMs(); |
| this.initialStats_ = this.getRenderingStats_(); |
| } |
| |
| GpuBenchmarkingRenderingStats.prototype.stop = function() { |
| this.stopTime_ = getTimeMs(); |
| this.finalStats_ = this.getRenderingStats_(); |
| } |
| |
| GpuBenchmarkingRenderingStats.prototype.getStartValues = function() { |
| if (!this.initialStats_) |
| throw new Error('Start not called.'); |
| |
| if (!this.finalStats_) |
| throw new Error('Stop was not called.'); |
| |
| return this.initialStats_; |
| } |
| |
| GpuBenchmarkingRenderingStats.prototype.getEndValues = function() { |
| if (!this.initialStats_) |
| throw new Error('Start not called.'); |
| |
| if (!this.finalStats_) |
| throw new Error('Stop was not called.'); |
| |
| return this.finalStats_; |
| } |
| |
| GpuBenchmarkingRenderingStats.prototype.getDeltas = function() { |
| if (!this.initialStats_) |
| throw new Error('Start not called.'); |
| |
| if (!this.finalStats_) |
| throw new Error('Stop was not called.'); |
| |
| var stats = {} |
| for (var key in this.finalStats_) |
| stats[key] = this.finalStats_[key] - this.initialStats_[key]; |
| return stats; |
| }; |
| |
| GpuBenchmarkingRenderingStats.prototype.getRenderingStats_ = function() { |
| var stats = chrome.gpuBenchmarking.renderingStats(); |
| stats.totalTimeInSeconds = getTimeMs() / 1000; |
| return stats; |
| }; |
| |
| /** |
| * Tracks rendering performance using requestAnimationFrame. |
| * @constructor |
| */ |
| function RafRenderingStats() { |
| this.recording_ = false; |
| this.frameTimes_ = []; |
| } |
| |
| RafRenderingStats.prototype.start = function() { |
| if (this.recording_) |
| throw new Error('Already started.'); |
| this.recording_ = true; |
| requestAnimationFrame(this.recordFrameTime_.bind(this)); |
| } |
| |
| RafRenderingStats.prototype.stop = function() { |
| this.recording_ = false; |
| } |
| |
| RafRenderingStats.prototype.getStartValues = function() { |
| var results = {}; |
| results.numAnimationFrames = 0; |
| results.numFramesSentToScreen = 0; |
| results.droppedFrameCount = 0; |
| return results; |
| } |
| |
| RafRenderingStats.prototype.getEndValues = function() { |
| var results = {}; |
| results.numAnimationFrames = this.frameTimes_.length - 1; |
| results.numFramesSentToScreen = results.numAnimationFrames; |
| results.droppedFrameCount = this.getDroppedFrameCount_(this.frameTimes_); |
| return results; |
| } |
| |
| RafRenderingStats.prototype.getDeltas = function() { |
| var endValues = this.getEndValues(); |
| endValues.totalTimeInSeconds = ( |
| this.frameTimes_[this.frameTimes_.length - 1] - |
| this.frameTimes_[0]) / 1000; |
| return endValues; |
| }; |
| |
| RafRenderingStats.prototype.recordFrameTime_ = function(timestamp) { |
| if (!this.recording_) |
| return; |
| |
| this.frameTimes_.push(timestamp); |
| requestAnimationFrame(this.recordFrameTime_.bind(this)); |
| }; |
| |
| RafRenderingStats.prototype.getDroppedFrameCount_ = function(frameTimes) { |
| var droppedFrameCount = 0; |
| for (var i = 1; i < frameTimes.length; i++) { |
| var frameTime = frameTimes[i] - frameTimes[i-1]; |
| if (frameTime > 1000 / 55) |
| droppedFrameCount++; |
| } |
| return droppedFrameCount; |
| }; |
| |
| function RenderingStats() { |
| if (window.chrome && chrome.gpuBenchmarking && |
| chrome.gpuBenchmarking.renderingStats) { |
| return new GpuBenchmarkingRenderingStats(); |
| } |
| return new RafRenderingStats(); |
| } |
| |
| window.__RenderingStats = RenderingStats; |
| })(); |