Index: samples/o3djs/performance.js |
=================================================================== |
--- samples/o3djs/performance.js (revision 0) |
+++ samples/o3djs/performance.js (revision 0) |
@@ -0,0 +1,195 @@ |
+/* |
+ * Copyright 2009, Google Inc. |
+ * All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions are |
+ * met: |
+ * |
+ * * Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above |
+ * copyright notice, this list of conditions and the following disclaimer |
+ * in the documentation and/or other materials provided with the |
+ * distribution. |
+ * * Neither the name of Google Inc. nor the names of its |
+ * contributors may be used to endorse or promote products derived from |
+ * this software without specific prior written permission. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+ |
+ |
+/** |
+ * @fileoverview This file contains a utility that helps adjust rendering |
+ * quality [or any other setting, really] based on rendering performance. |
+ * |
+ */ |
+ |
+o3djs.provide('o3djs.performance'); |
+ |
+/** |
+ * Creates a utility that monitors performance [in terms of FPS] and helps to |
+ * adjust the rendered scene accordingly. |
+ * @param {number} targetFPSMin the minimum acceptable frame rate; if we're |
+ * under this, try to decrease quality to improve performance. |
+ * @param {number} targetFPSMax if we're over this, try to increase quality. |
+ * @param {!function(): void} increaseQuality a function to increase |
+ * quality because we're rendering at high-enough FPS to afford it. |
+ * @param {!function(): void} decreaseQuality a function to decrease |
+ * quality to try to raise our rendering speed. |
+ * @param {!o3djs.performance.PerformanceMonitor.Options} opt_options Options. |
+ * @return {!o3djs.performance.PerformanceMonitor} The created |
+ * PerformanceMonitor. |
+ */ |
+o3djs.performance.createPerformanceMonitor = function( |
+ targetFPSMin, targetFPSMax, increaseQuality, decreaseQuality, opt_options) { |
+ return new o3djs.performance.PerformanceMonitor(targetFPSMin, targetFPSMax, |
+ increaseQuality, decreaseQuality, opt_options); |
+} |
+ |
+/** |
+ * A class that monitors performance [in terms of FPS] and helps to adjust the |
+ * rendered scene accordingly. |
+ * @constructor |
+ * @param {number} targetFPSMin the minimum acceptable frame rate; if we're |
+ * under this, try to decrease quality to improve performance. |
+ * @param {number} targetFPSMax if we're over this, try to increase quality. |
+ * @param {function(): void} increaseQuality a function to increase |
+ * quality/lower FPS. |
+ * @param {function(): void} decreaseQuality a function to decrease |
+ * quality/raise FPS. |
+ * @param {!o3djs.performance.PerformanceMonitor.Options} opt_options Options. |
+ */ |
+o3djs.performance.PerformanceMonitor = function( |
+ targetFPSMin, targetFPSMax, increaseQuality, decreaseQuality, opt_options) { |
+ opt_options = opt_options || {}; |
+ |
+ /** |
+ * A function to increase quality/lower FPS. |
+ * @type {function(): void} |
+ */ |
+ this.increaseQuality = increaseQuality; |
+ |
+ /** |
+ * A function to decrease quality/raise FPS. |
+ * @type {function(): void} |
+ */ |
+ this.decreaseQuality = decreaseQuality; |
+ |
+ /** |
+ * The mean time taken per frame so far, in seconds. This is only valid once |
+ * we've collected at least minSamples samples. |
+ * @type {number} |
+ */ |
+ this.meanFrameTime = 0; |
+ |
+ /** |
+ * The number of samples we've collected so far, when that number is less than |
+ * or equal to this.damping. After that point, we no longer update |
+ * this.sampleCount, so it will clip at this.damping. |
+ * |
+ * @type {number} |
+ */ |
+ this.sampleCount = 0; |
+ |
+ /** |
+ * The minimum number of samples to collect before trying to adjust quality. |
+ * |
+ * @type {number} |
+ */ |
+ this.minSamples = opt_options.opt_minSamples || 60; |
+ |
+ /** |
+ * A number that controls the rate at which the effects of any given sample |
+ * fade away. Higher is slower, but also means that each individual sample |
+ * counts for less at its most-influential. Damping defaults to 120; anywhere |
+ * between 60 and 600 are probably reasonable values, depending on your needs, |
+ * but the number must be no less than minSamples. |
+ * |
+ * @type {number} |
+ */ |
+ this.damping = opt_options.opt_damping || 120; |
+ |
+ /** |
+ * The minimum number of samples to take in between adjustments, to cut down |
+ * on overshoot. It defaults to 2 * minSamples. |
+ * |
+ * @type {number} |
+ */ |
+ this.delayCycles = opt_options.opt_delayCycles || 2 * this.minSamples; |
+ |
+ this.targetFrameTimeMax_ = 1 / targetFPSMin; |
+ this.targetFrameTimeMin_ = 1 / targetFPSMax; |
+ this.scaleInput_ = 1 / this.minSamples; |
+ this.scaleMean_ = 1; |
+ this.delayCyclesLeft_ = 0; |
+ if (this.damping < this.minSamples) { |
+ throw Error('Damping must be at least minSamples.'); |
+ } |
+} |
+ |
+/** |
+ * Options for the PerformanceMonitor. |
+ * |
+ * opt_minSamples is the minimum number of samples to take before making any |
+ * performance adjustments. |
+ * opt_damping is a number that controls the rate at which the effects of any |
+ * given sample fade away. Higher is slower, but also means that each |
+ * individual sample counts for less at its most-influential. Damping |
+ * defaults to 120; anywhere between 60 and 600 are probably reasonable values, |
+ * depending on your needs, but the number must be no less than minSamples. |
+ * opt_delayCycles is the minimum number of samples to take in between |
+ * adjustments, to cut down on overshoot. It defaults to 2 * opt_minSamples. |
+ * |
+ * @type {{ |
+ * opt_minSamples: number, |
+ * opt_damping: number, |
+ * opt_delayCycles, number |
+ * }} |
+ */ |
+o3djs.performance.PerformanceMonitor.Options = goog.typedef; |
+ |
+/** |
+ * Call this once per frame with the elapsed time since the last call, and it |
+ * will attempt to adjust your rendering quality as needed. |
+ * |
+ * @param {number} seconds the elapsed time since the last frame was rendered, |
+ * in seconds. |
+ */ |
+o3djs.performance.PerformanceMonitor.prototype.onRender = function(seconds) { |
+ var test = true; |
+ if (this.sampleCount < this.damping) { |
+ if (this.sampleCount >= this.minSamples) { |
+ this.scaleInput_ = 1 / (this.sampleCount + 1); |
+ this.scaleMean_ = this.sampleCount * this.scaleInput_; |
+ } else { |
+ test = false; |
+ } |
+ this.sampleCount += 1; |
+ } |
+ this.meanFrameTime = this.meanFrameTime * this.scaleMean_ + |
+ seconds * this.scaleInput_; |
+ if (this.delayCyclesLeft_ > 0) { |
+ this.delayCyclesLeft_ -= 1; |
+ } else if (test) { |
+ if (this.meanFrameTime < this.targetFrameTimeMin_) { |
+ this.increaseQuality(); |
+ this.delayCyclesLeft_ = this.delayCycles; |
+ } else if (this.meanFrameTime > this.targetFrameTimeMax_) { |
+ this.decreaseQuality(); |
+ this.delayCyclesLeft_ = this.delayCycles; |
+ } |
+ } |
+} |
+ |