Skip to content
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

Merged
merged 14 commits into from
Jul 9, 2020
Merged

Fix slow debug inspector #9004

merged 14 commits into from
Jul 9, 2020

Conversation

baothientran
Copy link
Contributor

@baothientran baothientran commented Jun 30, 2020

Fixes the debug inspector slowness

The issue is that when the scene has debug options turned on, debug commands will be created and executed in each frame. When a debug command is created, the shader of the original command has to be modified and recompiled in each frame as well. It is a very slow operation because the glsl text has to be created from a ShaderSource object. In WebGL 2, it is worse because of the extra step of modernizing the glsl code (for Scene.debugShowFrustums option, you can take a look at the function executeDebugCommand() in Scene.js and ShaderCache.getShaderProgram() in ShaderCache.js)

I created DebugInspector class to cache the debug shader by mapping the original shader id with it. This should speed up the frustum inspector significantly for both WebGL 1 and WebGL 2. If possible, I think I can move all the codes that are used to create debug commands (like debugShowBoundingVolume, etc...) from the Scene.js to DebugInspector.js. That should clean up the Scene.js file, and it is easier to add more state variables later on when debugging without polluting the Scene class.

@lilleyse can you please take a look at it? Please let me know if I should fix anything

@baothientran baothientran requested a review from lilleyse June 30, 2020 16:41
@cesium-concierge
Copy link

Thanks for the pull request @baothientran!

  • ✔️ Signed CLA found.
  • CHANGES.md was not updated.
    • If this change updates the public API in any way, please add a bullet point to CHANGES.md.
  • ❔ Unit tests were not updated.
    • Make sure you've updated tests to reflect your changes, added tests for any new code, and ran the code coverage tool.

Reviewers, don't forget to make sure that:

  • Cesium Viewer works.
  • Works in 2D/CV.
  • Works (or fails gracefully) in IE11.

};
} else {
debugCommand.uniformMap.debugShowCommandsColor = function () {
return new Color(1.0, 1.0, 1.0, 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The 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
return new Color(1.0, 1.0, 1.0, 1.0);
return Color.WHITE;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment for debugShowFrustumsColor

}

// setup uniform for the shader
if (!defined(command.uniformMap) || typeof command.uniformMap !== "object") {
Copy link
Contributor

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?

command._debugColor = Color.fromRandom();
}

debugCommand.uniformMap.debugShowCommandsColor = function () {
Copy link
Contributor

Choose a reason for hiding this comment

The 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 debugShowCommandsColor only if the uniform map doesn't already have a uniform with that name.

var b = command.debugOverlappingFrustums & (1 << 2) ? 1.0 : 0.0;

debugCommand.uniformMap.debugShowFrustumsColor = function () {
return new Color(r, g, b, 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

The 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 command in the closure instead of r, g, b since debugOverlappingFrustums changes every frame. E.g.

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 new Color(r, g, b, 1.0); you could use a scratch color to avoid the allocation. The GL uniforms get updated immediately after the function call so scratches are safe to use.

@@ -1964,126 +1963,6 @@ Scene.prototype.isVisible = function (command, cullingVolume, occluder) {
);
};

function getAttributeLocations(shaderProgram) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea to move this into it's own file and make Scene a little less cluttered

Comment on lines 91 to 92
defined(debugUniformMap.debugShowFrustumsColor) ||
defined(debugUniformMap.debugShowFrustumsColor)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
defined(debugUniformMap.debugShowFrustumsColor) ||
defined(debugUniformMap.debugShowFrustumsColor)
defined(debugUniformMap.debugShowCommandsColor ) ||
defined(debugUniformMap.debugShowFrustumsColor)

debugUniformMap = {};
} else {
debugUniformMap = clone(command.uniformMap);
// debugUniformMap = command.uniformMap;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I left a github comment here, but it maybe not shown up to you. My first time using github to contribute to the open source, so I'm still confused about some of its functionalities. Let me paste the comment below and the Sandcastle example for the issue as well:

I try to insert debug uniforms to the current command uniform and stop creating debug uniform closures if they already exist in the command uniform. But there is a problem that when the debug uniform closure captures the command, it may not be the command that is currently being executed. If you un-comment line 87 and have scene.debugShowCommand = true, the cesium billboard's debug color stop changing frequently. I'm not entirely sure, but I think the debug uniform closure only captures one of the billboard's command, which is not correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, I didn't see your comment. Maybe it was part of an in-progress review that didn't get submitted?

But there is a problem that when the debug uniform closure captures the command, it may not be the command that is currently being executed

Which suggests the billboard system might be creating a new command every frame but using the same uniform map object. That's interesting...

I prefer the non flickery behavior actually, even though it's different than master. I'd be happy to merge the debugUniformMap = command.uniformMap version.

Comment on lines 90 to 95
if (
defined(debugUniformMap.debugShowFrustumsColor) ||
defined(debugUniformMap.debugShowFrustumsColor)
) {
return debugUniformMap;
}
Copy link
Contributor

@lilleyse lilleyse Jul 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this condition will actually get hit because debugUniformMap is always cloned from the original command which doesn't contain these properties.

Should clone(command.uniformMap); be command.uniformMap after all? I see it was commented out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup this check is initially used for the case debugUniformMap = command.uniformMap. I temporarily left it here since I get a bug when using the shallow copy for uniformMap (I documented the bug in the reply to your comment above)

@baothientran
Copy link
Contributor Author

@lilleyse I've changed clone(uniformMap) to shallow copy. It is ready for review.

@lilleyse
Copy link
Contributor

lilleyse commented Jul 9, 2020

@baothientran did you see #9004 (comment)? I think that's all that's left.

@baothientran
Copy link
Contributor Author

Whoops I missed that. Let me fix it right away

@baothientran
Copy link
Contributor Author

@lilleyse updated

@lilleyse
Copy link
Contributor

lilleyse commented Jul 9, 2020

Thanks @baothientran!

@lilleyse lilleyse merged commit 44ac2ff into master Jul 9, 2020
@lilleyse lilleyse deleted the webgl2-slow-inspector branch July 9, 2020 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants