Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Main world and Render world Entity space #14988

Closed
wants to merge 67 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
95b7f0b
init
re0312 Jul 6, 2024
17f2bb0
sync
re0312 Jul 7, 2024
35fe01e
cleanup
re0312 Jul 22, 2024
f9bae87
clean
re0312 Jul 22, 2024
34853b2
fix
re0312 Jul 22, 2024
000cef4
Fly
re0312 Jul 22, 2024
2255b21
Merge branch 'main' into retain_world
re0312 Jul 22, 2024
f90c360
fly entity
re0312 Jul 22, 2024
756b082
sync world
re0312 Jul 22, 2024
5b5ef76
ui
re0312 Jul 22, 2024
e15e3a3
lighting
re0312 Jul 22, 2024
e4e0bc0
fix example
re0312 Jul 22, 2024
33cae8d
ui
re0312 Jul 22, 2024
4a58b0e
fix ui
re0312 Jul 22, 2024
3fc2207
fix gizmos
re0312 Jul 22, 2024
f9c8d5a
fix light
re0312 Jul 22, 2024
44d36a4
cleanup
re0312 Jul 22, 2024
9a7d641
Merge branch 'main' into retain_world
re0312 Jul 22, 2024
7989d21
fix cli
re0312 Jul 22, 2024
9485455
fix ui
re0312 Jul 23, 2024
bb3289b
clean
re0312 Jul 23, 2024
39e4f2e
fix cli
re0312 Jul 23, 2024
4b6506e
fix ui_material
re0312 Jul 23, 2024
03a6e09
fix sprite
re0312 Jul 23, 2024
b8b8225
whilelist
re0312 Jul 23, 2024
24212f5
Revert "whilelist"
re0312 Jul 23, 2024
2de636a
address review
re0312 Jul 24, 2024
1fbb76c
Update crates/bevy_render/src/world_sync.rs
re0312 Jul 24, 2024
c25d560
Update crates/bevy_render/src/world_sync.rs
re0312 Jul 24, 2024
457e83f
Update crates/bevy_render/src/world_sync.rs
re0312 Jul 24, 2024
16c1093
Merge branch 'main' into retain_world
re0312 Jul 25, 2024
cba1183
address review
re0312 Jul 25, 2024
2821849
fmt
re0312 Jul 25, 2024
a86dd39
address review
re0312 Jul 25, 2024
8422a48
comment
re0312 Jul 25, 2024
dc5f10f
remove mapping
re0312 Jul 26, 2024
2a6df8d
retain sprite
re0312 Jul 27, 2024
ce2ea36
cache state
re0312 Aug 1, 2024
c1a4fb9
fix cli
re0312 Aug 1, 2024
672778d
fix
re0312 Aug 1, 2024
0eed037
fix point light
re0312 Aug 1, 2024
5a83da4
fix regression
re0312 Aug 9, 2024
ed296f1
fix cli
re0312 Aug 9, 2024
bb8774d
Merge branch 'main' into retain_world
re0312 Aug 9, 2024
94be0cd
fix conflict
re0312 Aug 9, 2024
560ce59
Merge branch 'main' into retain_world
re0312 Aug 9, 2024
ab22138
Merge branch 'main' into retain_world
re0312 Aug 11, 2024
fd36379
Apply suggestions from code review
re0312 Aug 12, 2024
4bdfd60
Merge branch 'main' into retain_world
re0312 Aug 12, 2024
6214e6d
Merge branch 'retain_world' of https://github.com/re0312/bevy into re…
re0312 Aug 12, 2024
67e7a07
fix cli
re0312 Aug 12, 2024
1507437
Merge branch 'main' into retain_world
re0312 Aug 25, 2024
e5254be
fix
re0312 Aug 25, 2024
d9ecccd
Merge branch 'main' into retain_world
re0312 Aug 27, 2024
faf5ef2
fix
re0312 Aug 27, 2024
f127719
to render world
re0312 Aug 27, 2024
c7ba466
SyncRenderWorld
re0312 Aug 27, 2024
23a8bba
extract_component
re0312 Aug 27, 2024
37944a8
document and test
re0312 Aug 28, 2024
1e8601f
fix
re0312 Aug 28, 2024
7167cc0
typo
re0312 Aug 28, 2024
bfad1de
cleanup
re0312 Aug 28, 2024
8d2c81a
rename
re0312 Aug 28, 2024
70b1498
entities
re0312 Aug 30, 2024
a71a572
restore
re0312 Aug 30, 2024
d0eb5b6
clean
re0312 Aug 30, 2024
a54cda6
init
re0312 Aug 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions crates/bevy_app/src/sub_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@ impl SubApp {
Self::default()
}

/// Returns a default, empty [`SubApp`] using an entity alloc mask.
pub fn new_with_entity_alloc_mask(mask: u32) -> Self {
let mut world = World::new_with_entity_alloc_mask(mask);
world.init_resource::<Schedules>();
Self {
world,
plugin_registry: Vec::default(),
plugin_names: HashSet::default(),
plugin_build_depth: 0,
plugins_state: PluginsState::Adding,
update_schedule: None,
extract: None,
}
}

/// This method is a workaround. Each [`SubApp`] can have its own plugins, but [`Plugin`]
/// works on an [`App`] as a whole.
fn run_as_app<F>(&mut self, f: F)
Expand Down
104 changes: 52 additions & 52 deletions crates/bevy_ecs/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ use crate::{
};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::{fmt, hash::Hash, mem, num::NonZeroU32, sync::atomic::Ordering};
use std::{
fmt, hash::Hash, iter::StepBy, mem, num::NonZeroU32, ops::Range, sync::atomic::Ordering,
};

#[cfg(target_has_atomic = "64")]
use std::sync::atomic::AtomicI64 as AtomicIdCursor;
Expand Down Expand Up @@ -453,7 +455,8 @@ pub struct ReserveEntitiesIterator<'a> {
index_iter: std::slice::Iter<'a, u32>,

// New Entity indices to hand out, outside the range of meta.len().
index_range: std::ops::Range<u32>,
index_range: StepBy<Range<u32>>,
mask: u32,
}

impl<'a> Iterator for ReserveEntitiesIterator<'a> {
Expand All @@ -465,7 +468,11 @@ impl<'a> Iterator for ReserveEntitiesIterator<'a> {
.map(|&index| {
Entity::from_raw_and_generation(index, self.meta[index as usize].generation)
})
.or_else(|| self.index_range.next().map(Entity::from_raw))
.or_else(|| {
self.index_range
.next()
.map(|i| Entity::from_raw(i | self.mask))
})
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand All @@ -477,6 +484,10 @@ impl<'a> Iterator for ReserveEntitiesIterator<'a> {
impl<'a> ExactSizeIterator for ReserveEntitiesIterator<'a> {}
impl<'a> core::iter::FusedIterator for ReserveEntitiesIterator<'a> {}

pub const RESERVED_BITS: usize = 1;
pub const ENTITY_ALLOC_STEP: usize = 1 << RESERVED_BITS;
pub const INDEX_HIGH_MASK: u32 = u32::MAX << RESERVED_BITS;

/// A [`World`]'s internal metadata store on all of its entities.
///
/// Contains metadata on:
Expand Down Expand Up @@ -533,6 +544,7 @@ pub struct Entities {
free_cursor: AtomicIdCursor,
/// Stores the number of free entities for [`len`](Entities::len)
len: u32,
mask: u32,
}

impl Entities {
Expand All @@ -542,6 +554,18 @@ impl Entities {
pending: Vec::new(),
free_cursor: AtomicIdCursor::new(0),
len: 0,
mask: 0,
}
}

pub(crate) fn new_with_mask(mask: u32) -> Self {
assert!((mask as usize) < ENTITY_ALLOC_STEP);
Entities {
meta: Vec::new(),
pending: Vec::new(),
free_cursor: AtomicIdCursor::new(0),
len: 0,
mask,
}
}

Expand Down Expand Up @@ -577,7 +601,8 @@ impl Entities {
// to go, yielding `meta.len()+0 .. meta.len()+3`.
let base = self.meta.len() as IdCursor;

let new_id_end = u32::try_from(base - range_start).expect("too many entities");
let new_id_end = u32::try_from(base - (range_start * ENTITY_ALLOC_STEP as i64))
.expect("too many entities");

// `new_id_end` is in range, so no need to check `start`.
let new_id_start = (base - range_end.min(0)) as u32;
Expand All @@ -588,7 +613,8 @@ impl Entities {
ReserveEntitiesIterator {
meta: &self.meta[..],
index_iter: self.pending[freelist_range].iter(),
index_range: new_id_start..new_id_end,
index_range: (new_id_start..new_id_end).step_by(ENTITY_ALLOC_STEP),
mask: self.mask,
}
}

Expand All @@ -608,7 +634,9 @@ impl Entities {
// As `self.free_cursor` goes more and more negative, we return IDs farther
// and farther beyond `meta.len()`.
Entity::from_raw(
u32::try_from(self.meta.len() as IdCursor - n).expect("too many entities"),
u32::try_from(self.meta.len() as IdCursor - (n * ENTITY_ALLOC_STEP as i64))
.expect("too many entities")
| self.mask,
)
}
}
Expand All @@ -631,43 +659,10 @@ impl Entities {
Entity::from_raw_and_generation(index, self.meta[index as usize].generation)
} else {
let index = u32::try_from(self.meta.len()).expect("too many entities");
self.meta.push(EntityMeta::EMPTY);
Entity::from_raw(index)
}
}

/// Allocate a specific entity ID, overwriting its generation.
///
/// Returns the location of the entity currently using the given ID, if any. Location should be
/// written immediately.
pub fn alloc_at(&mut self, entity: Entity) -> Option<EntityLocation> {
self.verify_flushed();

let loc = if entity.index() as usize >= self.meta.len() {
self.pending
.extend((self.meta.len() as u32)..entity.index());
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta
.resize(entity.index() as usize + 1, EntityMeta::EMPTY);
self.len += 1;
None
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.index()) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len += 1;
None
} else {
Some(mem::replace(
&mut self.meta[entity.index() as usize].location,
EntityMeta::EMPTY.location,
))
};

self.meta[entity.index() as usize].generation = entity.generation;

loc
.extend((0..ENTITY_ALLOC_STEP).map(|_| EntityMeta::EMPTY));
Entity::from_raw(index | self.mask)
}
}

/// Allocate a specific entity ID, overwriting its generation.
Expand All @@ -680,12 +675,13 @@ impl Entities {
self.verify_flushed();

let result = if entity.index() as usize >= self.meta.len() {
self.pending
.extend((self.meta.len() as u32)..entity.index());
let padding = (entity.index() + 1).next_multiple_of(ENTITY_ALLOC_STEP as u32);
self.pending.extend(
(self.meta.len() as u32..padding).filter(|v| (v & !INDEX_HIGH_MASK) == self.mask),
);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta
.resize(entity.index() as usize + 1, EntityMeta::EMPTY);
self.meta.resize(padding as usize, EntityMeta::EMPTY);
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.index()) {
Expand Down Expand Up @@ -731,11 +727,13 @@ impl Entities {

let loc = mem::replace(&mut meta.location, EntityMeta::EMPTY.location);

self.pending.push(entity.index());
if entity.index() & !INDEX_HIGH_MASK == self.mask {
self.pending.push(entity.index());

let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len -= 1;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len -= 1;
}
Some(loc)
}

Expand Down Expand Up @@ -834,7 +832,8 @@ impl Entities {
// If this entity was manually created, then free_cursor might be positive
// Returning None handles that case correctly
let num_pending = usize::try_from(-free_cursor).ok()?;
(idu < self.meta.len() + num_pending).then_some(Entity::from_raw(index))
(idu < self.meta.len() + num_pending * ENTITY_ALLOC_STEP)
.then_some(Entity::from_raw(index))
}
}

Expand All @@ -860,7 +859,7 @@ impl Entities {
current_free_cursor as usize
} else {
let old_meta_len = self.meta.len();
let new_meta_len = old_meta_len + -current_free_cursor as usize;
let new_meta_len = old_meta_len + (-current_free_cursor as usize) * ENTITY_ALLOC_STEP;
self.meta.resize(new_meta_len, EntityMeta::EMPTY);
self.len += -current_free_cursor as u32;
for (index, meta) in self.meta.iter_mut().enumerate().skip(old_meta_len) {
Expand Down Expand Up @@ -902,6 +901,7 @@ impl Entities {
pub unsafe fn flush_and_reserve_invalid_assuming_no_entities(&mut self, count: usize) {
let free_cursor = self.free_cursor.get_mut();
*free_cursor = 0;
let count = count.next_multiple_of(ENTITY_ALLOC_STEP);
self.meta.reserve(count);
// SAFETY: The EntityMeta struct only contains integers, and it is valid to have all bytes set to u8::MAX
unsafe {
Expand Down
29 changes: 29 additions & 0 deletions crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,35 @@ impl World {
World::default()
}

/// Creates a new empty [`World`].
///
/// # Panics
///
/// If [`usize::MAX`] [`World`]s have been created.
/// This guarantee allows System Parameters to safely uniquely identify a [`World`],
/// since its [`WorldId`] is unique
pub fn new_with_entity_alloc_mask(mask: u32) -> Self {
let mut world = Self {
id: WorldId::new().expect("More `bevy` `World`s have been created than is supported"),
entities: Entities::new_with_mask(mask),
components: Default::default(),
archetypes: Archetypes::new(),
storages: Default::default(),
bundles: Default::default(),
observers: Observers::default(),
removed_components: Default::default(),
// Default value is `1`, and `last_change_tick`s default to `0`, such that changes
// are detected on first system runs and for direct world queries.
change_tick: AtomicU32::new(1),
last_change_tick: Tick::new(0),
last_check_tick: Tick::new(0),
last_trigger_id: 0,
command_queue: RawCommandQueue::new(),
};
world.bootstrap();
world
}

/// Retrieves this [`World`]'s unique ID
#[inline]
pub fn id(&self) -> WorldId {
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_gizmos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ use bevy_render::{
ShaderType, VertexFormat,
},
renderer::RenderDevice,
world_sync::TemporaryRenderEntity,
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
};

Expand Down Expand Up @@ -452,6 +453,7 @@ fn extract_gizmo_data(
(*handle).clone_weak(),
#[cfg(any(feature = "bevy_pbr", feature = "bevy_sprite"))]
config::GizmoMeshConfig::from(config),
TemporaryRenderEntity,
));
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ impl Plugin for PbrPlugin {
)
.init_resource::<LightMeta>();

render_app.world_mut().observe(add_light_view_entities);
render_app.world_mut().observe(remove_light_view_entities);

let shadow_pass_node = ShadowPassNode::new(render_app.world_mut());
let mut graph = render_app.world_mut().resource_mut::<RenderGraph>();
let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap();
Expand Down
Loading