Skip to content

Commit c0aac3f

Browse files
committed
slotmaps
1 parent cf3f26f commit c0aac3f

File tree

9 files changed

+466
-353
lines changed

9 files changed

+466
-353
lines changed

crates/bevy_ecs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ variadics_please = { version = "1.1", default-features = false }
124124
tracing = { version = "0.1", default-features = false, optional = true }
125125
log = { version = "0.4", default-features = false }
126126
bumpalo = "3"
127+
slotmap = { version = "1.0.7", default-features = false }
127128

128129
concurrent-queue = { version = "2.5.0", default-features = false }
129130
[target.'cfg(not(all(target_has_atomic = "8", target_has_atomic = "16", target_has_atomic = "32", target_has_atomic = "64", target_has_atomic = "ptr")))'.dependencies]

crates/bevy_ecs/src/schedule/auto_insert_apply_deferred.rs

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
22

33
use bevy_platform::collections::HashMap;
44

5-
use crate::system::IntoSystem;
5+
use crate::schedule::SystemSetKey;
66
use crate::world::World;
7+
use crate::{schedule::SystemKey, system::IntoSystem};
78

89
use super::{
910
is_apply_deferred, ApplyDeferred, DiGraph, Direction, NodeId, ReportCycles, ScheduleBuildError,
@@ -37,28 +38,26 @@ impl AutoInsertApplyDeferredPass {
3738
.get(&distance)
3839
.copied()
3940
.or_else(|| {
40-
let node_id = self.add_auto_sync(graph);
41+
let node_id = NodeId::System(self.add_auto_sync(graph));
4142
self.auto_sync_node_ids.insert(distance, node_id);
4243
Some(node_id)
4344
})
4445
.unwrap()
4546
}
4647
/// add an [`ApplyDeferred`] system with no config
47-
fn add_auto_sync(&mut self, graph: &mut ScheduleGraph) -> NodeId {
48-
let id = NodeId::System(graph.systems.len());
49-
50-
graph
48+
fn add_auto_sync(&mut self, graph: &mut ScheduleGraph) -> SystemKey {
49+
let key = graph
5150
.systems
52-
.push(SystemNode::new(Box::new(IntoSystem::into_system(
51+
.insert(SystemNode::new(Box::new(IntoSystem::into_system(
5352
ApplyDeferred,
5453
))));
55-
graph.system_conditions.push(Vec::new());
54+
graph.system_conditions.insert(key, Vec::new());
5655

5756
// ignore ambiguities with auto sync points
5857
// They aren't under user control, so no one should know or care.
59-
graph.ambiguous_with_all.insert(id);
58+
graph.ambiguous_with_all.insert(NodeId::System(key));
6059

61-
id
60+
key
6261
}
6362
}
6463

@@ -80,76 +79,90 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
8079
let mut sync_point_graph = dependency_flattened.clone();
8180
let topo = graph.topsort_graph(dependency_flattened, ReportCycles::Dependency)?;
8281

83-
fn set_has_conditions(graph: &ScheduleGraph, node: NodeId) -> bool {
84-
!graph.set_conditions_at(node).is_empty()
82+
fn set_has_conditions(graph: &ScheduleGraph, set: SystemSetKey) -> bool {
83+
!graph.set_conditions_at(set).is_empty()
8584
|| graph
8685
.hierarchy()
8786
.graph()
88-
.edges_directed(node, Direction::Incoming)
89-
.any(|(parent, _)| set_has_conditions(graph, parent))
87+
.edges_directed(NodeId::Set(set), Direction::Incoming)
88+
.any(|(parent, _)| {
89+
parent
90+
.as_set()
91+
.is_some_and(|p| set_has_conditions(graph, p))
92+
})
9093
}
9194

92-
fn system_has_conditions(graph: &ScheduleGraph, node: NodeId) -> bool {
93-
assert!(node.is_system());
94-
!graph.system_conditions[node.index()].is_empty()
95+
fn system_has_conditions(graph: &ScheduleGraph, key: SystemKey) -> bool {
96+
!graph.system_conditions[key].is_empty()
9597
|| graph
9698
.hierarchy()
9799
.graph()
98-
.edges_directed(node, Direction::Incoming)
99-
.any(|(parent, _)| set_has_conditions(graph, parent))
100+
.edges_directed(NodeId::System(key), Direction::Incoming)
101+
.any(|(parent, _)| {
102+
parent
103+
.as_set()
104+
.is_some_and(|p| set_has_conditions(graph, p))
105+
})
100106
}
101107

102-
let mut system_has_conditions_cache = HashMap::<usize, bool>::default();
103-
let mut is_valid_explicit_sync_point = |system: NodeId| {
104-
let index = system.index();
105-
is_apply_deferred(graph.systems[index].get().unwrap())
108+
let mut system_has_conditions_cache = HashMap::<SystemKey, bool>::default();
109+
let mut is_valid_explicit_sync_point = |key: SystemKey| {
110+
is_apply_deferred(graph.systems[key].get().unwrap())
106111
&& !*system_has_conditions_cache
107-
.entry(index)
108-
.or_insert_with(|| system_has_conditions(graph, system))
112+
.entry(key)
113+
.or_insert_with(|| system_has_conditions(graph, key))
109114
};
110115

111116
// Calculate the distance for each node.
112117
// The "distance" is the number of sync points between a node and the beginning of the graph.
113118
// Also store if a preceding edge would have added a sync point but was ignored to add it at
114119
// a later edge that is not ignored.
115-
let mut distances_and_pending_sync: HashMap<usize, (u32, bool)> =
120+
let mut distances_and_pending_sync: HashMap<SystemKey, (u32, bool)> =
116121
HashMap::with_capacity_and_hasher(topo.len(), Default::default());
117122

118123
// Keep track of any explicit sync nodes for a specific distance.
119124
let mut distance_to_explicit_sync_node: HashMap<u32, NodeId> = HashMap::default();
120125

121126
// Determine the distance for every node and collect the explicit sync points.
122127
for node in &topo {
128+
let &NodeId::System(key) = node else {
129+
continue;
130+
};
131+
123132
let (node_distance, mut node_needs_sync) = distances_and_pending_sync
124-
.get(&node.index())
133+
.get(&key)
125134
.copied()
126135
.unwrap_or_default();
127136

128-
if is_valid_explicit_sync_point(*node) {
137+
if is_valid_explicit_sync_point(key) {
129138
// The distance of this sync point does not change anymore as the iteration order
130139
// makes sure that this node is no unvisited target of another node.
131140
// Because of this, the sync point can be stored for this distance to be reused as
132141
// automatically added sync points later.
133-
distance_to_explicit_sync_node.insert(node_distance, *node);
142+
distance_to_explicit_sync_node.insert(node_distance, NodeId::System(key));
134143

135144
// This node just did a sync, so the only reason to do another sync is if one was
136145
// explicitly scheduled afterwards.
137146
node_needs_sync = false;
138147
} else if !node_needs_sync {
139148
// No previous node has postponed sync points to add so check if the system itself
140149
// has deferred params that require a sync point to apply them.
141-
node_needs_sync = graph.systems[node.index()].get().unwrap().has_deferred();
150+
node_needs_sync = graph.systems[key].get().unwrap().has_deferred();
142151
}
143152

144153
for target in dependency_flattened.neighbors_directed(*node, Direction::Outgoing) {
145-
let (target_distance, target_pending_sync) = distances_and_pending_sync
146-
.entry(target.index())
147-
.or_default();
154+
let NodeId::System(target) = target else {
155+
continue;
156+
};
157+
let (target_distance, target_pending_sync) =
158+
distances_and_pending_sync.entry(target).or_default();
148159

149160
let mut edge_needs_sync = node_needs_sync;
150161
if node_needs_sync
151-
&& !graph.systems[target.index()].get().unwrap().is_exclusive()
152-
&& self.no_sync_edges.contains(&(*node, target))
162+
&& !graph.systems[target].get().unwrap().is_exclusive()
163+
&& self
164+
.no_sync_edges
165+
.contains(&(*node, NodeId::System(target)))
153166
{
154167
// The node has deferred params to apply, but this edge is ignoring sync points.
155168
// Mark the target as 'delaying' those commands to a future edge and the current
@@ -174,14 +187,20 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
174187
// Find any edges which have a different number of sync points between them and make sure
175188
// there is a sync point between them.
176189
for node in &topo {
190+
let &NodeId::System(key) = node else {
191+
continue;
192+
};
177193
let (node_distance, _) = distances_and_pending_sync
178-
.get(&node.index())
194+
.get(&key)
179195
.copied()
180196
.unwrap_or_default();
181197

182198
for target in dependency_flattened.neighbors_directed(*node, Direction::Outgoing) {
199+
let NodeId::System(target) = target else {
200+
continue;
201+
};
183202
let (target_distance, _) = distances_and_pending_sync
184-
.get(&target.index())
203+
.get(&target)
185204
.copied()
186205
.unwrap_or_default();
187206

@@ -190,7 +209,7 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
190209
continue;
191210
}
192211

193-
if is_apply_deferred(graph.systems[target.index()].get().unwrap()) {
212+
if is_apply_deferred(graph.systems[target].get().unwrap()) {
194213
// We don't need to insert a sync point since ApplyDeferred is a sync point
195214
// already!
196215
continue;
@@ -202,10 +221,10 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
202221
.unwrap_or_else(|| self.get_sync_point(graph, target_distance));
203222

204223
sync_point_graph.add_edge(*node, sync_point);
205-
sync_point_graph.add_edge(sync_point, target);
224+
sync_point_graph.add_edge(sync_point, NodeId::System(target));
206225

207226
// The edge without the sync point is now redundant.
208-
sync_point_graph.remove_edge(*node, target);
227+
sync_point_graph.remove_edge(*node, NodeId::System(target));
209228
}
210229
}
211230

@@ -215,34 +234,39 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
215234

216235
fn collapse_set(
217236
&mut self,
218-
set: NodeId,
219-
systems: &[NodeId],
237+
set: SystemSetKey,
238+
systems: &[SystemKey],
220239
dependency_flattened: &DiGraph,
221240
) -> impl Iterator<Item = (NodeId, NodeId)> {
222241
if systems.is_empty() {
223242
// collapse dependencies for empty sets
224-
for a in dependency_flattened.neighbors_directed(set, Direction::Incoming) {
225-
for b in dependency_flattened.neighbors_directed(set, Direction::Outgoing) {
226-
if self.no_sync_edges.contains(&(a, set))
227-
&& self.no_sync_edges.contains(&(set, b))
243+
for a in dependency_flattened.neighbors_directed(NodeId::Set(set), Direction::Incoming)
244+
{
245+
for b in
246+
dependency_flattened.neighbors_directed(NodeId::Set(set), Direction::Outgoing)
247+
{
248+
if self.no_sync_edges.contains(&(a, NodeId::Set(set)))
249+
&& self.no_sync_edges.contains(&(NodeId::Set(set), b))
228250
{
229251
self.no_sync_edges.insert((a, b));
230252
}
231253
}
232254
}
233255
} else {
234-
for a in dependency_flattened.neighbors_directed(set, Direction::Incoming) {
256+
for a in dependency_flattened.neighbors_directed(NodeId::Set(set), Direction::Incoming)
257+
{
235258
for &sys in systems {
236-
if self.no_sync_edges.contains(&(a, set)) {
237-
self.no_sync_edges.insert((a, sys));
259+
if self.no_sync_edges.contains(&(a, NodeId::Set(set))) {
260+
self.no_sync_edges.insert((a, NodeId::System(sys)));
238261
}
239262
}
240263
}
241264

242-
for b in dependency_flattened.neighbors_directed(set, Direction::Outgoing) {
265+
for b in dependency_flattened.neighbors_directed(NodeId::Set(set), Direction::Outgoing)
266+
{
243267
for &sys in systems {
244-
if self.no_sync_edges.contains(&(set, b)) {
245-
self.no_sync_edges.insert((sys, b));
268+
if self.no_sync_edges.contains(&(NodeId::Set(set), b)) {
269+
self.no_sync_edges.insert((NodeId::System(sys), b));
246270
}
247271
}
248272
}

crates/bevy_ecs/src/schedule/executor/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::{
2020
error::{BevyError, ErrorContext, Result},
2121
prelude::{IntoSystemSet, SystemSet},
2222
query::{Access, FilteredAccessSet},
23-
schedule::{BoxedCondition, InternedSystemSet, NodeId, SystemTypeSet},
23+
schedule::{BoxedCondition, InternedSystemSet, SystemKey, SystemSetKey, SystemTypeSet},
2424
system::{ScheduleSystem, System, SystemIn, SystemParamValidationError},
2525
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
2626
};
@@ -73,7 +73,7 @@ pub enum ExecutorKind {
7373
#[derive(Default)]
7474
pub struct SystemSchedule {
7575
/// List of system node ids.
76-
pub(super) system_ids: Vec<NodeId>,
76+
pub(super) system_ids: Vec<SystemKey>,
7777
/// Indexed by system node id.
7878
pub(super) systems: Vec<ScheduleSystem>,
7979
/// Indexed by system node id.
@@ -96,7 +96,7 @@ pub struct SystemSchedule {
9696
/// List of sets containing the system that have conditions
9797
pub(super) sets_with_conditions_of_systems: Vec<FixedBitSet>,
9898
/// List of system set node ids.
99-
pub(super) set_ids: Vec<NodeId>,
99+
pub(super) set_ids: Vec<SystemSetKey>,
100100
/// Indexed by system set node id.
101101
pub(super) set_conditions: Vec<Vec<BoxedCondition>>,
102102
/// Indexed by system set node id.

0 commit comments

Comments
 (0)