Reduce material duplication, index static shadow casters and cache controller metadata

This commit is contained in:
chazmm committed 2026-09-09 19:59:49 +01:00
1 parent 10406cb25d
commit 1c62e56fd6
10 files changed
+860 -35

No files matched your search

+9
View File
@@ -1,5 +1,14 @@
# Local Bevy patch
## Bindless material resource reuse
`bevy_pbr/src/material_bind_groups.rs` chooses a fitting slab requiring the fewest
new resource slots instead of first-fit allocation. It prefers already resident
textures, then fuller slabs, while keeping existing allocation/refcount/free logic
and capacity limits. This adds work during material allocation, not each frame.
The game's explicit Vulkan shader probe tests reuse and retirement using real GPU
texture identities. See `docs/cpu-followup-optimizations.md` for scope and limits.
## Conservative occlusion depth pyramid
`bevy_core_pipeline` is vendored from crates.io 0.18.1 with its original licenses.
+15 -12
View File
@@ -815,19 +815,22 @@ impl MaterialBindGroupBindlessAllocator {
/// created, and the material is allocated into it.
fn allocate_unprepared(
&mut self,
mut unprepared_bind_group: UnpreparedBindGroup,
unprepared_bind_group: UnpreparedBindGroup,
) -> MaterialBindingId {
for (slab_index, slab) in self.slabs.iter_mut().enumerate() {
trace!("Trying to allocate in slab {}", slab_index);
match slab.try_allocate(unprepared_bind_group, self.slab_capacity) {
Ok(slot) => {
return MaterialBindingId {
group: MaterialBindGroupIndex(slab_index as u32),
slot,
};
}
Err(bind_group) => unprepared_bind_group = bind_group,
}
// Prefer resources already resident in a slab. First-fit can duplicate a
// texture into an earlier slab even when a later slab already binds it,
// increasing per-pass resource tracking and splitting compatible draws.
// Allocation only: no extra scan is added to rendering steady-state.
let best = self.slabs.iter().enumerate().filter_map(|(index, slab)| {
let candidate = slab.check_allocation(&unprepared_bind_group)?;
let used = slab.allocated_resource_count;
(used == 0 || used + candidate.needed_free_slots <= self.slab_capacity)
.then_some(((candidate.needed_free_slots, core::cmp::Reverse(used)), index))
}).min_by_key(|(score, _)| *score).map(|(_, index)| index);
if let Some(index) = best {
let slot = self.slabs[index].try_allocate(unprepared_bind_group, self.slab_capacity)
.unwrap_or_else(|_| unreachable!("selected slab has sufficient capacity"));
return MaterialBindingId { group: MaterialBindGroupIndex(index as u32), slot };
}
let group = MaterialBindGroupIndex(self.slabs.len() as u32);