bevy/assets
Patrick Walton 28441337bb
Use global binding arrays for bindless resources. (#17898)
Currently, Bevy's implementation of bindless resources is rather
unusual: every binding in an object that implements `AsBindGroup` (most
commonly, a material) becomes its own separate binding array in the
shader. This is inefficient for two reasons:

1. If multiple materials reference the same texture or other resource,
the reference to that resource will be duplicated many times. This
increases `wgpu` validation overhead.

2. It creates many unused binding array slots. This increases `wgpu` and
driver overhead and makes it easier to hit limits on APIs that `wgpu`
currently imposes tight resource limits on, like Metal.

This PR fixes these issues by switching Bevy to use the standard
approach in GPU-driven renderers, in which resources are de-duplicated
and passed as global arrays, one for each type of resource.

Along the way, this patch introduces per-platform resource limits and
bumps them from 16 resources per binding array to 64 resources per bind
group on Metal and 2048 resources per bind group on other platforms.
(Note that the number of resources per *binding array* isn't the same as
the number of resources per *bind group*; as it currently stands, if all
the PBR features are turned on, Bevy could pack as many as 496 resources
into a single slab.) The limits have been increased because `wgpu` now
has universal support for partially-bound binding arrays, which mean
that we no longer need to fill the binding arrays with fallback
resources on Direct3D 12. The `#[bindless(LIMIT)]` declaration when
deriving `AsBindGroup` can now simply be written `#[bindless]` in order
to have Bevy choose a default limit size for the current platform.
Custom limits are still available with the new
`#[bindless(limit(LIMIT))]` syntax: e.g. `#[bindless(limit(8))]`.

The material bind group allocator has been completely rewritten. Now
there are two allocators: one for bindless materials and one for
non-bindless materials. The new non-bindless material allocator simply
maintains a 1:1 mapping from material to bind group. The new bindless
material allocator maintains a list of slabs and allocates materials
into slabs on a first-fit basis. This unfortunately makes its
performance O(number of resources per object * number of slabs), but the
number of slabs is likely to be low, and it's planned to become even
lower in the future with `wgpu` improvements. Resources are
de-duplicated with in a slab and reference counted. So, for instance, if
multiple materials refer to the same texture, that texture will exist
only once in the appropriate binding array.

To support these new features, this patch adds the concept of a
*bindless descriptor* to the `AsBindGroup` trait. The bindless
descriptor allows the material bind group allocator to probe the layout
of the material, now that an array of `BindGroupLayoutEntry` records is
insufficient to describe the group. The `#[derive(AsBindGroup)]` has
been heavily modified to support the new features. The most important
user-facing change to that macro is that the struct-level `uniform`
attribute, `#[uniform(BINDING_NUMBER, StandardMaterial)]`, now reads
`#[uniform(BINDLESS_INDEX, MATERIAL_UNIFORM_TYPE,
binding_array(BINDING_NUMBER)]`, allowing the material to specify the
binding number for the binding array that holds the uniform data.

To make this patch simpler, I removed support for bindless
`ExtendedMaterial`s, as well as field-level bindless uniform and storage
buffers. I intend to add back support for these as a follow-up. Because
they aren't in any released Bevy version yet, I figured this was OK.

Finally, this patch updates `StandardMaterial` for the new bindless
changes. Generally, code throughout the PBR shaders that looked like
`base_color_texture[slot]` now looks like
`bindless_2d_textures[material_indices[slot].base_color_texture]`.

This patch fixes a system hang that I experienced on the [Caldera test]
when running with `caldera --random-materials --texture-count 100`. The
time per frame is around 19.75 ms, down from 154.2 ms in Bevy 0.14: a
7.8× speedup.

[Caldera test]: https://github.com/DGriffin91/bevy_caldera_scene
2025-02-21 05:55:36 +00:00
..
android-res/mipmap-mdpi
animation_graphs Implement additive blending for animation graphs. (#15631) 2024-10-04 22:13:22 +00:00
branding Remove unused namespace declarations (#10965) 2023-12-13 22:29:16 +00:00
cursors/kenney_crosshairPack Support texture atlases in CustomCursor::Image (#17121) 2025-01-14 22:27:24 +00:00
data Added Support for Extension-less Assets (#10153) 2024-01-31 14:58:08 +00:00
docs
environment_maps Implement percentage-closer soft shadows (PCSS). (#13497) 2024-09-18 18:07:17 +00:00
external Add external assets to .gitignore (#17388) 2025-01-17 01:20:14 +00:00
fonts
irradiance_volumes Implement irradiance volumes. (#10268) 2024-02-06 23:23:20 +00:00
lightmaps Introduce support for mixed lighting by allowing lights to opt out of contributing diffuse light to lightmapped objects. (#16761) 2024-12-16 23:48:33 +00:00
models Fix validation errors in Fox.glb (#17801) 2025-02-11 22:19:24 +00:00
pixel Add example for pixel-perfect grid snapping in 2D (#8112) 2023-12-26 17:15:50 +00:00
scenes Fix error in scene example (#17799) 2025-02-11 22:20:23 +00:00
shaders Use global binding arrays for bindless resources. (#17898) 2025-02-21 05:55:36 +00:00
sounds Programmed soundtrack example (#12774) 2024-03-29 20:32:30 +00:00
textures Add support for specular tints and maps per the KHR_materials_specular glTF extension. (#14069) 2025-01-26 20:38:46 +00:00
volumes Allow fog density texture to be scrolled over time with an offset (#14868) 2024-08-22 19:43:14 +00:00