-
-
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
Swap material and mesh bind groups #10485
Conversation
As a followup PR, we'll probably want to sort draws by pipeline id. |
Hmm pretty sure someone flipped these for some reason awhile back (with some reasonable justification for going against the "mesh before material" bind frequency advice) . Iirc it was some sort of technical details thing (ex: architectural limitation, platform support), not a performance thing. Worth trying to find that context. |
Because yeah this is the right approach. And I'm pretty sure I did it this way in the past. |
the current order used to be (potentially) better for performance before we batched meshes. now it makes more sense to put mesh first as the batch of meshes won't need frequent rebinding. |
Right so after moving mesh data (not mesh vertex data, just the MeshUniforms) to GpuArrayBuffer, the bind group should almost never need to be rebound (for normal meshes). What does need rebinding is:
(Note: We probably want to sort draws so regular/skinned/morph meshes are grouped together, after material sorting) So the only way this PR loses out currently is for e.g. skinned meshes, where you may have two different skinned meshes with the same material. This PR would cause you to have to rebind the material for each unique skinned mesh, which is expensive. But this PR is better for regular meshes... |
For CPU-driven rendering, I guess maybe it makes more sense to keep this as-is to avoid expensive material (pipeline) rebinds. For GPU-driven, where the pipeline is the only rebind, I can just put materials in bind group 2 anyways. I'm thinking we should close this. |
Cool yeah that all makes sense! |
@JMS55 I'm not so sure. I think this is useful for CPU-driven as well. Considering the two bind groups:
The usual case for mesh assets is lots of non-skinned + non-morphed mesh entities and few skinned / morphed mesh entities. So prioritising the defaults for non-skinned / non-morphed entities makes sense. And those require one binding as all the data they need is in one buffer. The usual case for material assets with the current solution is a bit less clear:
Either way, rebinding for a material asset is at best once per group of mesh entities, and at worst once per mesh entity. The only situation I can think of where it would be 'worse' would be for entities using different skinned/morphed mesh assets which have the same material. Unless I'm missing something, that seems very niche and unlikely? I think at this point it does make sense to swap the material and mesh bind groups. I'd suggest reopening this and merging it, as well as in a separate PR, changing the sorting of the opaque and alpha mask passes. If we do swap the binding order, then we would want to sort by pipeline id, mesh bind group id + dynamic offset, material bind group id, z front to back. Though we'd want to test the impact on sorting performance for non-trivial configurations to see whether we could cut down on those sort key fields. |
Would it be possible to move the skinning and morph data into storage buffers? More perf, and we'd avoid this whole issue to begin with. |
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.
lgtm.
one lingering "group 1" in a comment in bind_group.rs:
/// ... in Bevy material bind groups
/// are generally bound to group 1.
i haven't checked performance - i don't expect any regressions but maybe we ought to benchmark?
Shouldn't be any regressions atm I don't think, as we don't sort primarily by pipeline/bind group yet. It'll limit the max perf we can have for skinned meshes/morph targets in the future though (as they use a separate vertex buffer per mesh), but that's a tradeoff we'll have to accept, unless we want to add a toggle to the shader code to switch the group orderings (which we could also easily do). EDIT: I personally can't benchmark anything well for the next 2 weeks, as I only have access to an old laptop atm. |
I have a branch locally that does this for skinning. Morph uses textures so it's a different beast. And we still can't avoid it because the current approach is the best we can do for uniform buffers and not everyone has access to storage buffers. |
@@ -2,20 +2,8 @@ | |||
|
|||
#import bevy_pbr::mesh_types::Mesh | |||
|
|||
#ifdef MESH_BINDGROUP_1 |
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.
🚀
# Objective - Materials should be a more frequent rebind then meshes (due to being able to use a single vertex buffer, such as in bevyengine#10164) and therefore should be in a higher bind group. --- ## Changelog - For 2d and 3d mesh/material setups (but not UI materials, or other rendering setups such as gizmos, sprites, or text), mesh data is now in bind group 1, and material data is now in bind group 2, which is swapped from how they were before. ## Migration Guide - Custom 2d and 3d mesh/material shaders should now use bind group 2 `@group(2) @binding(x)` for their bound resources, instead of bind group 1. - Many internal pieces of rendering code have changed so that mesh data is now in bind group 1, and material data is now in bind group 2. Semi-custom rendering setups (that don't use the Material or Material2d APIs) should adapt to these changes.
* wip: took more than the 30 mins I have available -- will have to finish this later * wip: keycodes, digits... misc renaming * wip: 2d working -- panic on 3d checking that out now... * chore: they've all gotta be on grout 2 bevyengine/bevy#10485 * chore: bulk replace all group(1)s to group(2)s for bevy 0.13.. * fix: make the might example work * chore: make the cube much, much bigger!
Objective
Changelog
Migration Guide
@group(2) @binding(x)
for their bound resources, instead of bind group 1.