-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix slow debug inspector #9004
Fix slow debug inspector #9004
Changes from 8 commits
13bafc8
012a3d5
efa6629
8b7fc5a
d0fd9d2
0690e3b
48aba95
a43a090
32c9652
3beb6e2
ecdc593
c7dde23
976a31b
6a51c2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,136 @@ | ||||||
import clone from "../Core/clone.js"; | ||||||
import Color from "../Core/Color.js"; | ||||||
import DrawCommand from "../Renderer/DrawCommand.js"; | ||||||
import ShaderSource from "../Renderer/ShaderSource.js"; | ||||||
import ShaderProgram from "../Renderer/ShaderProgram.js"; | ||||||
import defined from "../Core/defined.js"; | ||||||
|
||||||
/** | ||||||
* @private | ||||||
*/ | ||||||
function DebugInspector() { | ||||||
this._cachedShowFrustumsShaders = {}; | ||||||
} | ||||||
|
||||||
function getAttributeLocations(shaderProgram) { | ||||||
var attributeLocations = {}; | ||||||
var attributes = shaderProgram.vertexAttributes; | ||||||
for (var a in attributes) { | ||||||
if (attributes.hasOwnProperty(a)) { | ||||||
attributeLocations[a] = attributes[a].index; | ||||||
} | ||||||
} | ||||||
|
||||||
return attributeLocations; | ||||||
} | ||||||
|
||||||
function createDebugShowFrustumsShaderProgram(scene, shaderProgram) { | ||||||
var context = scene.context; | ||||||
var sp = shaderProgram; | ||||||
var fs = sp.fragmentShaderSource.clone(); | ||||||
|
||||||
var targets = []; | ||||||
fs.sources = fs.sources.map(function (source) { | ||||||
source = ShaderSource.replaceMain(source, "czm_Debug_main"); | ||||||
var re = /gl_FragData\[(\d+)\]/g; | ||||||
var match; | ||||||
while ((match = re.exec(source)) !== null) { | ||||||
if (targets.indexOf(match[1]) === -1) { | ||||||
targets.push(match[1]); | ||||||
} | ||||||
} | ||||||
return source; | ||||||
}); | ||||||
var length = targets.length; | ||||||
|
||||||
var newMain = ""; | ||||||
newMain += "uniform vec3 debugShowCommandsColor;\n"; | ||||||
newMain += "uniform vec3 debugShowFrustumsColor;\n"; | ||||||
newMain += "void main() \n" + "{ \n" + " czm_Debug_main(); \n"; | ||||||
|
||||||
// set debugShowCommandsColor to Color(1.0, 1.0, 1.0, 1.0) to stop rendering scene.debugShowCommands | ||||||
// set debugShowFrustumsColor to Color(1.0, 1.0, 1.0, 1.0) to stop rendering scene.debugShowFrustums | ||||||
var i; | ||||||
if (length > 0) { | ||||||
for (i = 0; i < length; ++i) { | ||||||
newMain += | ||||||
" gl_FragData[" + targets[i] + "].rgb *= debugShowCommandsColor;\n"; | ||||||
newMain += | ||||||
" gl_FragData[" + targets[i] + "].rgb *= debugShowFrustumsColor;\n"; | ||||||
} | ||||||
} else { | ||||||
newMain += " gl_FragColor.rgb *= debugShowCommandsColor;\n"; | ||||||
newMain += " gl_FragColor.rgb *= debugShowFrustumsColor;\n"; | ||||||
} | ||||||
newMain += "}"; | ||||||
|
||||||
fs.sources.push(newMain); | ||||||
|
||||||
var attributeLocations = getAttributeLocations(sp); | ||||||
|
||||||
return ShaderProgram.fromCache({ | ||||||
context: context, | ||||||
vertexShaderSource: sp.vertexShaderSource, | ||||||
fragmentShaderSource: fs, | ||||||
attributeLocations: attributeLocations, | ||||||
}); | ||||||
} | ||||||
|
||||||
DebugInspector.prototype.createShowFrustumsCommand = function (scene, command) { | ||||||
// create debug command | ||||||
var debugCommand = DrawCommand.shallowClone(command); | ||||||
var shaderProgramId = command.shaderProgram.id; | ||||||
if (!defined(this._cachedShowFrustumsShaders[shaderProgramId])) { | ||||||
debugCommand.shaderProgram = createDebugShowFrustumsShaderProgram( | ||||||
scene, | ||||||
command.shaderProgram | ||||||
); | ||||||
|
||||||
this._cachedShowFrustumsShaders[shaderProgramId] = | ||||||
debugCommand.shaderProgram; | ||||||
} else { | ||||||
debugCommand.shaderProgram = this._cachedShowFrustumsShaders[ | ||||||
shaderProgramId | ||||||
]; | ||||||
} | ||||||
|
||||||
// setup uniform for the shader | ||||||
if (!defined(command.uniformMap) || typeof command.uniformMap !== "object") { | ||||||
debugCommand.uniformMap = {}; | ||||||
} else { | ||||||
debugCommand.uniformMap = clone(command.uniformMap); | ||||||
} | ||||||
|
||||||
if (scene.debugShowCommands) { | ||||||
if (!defined(command._debugColor)) { | ||||||
command._debugColor = Color.fromRandom(); | ||||||
} | ||||||
|
||||||
debugCommand.uniformMap.debugShowCommandsColor = function () { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably okay since this is debug code, but normally we wouldn't set the uniform function every frame since it allocates a new function object, creates a closure, etc, all of which can add garbage collection pressure. Instead we would add the uniform function on the command once. Maybe you could add |
||||||
return command._debugColor; | ||||||
}; | ||||||
} else { | ||||||
debugCommand.uniformMap.debugShowCommandsColor = function () { | ||||||
return new Color(1.0, 1.0, 1.0, 1.0); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More concise, and avoids the allocation when retrieving the uniform value every frame.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment for |
||||||
}; | ||||||
} | ||||||
|
||||||
if (scene.debugShowFrustums) { | ||||||
// Support up to three frustums. If a command overlaps all | ||||||
// three, it's code is not changed. | ||||||
var r = command.debugOverlappingFrustums & (1 << 0) ? 1.0 : 0.0; | ||||||
var g = command.debugOverlappingFrustums & (1 << 1) ? 1.0 : 0.0; | ||||||
var b = command.debugOverlappingFrustums & (1 << 2) ? 1.0 : 0.0; | ||||||
|
||||||
debugCommand.uniformMap.debugShowFrustumsColor = function () { | ||||||
return new Color(r, g, b, 1.0); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar comment to above. If you end up making a similar change here be sure use if (!defined(debugCommand.uniformMap.debugShowFrustumsColor)) {
debugCommand.uniformMap.debugShowFrustumsColor = function () {
var r = command.debugOverlappingFrustums & (1 << 0) ? 1.0 : 0.0;
var g = command.debugOverlappingFrustums & (1 << 1) ? 1.0 : 0.0;
var b = command.debugOverlappingFrustums & (1 << 2) ? 1.0 : 0.0;
return new Color(r, g, b, 1.0);
}
} Also instead of |
||||||
}; | ||||||
} else { | ||||||
debugCommand.uniformMap.debugShowFrustumsColor = function () { | ||||||
return new Color(1.0, 1.0, 1.0, 1.0); | ||||||
}; | ||||||
} | ||||||
|
||||||
return debugCommand; | ||||||
}; | ||||||
export default DebugInspector; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,11 +34,8 @@ import ClearCommand from "../Renderer/ClearCommand.js"; | |
import ComputeEngine from "../Renderer/ComputeEngine.js"; | ||
import Context from "../Renderer/Context.js"; | ||
import ContextLimits from "../Renderer/ContextLimits.js"; | ||
import DrawCommand from "../Renderer/DrawCommand.js"; | ||
import Pass from "../Renderer/Pass.js"; | ||
import RenderState from "../Renderer/RenderState.js"; | ||
import ShaderProgram from "../Renderer/ShaderProgram.js"; | ||
import ShaderSource from "../Renderer/ShaderSource.js"; | ||
import BrdfLutGenerator from "./BrdfLutGenerator.js"; | ||
import Camera from "./Camera.js"; | ||
import Cesium3DTilePass from "./Cesium3DTilePass.js"; | ||
|
@@ -72,6 +69,7 @@ import SunLight from "./SunLight.js"; | |
import SunPostProcess from "./SunPostProcess.js"; | ||
import TweenCollection from "./TweenCollection.js"; | ||
import View from "./View.js"; | ||
import DebugInspector from "./DebugInspector.js"; | ||
|
||
var requestRenderAfterFrame = function (scene) { | ||
return function () { | ||
|
@@ -262,6 +260,7 @@ function Scene(options) { | |
this._postRender = new Event(); | ||
|
||
this._minimumDisableDepthTestDistance = 0.0; | ||
this._debugInspector = new DebugInspector(); | ||
|
||
/** | ||
* Exceptions occurring in <code>render</code> are always caught in order to raise the | ||
|
@@ -1964,126 +1963,6 @@ Scene.prototype.isVisible = function (command, cullingVolume, occluder) { | |
); | ||
}; | ||
|
||
function getAttributeLocations(shaderProgram) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great idea to move this into it's own file and make |
||
var attributeLocations = {}; | ||
var attributes = shaderProgram.vertexAttributes; | ||
for (var a in attributes) { | ||
if (attributes.hasOwnProperty(a)) { | ||
attributeLocations[a] = attributes[a].index; | ||
} | ||
} | ||
|
||
return attributeLocations; | ||
} | ||
|
||
function createDebugFragmentShaderProgram(command, scene, shaderProgram) { | ||
var context = scene.context; | ||
var sp = defaultValue(shaderProgram, command.shaderProgram); | ||
var fs = sp.fragmentShaderSource.clone(); | ||
|
||
var targets = []; | ||
fs.sources = fs.sources.map(function (source) { | ||
source = ShaderSource.replaceMain(source, "czm_Debug_main"); | ||
var re = /gl_FragData\[(\d+)\]/g; | ||
var match; | ||
while ((match = re.exec(source)) !== null) { | ||
if (targets.indexOf(match[1]) === -1) { | ||
targets.push(match[1]); | ||
} | ||
} | ||
return source; | ||
}); | ||
var length = targets.length; | ||
|
||
var newMain = "void main() \n" + "{ \n" + " czm_Debug_main(); \n"; | ||
|
||
var i; | ||
if (scene.debugShowCommands) { | ||
if (!defined(command._debugColor)) { | ||
command._debugColor = Color.fromRandom(); | ||
} | ||
var c = command._debugColor; | ||
if (length > 0) { | ||
for (i = 0; i < length; ++i) { | ||
newMain += | ||
" gl_FragData[" + | ||
targets[i] + | ||
"].rgb *= vec3(" + | ||
c.red + | ||
", " + | ||
c.green + | ||
", " + | ||
c.blue + | ||
"); \n"; | ||
} | ||
} else { | ||
newMain += | ||
" " + | ||
"gl_FragColor" + | ||
".rgb *= vec3(" + | ||
c.red + | ||
", " + | ||
c.green + | ||
", " + | ||
c.blue + | ||
"); \n"; | ||
} | ||
} | ||
|
||
if (scene.debugShowFrustums) { | ||
// Support up to three frustums. If a command overlaps all | ||
// three, it's code is not changed. | ||
var r = command.debugOverlappingFrustums & (1 << 0) ? "1.0" : "0.0"; | ||
var g = command.debugOverlappingFrustums & (1 << 1) ? "1.0" : "0.0"; | ||
var b = command.debugOverlappingFrustums & (1 << 2) ? "1.0" : "0.0"; | ||
if (length > 0) { | ||
for (i = 0; i < length; ++i) { | ||
newMain += | ||
" gl_FragData[" + | ||
targets[i] + | ||
"].rgb *= vec3(" + | ||
r + | ||
", " + | ||
g + | ||
", " + | ||
b + | ||
"); \n"; | ||
} | ||
} else { | ||
newMain += | ||
" " + | ||
"gl_FragColor" + | ||
".rgb *= vec3(" + | ||
r + | ||
", " + | ||
g + | ||
", " + | ||
b + | ||
"); \n"; | ||
} | ||
} | ||
|
||
newMain += "}"; | ||
|
||
fs.sources.push(newMain); | ||
|
||
var attributeLocations = getAttributeLocations(sp); | ||
|
||
return ShaderProgram.fromCache({ | ||
context: context, | ||
vertexShaderSource: sp.vertexShaderSource, | ||
fragmentShaderSource: fs, | ||
attributeLocations: attributeLocations, | ||
}); | ||
} | ||
|
||
function executeDebugCommand(command, scene, passState) { | ||
var debugCommand = DrawCommand.shallowClone(command); | ||
debugCommand.shaderProgram = createDebugFragmentShaderProgram(command, scene); | ||
debugCommand.execute(scene.context, passState); | ||
debugCommand.shaderProgram.destroy(); | ||
} | ||
|
||
var transformFrom2D = new Matrix4( | ||
0.0, | ||
0.0, | ||
|
@@ -2260,7 +2139,11 @@ function executeCommand(command, scene, context, passState, debugFramebuffer) { | |
} | ||
|
||
if (scene.debugShowCommands || scene.debugShowFrustums) { | ||
executeDebugCommand(command, scene, passState); | ||
var debugCommand = scene._debugInspector.createShowFrustumsCommand( | ||
scene, | ||
command | ||
); | ||
debugCommand.execute(scene.context, passState); | ||
return; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When is the uniform map defined but not an object?