Skip to content

Commit 966c644

Browse files
mjhostetjoshuajbouw
authored andcommitted
Adjust how ArchetypeAccess tracks mutable & immutable deps (bevyengine#660)
`ArchetypeAccess` was tracking `immutable` and `mutable` separately. This means that checking is_compatible requires three checks: m+m, m+i, i+m. Instead, continue tracking `mutable` accesses, but instead of `immutable` track `immutable | mutable` as another `accessed` bit mask. This drops the comparisons to two (m+a, a+m) and turns out to be what the rest of the code base wants too, unifying various duplicated checks and loops.
1 parent cebfa0b commit 966c644

File tree

2 files changed

+20
-35
lines changed

2 files changed

+20
-35
lines changed

crates/bevy_ecs/src/system/query.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,8 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
4646
if let Some(location) = self.world.get_entity_location(entity) {
4747
if self
4848
.archetype_access
49-
.immutable
49+
.accessed
5050
.contains(location.archetype as usize)
51-
|| self
52-
.archetype_access
53-
.mutable
54-
.contains(location.archetype as usize)
5551
{
5652
// SAFE: we have already checked that the entity/component matches our archetype access. and systems are scheduled to run with safe archetype access
5753
unsafe {
@@ -71,12 +67,8 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
7167
if let Some(location) = self.world.get_entity_location(entity) {
7268
if self
7369
.archetype_access
74-
.immutable
70+
.accessed
7571
.contains(location.archetype as usize)
76-
|| self
77-
.archetype_access
78-
.mutable
79-
.contains(location.archetype as usize)
8072
{
8173
// SAFE: we have already checked that the entity matches our archetype. and systems are scheduled to run with safe archetype access
8274
Ok(unsafe {
@@ -205,11 +197,7 @@ impl<'w, Q: HecsQuery> QueryBorrowChecked<'w, Q> {
205197
);
206198
}
207199

208-
for index in self.archetype_access.immutable.ones() {
209-
Q::Fetch::borrow(&self.archetypes[index]);
210-
}
211-
212-
for index in self.archetype_access.mutable.ones() {
200+
for index in self.archetype_access.accessed.ones() {
213201
Q::Fetch::borrow(&self.archetypes[index]);
214202
}
215203

@@ -224,11 +212,7 @@ impl<'w, Q: HecsQuery> Drop for QueryBorrowChecked<'w, Q> {
224212
#[inline]
225213
fn drop(&mut self) {
226214
if self.borrowed {
227-
for index in self.archetype_access.immutable.ones() {
228-
Q::Fetch::release(&self.archetypes[index]);
229-
}
230-
231-
for index in self.archetype_access.mutable.ones() {
215+
for index in self.archetype_access.accessed.ones() {
232216
Q::Fetch::release(&self.archetypes[index]);
233217
}
234218
}

crates/bevy_ecs/src/system/system.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,19 @@ pub trait System: Send + Sync {
3737
/// Provides information about the archetypes a [System] reads and writes
3838
#[derive(Debug, Default)]
3939
pub struct ArchetypeAccess {
40-
pub immutable: FixedBitSet,
40+
pub accessed: FixedBitSet, // union of both immutable and mutable
4141
pub mutable: FixedBitSet,
4242
}
4343

4444
// credit to Ratysz from the Yaks codebase
4545
impl ArchetypeAccess {
4646
pub fn is_compatible(&self, other: &ArchetypeAccess) -> bool {
47-
self.mutable.is_disjoint(&other.mutable)
48-
&& self.mutable.is_disjoint(&other.immutable)
49-
&& self.immutable.is_disjoint(&other.mutable)
47+
self.mutable.is_disjoint(&other.accessed) && self.accessed.is_disjoint(&other.mutable)
5048
}
5149

5250
pub fn union(&mut self, other: &ArchetypeAccess) {
5351
self.mutable.union_with(&other.mutable);
54-
self.immutable.union_with(&other.immutable);
52+
self.accessed.union_with(&other.accessed);
5553
}
5654

5755
pub fn set_access_for_query<Q>(&mut self, world: &World)
@@ -60,20 +58,23 @@ impl ArchetypeAccess {
6058
{
6159
let iterator = world.archetypes();
6260
let bits = iterator.len();
63-
self.immutable.grow(bits);
61+
self.accessed.grow(bits);
6462
self.mutable.grow(bits);
6563
iterator
6664
.enumerate()
6765
.filter_map(|(index, archetype)| archetype.access::<Q>().map(|access| (index, access)))
6866
.for_each(|(archetype, access)| match access {
69-
Access::Read => self.immutable.set(archetype, true),
70-
Access::Write => self.mutable.set(archetype, true),
67+
Access::Read => self.accessed.set(archetype, true),
68+
Access::Write => {
69+
self.accessed.set(archetype, true);
70+
self.mutable.set(archetype, true);
71+
}
7172
Access::Iterate => (),
7273
});
7374
}
7475

7576
pub fn clear(&mut self) {
76-
self.immutable.clear();
77+
self.accessed.clear();
7778
self.mutable.clear();
7879
}
7980
}
@@ -128,16 +129,16 @@ mod tests {
128129
let e2_archetype = world.get_entity_location(e2).unwrap().archetype as usize;
129130
let e3_archetype = world.get_entity_location(e3).unwrap().archetype as usize;
130131

131-
assert!(access.immutable.contains(e1_archetype));
132-
assert!(access.immutable.contains(e2_archetype));
133-
assert!(access.immutable.contains(e3_archetype));
132+
assert!(access.accessed.contains(e1_archetype));
133+
assert!(access.accessed.contains(e2_archetype));
134+
assert!(access.accessed.contains(e3_archetype));
134135

135136
let mut access = ArchetypeAccess::default();
136137
access.set_access_for_query::<(&A, &B)>(&world);
137138

138-
assert!(access.immutable.contains(e1_archetype) == false);
139-
assert!(access.immutable.contains(e2_archetype));
140-
assert!(access.immutable.contains(e3_archetype));
139+
assert!(access.accessed.contains(e1_archetype) == false);
140+
assert!(access.accessed.contains(e2_archetype));
141+
assert!(access.accessed.contains(e3_archetype));
141142
}
142143

143144
#[test]

0 commit comments

Comments
 (0)