Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
98892ba
basic structure
ElliottjPierce Feb 5, 2025
de042ac
removed dead test
ElliottjPierce Feb 5, 2025
011dd43
added some utils
ElliottjPierce Feb 5, 2025
b151538
scoping functions
ElliottjPierce Feb 5, 2025
57f2500
removed maybe locked
ElliottjPierce Feb 5, 2025
4001876
dedupe code
ElliottjPierce Feb 5, 2025
024b1e1
locked scope
ElliottjPierce Feb 5, 2025
4574bd2
clone for ref
ElliottjPierce Feb 5, 2025
33374f3
Arcs
ElliottjPierce Feb 5, 2025
068cc8d
generalized stage locking
ElliottjPierce Feb 6, 2025
1ad1c4a
Separate atomic operations
ElliottjPierce Feb 6, 2025
92b5c79
rename
ElliottjPierce Feb 6, 2025
b2e89de
redid with a focus on non-atomic
ElliottjPierce Feb 6, 2025
dc0fccf
implemented atomic stage on write
ElliottjPierce Feb 6, 2025
b2a0855
docs pass
ElliottjPierce Feb 6, 2025
b6d1a24
constructors
ElliottjPierce Feb 6, 2025
1952035
more docs
ElliottjPierce Feb 6, 2025
a452de0
basic test example
ElliottjPierce Feb 6, 2025
7bd0695
deadlocking warnings
ElliottjPierce Feb 6, 2025
5fa5d58
module docs
ElliottjPierce Feb 6, 2025
296ed03
rename to just staging
ElliottjPierce Feb 6, 2025
026c0ea
fixed no_std hopefully
ElliottjPierce Feb 6, 2025
364165c
moved to platform_support
ElliottjPierce Feb 6, 2025
b3267db
More granular alloc feature cfgs
ElliottjPierce Feb 6, 2025
6d45061
More great suggestions from bushrat
ElliottjPierce Feb 6, 2025
94d0655
cleaned up from review
ElliottjPierce Feb 6, 2025
885014c
tiny docs clarification
ElliottjPierce Feb 6, 2025
c96660a
Clear poison instead of crashing
ElliottjPierce Feb 6, 2025
9e48a80
moved back to bevy_utils lol
ElliottjPierce Feb 6, 2025
1794045
mostly working example
ElliottjPierce Feb 6, 2025
7be807c
finished example
ElliottjPierce Feb 6, 2025
0d2990a
better docs
ElliottjPierce Feb 6, 2025
18c4ab2
fixed docs
ElliottjPierce Feb 6, 2025
3660a57
implemented StagableWritesCore
ElliottjPierce Feb 6, 2025
08cba28
finished StagableWritesCore
ElliottjPierce Feb 6, 2025
34160b4
Alert for deadlocks with unsafe
ElliottjPierce Feb 6, 2025
472b1c2
improved deadlock prevention
ElliottjPierce Feb 6, 2025
2e50c5f
impl StagableWrites
ElliottjPierce Feb 6, 2025
10c1857
use RefStageOnWrite internally
ElliottjPierce Feb 6, 2025
0576c69
fixed docs
ElliottjPierce Feb 6, 2025
69b7ca8
docs pass
ElliottjPierce Feb 7, 2025
fd858d5
module level docs
ElliottjPierce Feb 7, 2025
23f2f71
default for arc
ElliottjPierce Feb 7, 2025
acba828
clean up and polish
ElliottjPierce Feb 7, 2025
944bafe
fixed docs
ElliottjPierce Feb 7, 2025
66017c6
Reding Trait
ElliottjPierce Feb 14, 2025
c1ae8df
implemented reading
ElliottjPierce Feb 15, 2025
c6566bb
flatten component clone handlers
ElliottjPierce Feb 15, 2025
264011b
ComponentsWriter
ElliottjPierce Feb 15, 2025
4071826
staging
ElliottjPierce Feb 15, 2025
040c856
StagedRef implemented
ElliottjPierce Feb 15, 2025
baf8903
implemented reader for stager
ElliottjPierce Feb 15, 2025
95c6c22
more traits
ElliottjPierce Feb 15, 2025
975d011
basic trait impls
ElliottjPierce Feb 15, 2025
5a0e0b7
finalized traits
ElliottjPierce Feb 15, 2025
78ff25e
moved component impl to traits
ElliottjPierce Feb 15, 2025
76f3c05
Merge branch 'main' into staged-components
ElliottjPierce Feb 15, 2025
ee06622
completed merge
ElliottjPierce Feb 15, 2025
ed83baa
Merge branch 'main' into staged-components
ElliottjPierce Feb 15, 2025
193a6b2
small changes for ci
ElliottjPierce Feb 15, 2025
1c271ab
fixed docs
ElliottjPierce Feb 15, 2025
6c1773d
inline register_inherited_required_components
ElliottjPierce Feb 15, 2025
3962927
better doc refs
ElliottjPierce Feb 15, 2025
54da184
staging required components
ElliottjPierce Feb 15, 2025
357d21f
impl ComponentsInternalReader for Stager
ElliottjPierce Feb 15, 2025
9e9b61e
fully implemented stager
ElliottjPierce Feb 16, 2025
62d41e2
registration benchmarks
ElliottjPierce Feb 16, 2025
be6638d
fixed an important bug
ElliottjPierce Feb 16, 2025
fc6df4a
fixed the bug for real
ElliottjPierce Feb 16, 2025
086cf80
Merge branch 'main' into staged-components
ElliottjPierce Feb 17, 2025
55c2dff
cleaned up merge
ElliottjPierce Feb 17, 2025
a751574
removed ComponentInfo::required_components
ElliottjPierce Feb 21, 2025
5ede1e8
removed derefByLifetime
ElliottjPierce Feb 21, 2025
bedea0b
fixed docs
ElliottjPierce Feb 21, 2025
fe23d37
removed unneeded changes to deferred_world
ElliottjPierce Feb 24, 2025
76df23a
cleaned up unneeded changes to ComponentCloneBehavior
ElliottjPierce Feb 24, 2025
501e0ac
Unified ComponentsInternalReader with ComponentsReader
ElliottjPierce Feb 24, 2025
9b3c58e
Made migration easier.
ElliottjPierce Feb 24, 2025
f51ef92
small rename to future-proof
ElliottjPierce Feb 24, 2025
583526e
fixed docs
ElliottjPierce Feb 24, 2025
722fa3c
Update crates/bevy_utils/src/staging.rs
ElliottjPierce Feb 25, 2025
8aa1f1f
Merge branch 'main' into staged-components
ElliottjPierce Feb 25, 2025
40432eb
Merge branch 'main' into staged-components
ElliottjPierce Feb 26, 2025
025b1b4
remove un-needed bound
ElliottjPierce Feb 26, 2025
ea59cb1
Quick renames per review
ElliottjPierce Mar 2, 2025
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
2 changes: 2 additions & 0 deletions benches/benches/bevy_ecs/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod add_remove_very_big_table;
mod archetype_updates;
mod insert_simple;
mod insert_simple_unbatched;
mod registration;

use archetype_updates::*;
use criterion::{criterion_group, Criterion};
Expand All @@ -19,6 +20,7 @@ criterion_group!(
insert_simple,
no_archetypes,
added_archetypes,
registration::bench_registration,
);

fn add_remove(c: &mut Criterion) {
Expand Down
250 changes: 250 additions & 0 deletions benches/benches/bevy_ecs/components/registration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
use core::hint::black_box;
use std::ops::Deref;

use bevy_ecs::component::{require, Component, Components, ComponentsWriter, StagedComponents};
use bevy_utils::staging::{
ArcStageOnWrite, AtomicStageOnWrite, RefStageOnWrite, StagableWrites, StagableWritesCore,
StageOnWrite,
};
use criterion::Criterion;

#[derive(Component, Default)]
struct ComponentA0;

#[derive(Component, Default)]
struct ComponentA1;

#[derive(Component, Default)]
struct ComponentA2;

#[derive(Component, Default)]
struct ComponentA3;

#[derive(Component, Default)]
struct ComponentA4;

#[derive(Component, Default)]
struct ComponentA5;

#[derive(Component, Default)]
struct ComponentA6;

#[derive(Component, Default)]
struct ComponentA7;

#[derive(Component, Default)]
struct ComponentA8;

#[derive(Component, Default)]
struct ComponentA9;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA2)]
struct ComponentB0;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA3, ComponentA7)]
struct ComponentB1;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA2)]
struct ComponentB2;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA1)]
struct ComponentB3;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA1)]
struct ComponentB4;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA1, ComponentA8, ComponentA4)]
struct ComponentB5;

#[derive(Component, Default)]
#[require(ComponentA0, ComponentA1, ComponentA6)]
struct ComponentB6;

#[derive(Component, Default)]
struct ComponentB7;

#[derive(Component, Default)]
struct ComponentB8;

#[derive(Component, Default)]
struct ComponentB9;

#[derive(Component, Default)]
struct ComponentC0;

#[derive(Component, Default)]
struct ComponentC1;

#[derive(Component, Default)]
#[require(ComponentB1)]
struct ComponentC2;

#[derive(Component, Default)]
#[require(ComponentB1)]
struct ComponentC3;

#[derive(Component, Default)]
#[require(ComponentB1, ComponentB2, ComponentB3, ComponentB4)]
struct ComponentC4;

#[derive(Component, Default)]
#[require(ComponentB1, ComponentB2, ComponentB4)]
struct ComponentC5;

#[derive(Component, Default)]
#[require(ComponentB1, ComponentB9, ComponentB3)]
struct ComponentC6;

#[derive(Component, Default)]
#[require(ComponentB1, ComponentB8, ComponentB4)]
struct ComponentC7;

#[derive(Component, Default)]
#[require(ComponentB1, ComponentB2, ComponentB6)]
struct ComponentC8;

#[derive(Component, Default)]
#[require(ComponentB1, ComponentB5, ComponentB8)]
struct ComponentC9;

fn register_direct(components: &mut impl ComponentsWriter) {
components.register_component::<ComponentA0>();
components.register_component::<ComponentA1>();
components.register_component::<ComponentA2>();
components.register_component::<ComponentA3>();
components.register_component::<ComponentA4>();
components.register_component::<ComponentA5>();
components.register_component::<ComponentA6>();
components.register_component::<ComponentA7>();
components.register_component::<ComponentA8>();
components.register_component::<ComponentA9>();
components.register_component::<ComponentB0>();
components.register_component::<ComponentB1>();
components.register_component::<ComponentB2>();
components.register_component::<ComponentB3>();
components.register_component::<ComponentB4>();
components.register_component::<ComponentB5>();
components.register_component::<ComponentB6>();
components.register_component::<ComponentB7>();
components.register_component::<ComponentB8>();
components.register_component::<ComponentB9>();
components.register_component::<ComponentC0>();
components.register_component::<ComponentC1>();
components.register_component::<ComponentC2>();
components.register_component::<ComponentC3>();
components.register_component::<ComponentC4>();
components.register_component::<ComponentC5>();
components.register_component::<ComponentC6>();
components.register_component::<ComponentC7>();
components.register_component::<ComponentC8>();
components.register_component::<ComponentC9>();
}

fn register_synced(
mut components: impl StagableWrites<Core: StagableWritesCore<Staging = StagedComponents>>,
) {
components.stage_scope_locked(|stager| stager.register_component::<ComponentA0>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA1>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA2>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA3>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA4>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA5>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA6>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA7>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA8>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentA9>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB0>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB1>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB2>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB3>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB4>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB5>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB6>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB7>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB8>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentB9>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC0>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC1>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC2>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC3>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC4>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC5>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC6>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC7>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC8>());
components.stage_scope_locked(|stager| stager.register_component::<ComponentC9>());
}

pub fn bench_registration(c: &mut Criterion) {
let mut group = c.benchmark_group("registration");
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
group.bench_function("Components directly", |b| {
b.iter(move || {
let mut components = black_box(Components::default());
register_direct(&mut components);
});
});
group.bench_function("StageOnWrite stage", |b| {
b.iter(move || {
let mut components = black_box(StageOnWrite::<StagedComponents>::default());
register_direct(&mut components.stage());
components.apply_staged_for_full();
});
});
group.bench_function("AtomicStageOnWrite stage", |b| {
b.iter(move || {
let mut components = black_box(AtomicStageOnWrite::<StagedComponents>::default());
register_direct(&mut components.stage());
components.apply_staged_for_full();
});
});
group.bench_function("StageOnWrite lock", |b| {
b.iter(move || {
let mut components = black_box(StageOnWrite::<StagedComponents>::default());
register_direct(&mut RefStageOnWrite(&components).stage_lock().as_stager());
components.apply_staged_for_full();
});
});
group.bench_function("AtomicStageOnWrite lock", |b| {
b.iter(move || {
let mut components = black_box(AtomicStageOnWrite::<StagedComponents>::default());
register_direct(&mut RefStageOnWrite(&components).stage_lock().as_stager());
components.apply_staged_for_full();
});
});
group.bench_function("ArcStageOnWrite lock eager", |b| {
b.iter(move || {
let mut components = black_box(ArcStageOnWrite::<StagedComponents>::default());
components.stage_scope_locked_eager(|stager| register_direct(stager));
});
});
group.bench_function("StageOnWrite sync", |b| {
b.iter(move || {
let mut components = black_box(StageOnWrite::<StagedComponents>::default());
register_synced(RefStageOnWrite(&components));
components.apply_staged_for_full();
});
});
group.bench_function("AtomicStageOnWrite sync", |b| {
b.iter(move || {
let mut components = black_box(AtomicStageOnWrite::<StagedComponents>::default());
register_synced(RefStageOnWrite(&components));
components.apply_staged_for_full();
});
});
group.bench_function("ArcStageOnWrite sync eager", |b| {
b.iter(move || {
let components = black_box(ArcStageOnWrite::<StagedComponents>::default());
register_synced(RefStageOnWrite(components.0.deref()));
components.apply_staged_non_blocking();
});
});
group.finish();
}
2 changes: 1 addition & 1 deletion crates/bevy_asset/src/asset_changed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! and triggers whenever the handle or the underlying asset changes.

use crate::{AsAssetId, Asset, AssetId};
use bevy_ecs::component::Components;
use bevy_ecs::component::{Components, ComponentsReader};
use bevy_ecs::{
archetype::Archetype,
component::{ComponentId, Tick},
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/macros/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
type Mutability = #mutable_type;
fn register_required_components(
requiree: #bevy_ecs_path::component::ComponentId,
components: &mut #bevy_ecs_path::component::Components,
components: &mut impl #bevy_ecs_path::component::ComponentsWriter,
required_components: &mut #bevy_ecs_path::component::RequiredComponents,
inheritance_depth: u16,
recursion_check_stack: &mut #bevy_ecs_path::__macro_exports::Vec<#bevy_ecs_path::component::ComponentId>
Expand Down
4 changes: 3 additions & 1 deletion crates/bevy_ecs/src/archetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

use crate::{
bundle::BundleId,
component::{ComponentId, Components, RequiredComponentConstructor, StorageType},
component::{
ComponentId, Components, ComponentsReader, RequiredComponentConstructor, StorageType,
},
entity::{Entity, EntityLocation},
observer::Observers,
storage::{ImmutableSparseSet, SparseArray, SparseSet, SparseSetIndex, TableId, TableRow},
Expand Down
20 changes: 13 additions & 7 deletions crates/bevy_ecs/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use crate::{
},
change_detection::MaybeLocation,
component::{
Component, ComponentId, Components, RequiredComponentConstructor, RequiredComponents,
StorageType, Tick,
Component, ComponentId, Components, ComponentsReader, ComponentsWriter,
RequiredComponentConstructor, RequiredComponents, StorageType, Tick,
},
entity::{Entities, Entity, EntityLocation},
observer::Observers,
Expand All @@ -30,7 +30,7 @@ use variadics_please::all_tuples;

/// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity.
///
/// Implementors of the `Bundle` trait are called 'bundles'.
/// Implementers of the `Bundle` trait are called 'bundles'.
///
/// Each bundle represents a static set of [`Component`] types.
/// Currently, bundles can only contain one of each [`Component`], and will
Expand Down Expand Up @@ -71,7 +71,7 @@ use variadics_please::all_tuples;
/// That is, if the entity does not have all the components of the bundle, those
/// which are present will be removed.
///
/// # Implementors
/// # Implementers
///
/// Every type which implements [`Component`] also implements `Bundle`, since
/// [`Component`] types can be added to or removed from an entity.
Expand Down Expand Up @@ -508,9 +508,15 @@ impl BundleInfo {
let mut required_components = RequiredComponents::default();
for component_id in component_ids.iter().copied() {
// SAFETY: caller has verified that all ids are valid
let info = unsafe { components.get_info_unchecked(component_id) };
required_components.merge(info.required_components());
let info = unsafe { &components.get_info_unchecked(component_id) };
storages.prepare_component(info);
// SAFETY: caller has verified that all ids are valid
let required = unsafe {
&components
.get_required_components(component_id)
.debug_checked_unwrap()
};
required.merge_into(&mut required_components);
}
required_components.remove_explicit_components(&component_ids);

Expand All @@ -520,7 +526,7 @@ impl BundleInfo {
.into_iter()
.map(|(component_id, v)| {
// Safety: These ids came out of the passed `components`, so they must be valid.
let info = unsafe { components.get_info_unchecked(component_id) };
let info = unsafe { &components.get_info_unchecked(component_id) };
storages.prepare_component(info);
// This adds required components to the component_ids list _after_ using that list to remove explicitly provided
// components. This ordering is important!
Expand Down
Loading