summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorericu@google.com <ericu@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-02 00:54:37 +0000
committerericu@google.com <ericu@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-02 00:54:37 +0000
commit117366a1d4d1d64322d021e444a2efa0e61ca5b9 (patch)
treea1de02e4e68910742400615ac522cdf6c3ab72cc
parent7a37de37359341143f01045aa1a0c5cb1843e252 (diff)
downloadchromium_src-117366a1d4d1d64322d021e444a2efa0e61ca5b9.zip
chromium_src-117366a1d4d1d64322d021e444a2efa0e61ca5b9.tar.gz
chromium_src-117366a1d4d1d64322d021e444a2efa0e61ca5b9.tar.bz2
Review URL: http://codereview.chromium.org/147258
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19795 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--o3d/plugin/idl/pack.idl2
-rw-r--r--o3d/samples/beachdemo/beachdemo.js130
-rw-r--r--o3d/samples/o3djs/js_list.scons1
-rw-r--r--o3d/samples/o3djs/performance.js195
4 files changed, 298 insertions, 30 deletions
diff --git a/o3d/plugin/idl/pack.idl b/o3d/plugin/idl/pack.idl
index 99b4863..d52424a 100644
--- a/o3d/plugin/idl/pack.idl
+++ b/o3d/plugin/idl/pack.idl
@@ -64,7 +64,7 @@ typedef ObjectBase[] ObjectArray;
\endcode
The only difference is that after all the objects are removed the pack
- itself will be released from the client. See documenation on
+ itself will be released from the client. See documentation on
pack.removeObject for why this is important.
It's important to note that many objects are only referenced by the pack.
diff --git a/o3d/samples/beachdemo/beachdemo.js b/o3d/samples/beachdemo/beachdemo.js
index 8bf52be..69bd455 100644
--- a/o3d/samples/beachdemo/beachdemo.js
+++ b/o3d/samples/beachdemo/beachdemo.js
@@ -49,9 +49,8 @@ o3djs.require('o3djs.canvas');
o3djs.require('o3djs.fps');
o3djs.require('o3djs.debug');
o3djs.require('o3djs.particles');
+o3djs.require('o3djs.performance');
-var RENDER_TARGET_WIDTH = 256;
-var RENDER_TARGET_HEIGHT = 256;
var PROXY_HEIGHT = 5150;
// client.root
@@ -128,6 +127,9 @@ var g_skyDomeTransform;
var g_waterTransform;
var g_reflectionTexture;
var g_refractionTexture;
+var g_reflectionImage;
+var g_refrectionImage;
+var g_depthSurface;
var g_globalParams;
var g_globalClockParam;
var g_clipHeightParam;
@@ -180,6 +182,9 @@ var g_downloadPercent = -1;
var g_showError = false;
var g_sceneEffects = [];
var g_sceneTexturesByURI;
+var g_renderTargetWidth = 256;
+var g_renderTargetHeight = 256;
+var g_perfMon;
var g_camera = {
farPlane: 80000,
@@ -1541,6 +1546,8 @@ function loadMainScene() {
}
}
}
+ g_perfMon = o3djs.performance.createPerformanceMonitor(
+ 25, 35, increaseRenderTargetResolution, decreaseRenderTargetResolution);
}
try {
@@ -1815,6 +1822,10 @@ function onRender(renderEvent) {
// Render the FPS display.
g_client.renderTree(g_fpsManager.viewInfo.root);
+
+ if (g_perfMon) {
+ g_perfMon.onRender(renderEvent.elapsedTime);
+ }
}
function onAllLoadingFinished() {
@@ -1843,6 +1854,82 @@ function init() {
o3djs.util.makeClients(initStep2);
}
+function setupRenderTargets() {
+ var oldReflectionTexture;
+ var oldRefractionTexture;
+ var oldDepthSurface;
+
+ if (g_reflectionTexture) {
+ g_mainPack.removeObject(g_reflectionSurfaceSet.renderSurface);
+ g_mainPack.removeObject(g_refractionSurfaceSet.renderSurface);
+ g_mainPack.removeObject(g_reflectionTexture);
+ g_mainPack.removeObject(g_refractionTexture);
+ g_mainPack.removeObject(g_depthSurface);
+ } else {
+ // First time only.
+ g_reflectionSurfaceSet = g_mainPack.createObject('RenderSurfaceSet');
+ g_refractionSurfaceSet = g_mainPack.createObject('RenderSurfaceSet');
+ }
+
+ // Create Render Targets for the reflection and refraction.
+ g_reflectionTexture = g_mainPack.createTexture2D(g_renderTargetWidth,
+ g_renderTargetHeight,
+ g_o3d.Texture.ARGB8, 1,
+ true);
+ var reflectionSurface = g_reflectionTexture.getRenderSurface(0, g_mainPack);
+ g_refractionTexture = g_mainPack.createTexture2D(g_renderTargetWidth,
+ g_renderTargetHeight,
+ g_o3d.Texture.XRGB8, 1,
+ true);
+ var refractionSurface = g_refractionTexture.getRenderSurface(0, g_mainPack);
+ g_depthSurface = g_mainPack.createDepthStencilSurface(g_renderTargetWidth,
+ g_renderTargetHeight);
+
+ // Set up the render graph to generate them.
+ g_reflectionSurfaceSet.renderSurface = reflectionSurface;
+ g_reflectionSurfaceSet.renderDepthStencilSurface = g_depthSurface;
+
+ g_refractionSurfaceSet.renderSurface = refractionSurface;
+ g_refractionSurfaceSet.renderDepthStencilSurface = g_depthSurface;
+
+ g_updateRenderTargets = true;
+
+ if (g_waterMaterial) { // Every time after the first.
+ var sampler = g_waterMaterial.getParam('reflectionSampler').value;
+ sampler.texture = g_reflectionTexture;
+ sampler = g_waterMaterial.getParam('refractionSampler').value;
+ sampler.texture = g_refractionTexture;
+ g_reflectionImage.sampler.texture = g_reflectionTexture;
+ g_refractionImage.sampler.texture = g_refractionTexture;
+ }
+}
+
+function increaseRenderTargetResolution() {
+ var changed;
+ if (g_renderTargetWidth < 2048) {
+ g_renderTargetWidth <<= 1;
+ changed = true;
+ }
+ if (g_renderTargetHeight < 2048) {
+ g_renderTargetHeight <<= 1;
+ changed = true;
+ }
+ setupRenderTargets();
+}
+
+function decreaseRenderTargetResolution() {
+ var changed;
+ if (g_renderTargetWidth > 256) {
+ g_renderTargetWidth >>= 1;
+ changed = true;
+ }
+ if (g_renderTargetHeight > 256) {
+ g_renderTargetHeight >>= 1;
+ changed = true;
+ }
+ setupRenderTargets();
+}
+
/**
* Initializes O3D and loads the scene into the transform graph.
* @param {Array} clientElements Array of o3d object elements.
@@ -1865,20 +1952,6 @@ function initStep2(clientElements) {
g_mainPack = g_client.createPack();
g_scenePack = g_client.createPack();
- // Create Render Targets for the reflection and refraction.
- g_reflectionTexture = g_mainPack.createTexture2D(RENDER_TARGET_WIDTH,
- RENDER_TARGET_HEIGHT,
- g_o3d.Texture.ARGB8, 1,
- true);
- var reflectionSurface = g_reflectionTexture.getRenderSurface(0, g_mainPack);
- g_refractionTexture = g_mainPack.createTexture2D(RENDER_TARGET_WIDTH,
- RENDER_TARGET_HEIGHT,
- g_o3d.Texture.XRGB8, 1,
- true);
- var refractionSurface = g_refractionTexture.getRenderSurface(0, g_mainPack);
- var depthSurface = g_mainPack.createDepthStencilSurface(RENDER_TARGET_WIDTH,
- RENDER_TARGET_HEIGHT);
-
g_mainRoot = g_mainPack.createObject('Transform');
g_baseRoot = g_scenePack.createObject('Transform');
g_baseRoot.parent = g_mainRoot;
@@ -1887,14 +1960,7 @@ function initStep2(clientElements) {
g_mainRoot.parent = g_client.root;
g_sceneRoot.translate(0, 0, -g_waterLevel);
- // Setup the render graph to generate them.
- g_reflectionSurfaceSet = g_mainPack.createObject('RenderSurfaceSet');
- g_reflectionSurfaceSet.renderSurface = reflectionSurface;
- g_reflectionSurfaceSet.renderDepthStencilSurface = depthSurface;
-
- g_refractionSurfaceSet = g_mainPack.createObject('RenderSurfaceSet');
- g_refractionSurfaceSet.renderSurface = refractionSurface;
- g_refractionSurfaceSet.renderDepthStencilSurface = depthSurface;
+ setupRenderTargets();
// Create states to set clipping.
g_reflectionClipState = g_mainPack.createObject('State');
@@ -2540,22 +2606,28 @@ function setupHud() {
// Make images to show the render targets.
for (var ii = 0; ii < 2; ++ii) {
+ var textureDisplaySquareSize = 256;
var renderTargetTexture = (ii == 0) ? g_reflectionTexture :
g_refractionTexture;
- var scale = 1;
var x = 10;
- var y = 10 + ii * (g_reflectionTexture.height * scale + 10);
+ var y = 10 + ii * (textureDisplaySquareSize + 10);
var borderSize = 2;
var image;
// make a back image to create a border around render target.
image = new Image(g_renderTargetDisplayRoot, backTexture, true);
image.transform.translate(x - borderSize, y - borderSize, -3);
- image.transform.scale(renderTargetTexture.width * scale + borderSize * 2,
- renderTargetTexture.height * scale + borderSize * 2,
+ image.transform.scale(textureDisplaySquareSize + borderSize * 2,
+ textureDisplaySquareSize + borderSize * 2,
1);
image = new Image(g_renderTargetDisplayRoot, renderTargetTexture, true);
image.transform.translate(x, y, -2);
- image.transform.scale(scale, scale, 1);
+ image.transform.scale(textureDisplaySquareSize / g_renderTargetWidth,
+ textureDisplaySquareSize / g_renderTargetHeight, 1);
+ if (ii == 0) {
+ g_reflectionImage = image;
+ } else {
+ g_refractionImage = image;
+ }
}
// Make a fader plane.
diff --git a/o3d/samples/o3djs/js_list.scons b/o3d/samples/o3djs/js_list.scons
index 5a0da33..f590330 100644
--- a/o3d/samples/o3djs/js_list.scons
+++ b/o3d/samples/o3djs/js_list.scons
@@ -45,6 +45,7 @@ O3D_JS_SOURCES = [
'math.js',
'pack.js',
'particles.js',
+ 'performance.js',
'picking.js',
'primitives.js',
'quaternions.js',
diff --git a/o3d/samples/o3djs/performance.js b/o3d/samples/o3djs/performance.js
new file mode 100644
index 0000000..055bf2e
--- /dev/null
+++ b/o3d/samples/o3djs/performance.js
@@ -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;
+ }
+ }
+}
+