Skip to content

Commit 69db29e

Browse files
pcwaltonsuperdump
andauthored
Sweep bins after queuing so as to only sweep them once. (#17787)
Currently, we *sweep*, or remove entities from bins when those entities became invisible or changed phases, during `queue_material_meshes` and similar phases. This, however, is wrong, because `queue_material_meshes` executes once per material type, not once per phase. This could result in sweeping bins multiple times per phase, which can corrupt the bins. This commit fixes the issue by moving sweeping to a separate system that runs after queuing. This manifested itself as entities appearing and disappearing seemingly at random. Closes #17759. --------- Co-authored-by: Robert Swain <[email protected]>
1 parent a861452 commit 69db29e

File tree

6 files changed

+21
-31
lines changed

6 files changed

+21
-31
lines changed

crates/bevy_pbr/src/material.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,10 +1047,6 @@ pub fn queue_material_meshes<M: Material>(
10471047
}
10481048
}
10491049
}
1050-
1051-
// Remove invalid entities from the bins.
1052-
opaque_phase.sweep_old_entities();
1053-
alpha_mask_phase.sweep_old_entities();
10541050
}
10551051
}
10561052

crates/bevy_pbr/src/prepass/mod.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,20 +1229,6 @@ pub fn queue_prepass_material_meshes<M: Material>(
12291229
_ => {}
12301230
}
12311231
}
1232-
1233-
// Remove invalid entities from the bins.
1234-
if let Some(phase) = opaque_phase {
1235-
phase.sweep_old_entities();
1236-
}
1237-
if let Some(phase) = alpha_mask_phase {
1238-
phase.sweep_old_entities();
1239-
}
1240-
if let Some(phase) = opaque_deferred_phase {
1241-
phase.sweep_old_entities();
1242-
}
1243-
if let Some(phase) = alpha_mask_deferred_phase {
1244-
phase.sweep_old_entities();
1245-
}
12461232
}
12471233
}
12481234

crates/bevy_pbr/src/render/light.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,9 +1953,6 @@ pub fn queue_shadows<M: Material>(
19531953
*current_change_tick,
19541954
);
19551955
}
1956-
1957-
// Remove invalid entities from the bins.
1958-
shadow_phase.sweep_old_entities();
19591956
}
19601957
}
19611958
}

crates/bevy_render/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ pub enum RenderSet {
146146
Queue,
147147
/// A sub-set within [`Queue`](RenderSet::Queue) where mesh entity queue systems are executed. Ensures `prepare_assets::<RenderMesh>` is completed.
148148
QueueMeshes,
149+
/// A sub-set within [`Queue`](RenderSet::Queue) where meshes that have
150+
/// become invisible or changed phases are removed from the bins.
151+
QueueSweep,
149152
// TODO: This could probably be moved in favor of a system ordering
150153
// abstraction in `Render` or `Queue`
151154
/// Sort the [`SortedRenderPhase`](render_phase::SortedRenderPhase)s and
@@ -201,7 +204,8 @@ impl Render {
201204

202205
schedule.configure_sets((ExtractCommands, PrepareAssets, PrepareMeshes, Prepare).chain());
203206
schedule.configure_sets(
204-
QueueMeshes
207+
(QueueMeshes, QueueSweep)
208+
.chain()
205209
.in_set(Queue)
206210
.after(prepare_assets::<RenderMesh>),
207211
);

crates/bevy_render/src/render_phase/mod.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -823,16 +823,14 @@ where
823823
/// Removes all entities not marked as clean from the bins.
824824
///
825825
/// During `queue_material_meshes`, we process all visible entities and mark
826-
/// each as clean as we come to it. Then we call this method, which removes
827-
/// entities that aren't marked as clean from the bins.
826+
/// each as clean as we come to it. Then, in [`sweep_old_entities`], we call
827+
/// this method, which removes entities that aren't marked as clean from the
828+
/// bins.
828829
pub fn sweep_old_entities(&mut self) {
829830
// Search for entities not marked as valid. We have to do this in
830831
// reverse order because `swap_remove_index` will potentially invalidate
831832
// all indices after the one we remove.
832833
for index in ReverseFixedBitSetZeroesIterator::new(&self.valid_cached_entity_bin_keys) {
833-
// If we found an invalid entity, remove it. Note that this
834-
// potentially invalidates later indices, but that's OK because
835-
// we're going in reverse order.
836834
let Some((entity, entity_bin_key)) =
837835
self.cached_entity_bin_keys.swap_remove_index(index)
838836
else {
@@ -1068,6 +1066,7 @@ where
10681066
),
10691067
)
10701068
.in_set(RenderSet::PrepareResources),
1069+
sweep_old_entities::<BPI>.in_set(RenderSet::QueueSweep),
10711070
),
10721071
);
10731072
}
@@ -1605,6 +1604,18 @@ where
16051604
}
16061605
}
16071606

1607+
/// Removes entities that became invisible or changed phases from the bins.
1608+
///
1609+
/// This must run after queuing.
1610+
pub fn sweep_old_entities<BPI>(mut render_phases: ResMut<ViewBinnedRenderPhases<BPI>>)
1611+
where
1612+
BPI: BinnedPhaseItem,
1613+
{
1614+
for phase in render_phases.0.values_mut() {
1615+
phase.sweep_old_entities();
1616+
}
1617+
}
1618+
16081619
impl BinnedRenderPhaseType {
16091620
pub fn mesh(
16101621
batchable: bool,

crates/bevy_sprite/src/mesh2d/material.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -848,10 +848,6 @@ pub fn queue_material2d_meshes<M: Material2d>(
848848
}
849849
}
850850
}
851-
852-
// Remove invalid entities from the bins.
853-
opaque_phase.sweep_old_entities();
854-
alpha_mask_phase.sweep_old_entities();
855851
}
856852
}
857853

0 commit comments

Comments
 (0)