Add bindless support for 2D materials.#24833
Conversation
87906a6 to
c889703
Compare
| /// The material bind group allocator is infrastructure for bindless resources. | ||
| /// It packs multiple materials into a small number of bind groups, allowing | ||
| /// Bevy to render large parts of the scene with a small number of drawcalls. | ||
| pub struct MaterialBindGroupsPlugin; |
There was a problem hiding this comment.
Could you split this PR - one to move material bind groups from pbr to render
The other to update colour and sprite materials to use it
There was a problem hiding this comment.
OK, I ripped the ColorMaterial and SpriteMaterial update out of this PR. It’ll be a follow-up.
There was a problem hiding this comment.
Cheers, it just makes it easier to follow
|
The generated |
At the moment, Bevy must issue a separate drawcall and bind group switch for each 2D object with a different texture, incurring significant `wgpu` and driver overhead. To address this problem, this commit ports the bindless support that the 3D PBR pipeline has long enjoyed to the 2D pipeline as well. Bindless allows Bevy to batch 2D meshes into single drawcalls as long as they share the same mesh, even if their materials (including textures) differ. To implement bindless, this patch moves the efficient material bind group allocator from `bevy_pbr` to `bevy_render`. Like the 3D PBR pipeline, the code in this PR checks to see whether bindless is supported on the current platform and automatically falls back to non-bindless if it isn't. Because the logic needed to support bindless is tightly intertwined with the logic needed to prepare pipelines, this PR also overhauls `specialize_material2d_meshes`. That function is now very similar to the one in the 3D pipeline. At some point, it'd probably be best to merge the core logic of this function for the 2D and 3D pipelines together. However, I opted to leave that to a follow-up for two reasons: (1) it's easier to verify in review that the 2D and 3D functions are the same than to verify that any added layers of abstraction are correct; (2) it might (or might not) be best to wait until multi-draw indirect is added to the 2D pipeline to do the refactoring. Per review request, I've left the migration of `ColorMaterial` and `SpriteMaterial` over to bindless to a follow-up. With this follow-up (*not in this PR*), on the `bevymark` example with `--waves 1 --per-wave 10000 --vary-per-instance --material-texture-count 1000`, I observed: * With the dedicated sprite rendering path, which doesn't use bindless, I get 21.5 ms/frame, or 47 FPS. * With the `SpriteMaterial` path, with the follow-up patch that adds bindless support to that material, I get 17.4 ms/frame, or 67 FPS. * With the `SpriteMaterial` path on `main`, I get 29.7 ms/frame, or 38.2 FPS. The follow-up patch is therefore a 1.71× speedup on that workload for `SpriteMaterial` and a 1.24× speedup over the dedicated sprite rendering path. Note that, in that follow-up patch, order to see the changes in action, I had to change `bevymark` to avoid using the same seed for all its parallel RNGs. Without that change, the fact that each RNG uses the same seed means that each texture effectively gets its own Z layer, causing the benchmark to degenerate into the optimal scenario for batching in the non-bindless case. The follow-up PR scrambles the RNG seeds to avoid this pathological, unrealistic behavior.
c889703 to
8561eed
Compare
|
check-advisories failure seems unrelated to this PR. |
| @@ -238,7 +237,7 @@ pub struct AlphaMask2dBinKey { | |||
| /// the ID of another type of asset. | |||
| pub asset_id: UntypedAssetId, | |||
| /// The ID of a bind group specific to the material. | |||
There was a problem hiding this comment.
nit: the comment should refer to an index, not ID
|
|
||
| /// A [`Plugin`] that supplies generic infrastructure for 2D materials. | ||
| #[derive(Default)] | ||
| pub struct Materials2dPlugin; |
Zeophlite
left a comment
There was a problem hiding this comment.
Thanks for taking the time to improve 2d
At the moment, Bevy must issue a separate drawcall and bind group switch for each 2D object with a different texture, incurring significant
wgpuand driver overhead. To address this problem, this commit ports the bindless support that the 3D PBR pipeline has long enjoyed to the 2D pipeline as well. Bindless allows Bevy to batch 2D meshes into single drawcalls as long as they share the same mesh, even if their materials (including textures) differ.To implement bindless, this patch moves the efficient material bind group allocator from
bevy_pbrtobevy_render. Like the 3D PBR pipeline, the code in this PR checks to see whether bindless is supported on the current platform and automatically falls back to non-bindless if it isn't.Because the logic needed to support bindless is tightly intertwined with the logic needed to prepare pipelines, this PR also overhauls
specialize_material2d_meshes. That function is now very similar to the one in the 3D pipeline. At some point, it'd probably be best to merge the core logic of this function for the 2D and 3D pipelines together. However, I opted to leave that to a follow-up for two reasons: (1) it's easier to verify in review that the 2D and 3D functions are the same than to verify that any added layers of abstraction are correct; (2) it might (or might not) be best to wait until multi-draw indirect is added to the 2D pipeline to do the refactoring.Per review request, I've left the migration of
ColorMaterialandSpriteMaterialover to bindless to a follow-up. With this follow-up (not in this PR), on thebevymarkexample with--waves 1 --per-wave 10000 --vary-per-instance --material-texture-count 1000, I observed:With the dedicated sprite rendering path, which doesn't use bindless, I get 21.5 ms/frame, or 47 FPS.
With the
SpriteMaterialpath, with the follow-up patch that adds bindless support to that material, I get 17.4 ms/frame, or 67 FPS.With the
SpriteMaterialpath onmain, I get 29.7 ms/frame, or 38.2 FPS.The follow-up patch is therefore a 1.71× speedup on that workload for
SpriteMaterialand a 1.24× speedup over the dedicated sprite rendering path.Note that, in that follow-up patch, order to see the changes in action, I had to change
bevymarkto avoid using the same seed for all its parallel RNGs. Without that change, the fact that each RNG uses the same seed means that each texture effectively gets its own Z layer, causing the benchmark to degenerate into the optimal scenario for batching in the non-bindless case. The follow-up PR scrambles the RNG seeds to avoid this pathological, unrealistic behavior.