Skip to content

Commit 656c082

Browse files
Implement batched query support
PR bevyengine#6161 Issue bevyengine#1990 * Only Dense queries are accelerated currently * Code refactored to use GATs * Batch type does not encode alignment as per discussion * Simplified calling for_each_{mut_}batched (no longer need _ arguments) * Documentation about SIMD and batching
1 parent 2938792 commit 656c082

File tree

16 files changed

+1252
-43
lines changed

16 files changed

+1252
-43
lines changed

crates/bevy_ecs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ serde = { version = "1", features = ["derive"] }
3030

3131
[dev-dependencies]
3232
rand = "0.8"
33+
bevy_math = { path = "../bevy_math", version = "0.9.0-dev" }
3334

3435
[[example]]
3536
name = "events"

crates/bevy_ecs/src/archetype.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ use crate::{
2323
bundle::BundleId,
2424
component::{ComponentId, StorageType},
2525
entity::{Entity, EntityLocation},
26-
storage::{ImmutableSparseSet, SparseArray, SparseSet, SparseSetIndex, TableId, TableRow},
26+
storage::{
27+
aligned_vec::SimdAlignedVec, ImmutableSparseSet, SparseArray, SparseSet, SparseSetIndex,
28+
TableId, TableRow,
29+
},
2730
};
2831
use std::{
2932
collections::HashMap,
@@ -295,7 +298,7 @@ pub struct Archetype {
295298
id: ArchetypeId,
296299
table_id: TableId,
297300
edges: Edges,
298-
entities: Vec<ArchetypeEntity>,
301+
entities: SimdAlignedVec<ArchetypeEntity>,
299302
components: ImmutableSparseSet<ComponentId, ArchetypeComponentInfo>,
300303
}
301304

@@ -331,7 +334,7 @@ impl Archetype {
331334
Self {
332335
id,
333336
table_id,
334-
entities: Vec::new(),
337+
entities: SimdAlignedVec::new(),
335338
components: components.into_immutable(),
336339
edges: Default::default(),
337340
}

crates/bevy_ecs/src/change_detection.rs

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
33
use crate::{
44
component::{Tick, TickCells},
5-
ptr::PtrMut,
5+
ptr::{Batch, PtrMut, UnsafeCellDeref},
66
system::Resource,
77
};
8-
use bevy_ptr::UnsafeCellDeref;
8+
use core::marker::PhantomData;
99
use std::ops::{Deref, DerefMut};
1010

1111
/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
@@ -283,6 +283,12 @@ impl<'a> Ticks<'a> {
283283
}
284284
}
285285
}
286+
pub(crate) struct TicksBatch<'a, const N: usize> {
287+
pub(crate) added_ticks: &'a mut Batch<Tick, N>,
288+
pub(crate) changed_ticks: &'a mut Batch<Tick, N>,
289+
pub(crate) last_change_tick: u32,
290+
pub(crate) change_tick: u32,
291+
}
286292

287293
/// Unique mutable borrow of a [`Resource`].
288294
///
@@ -407,6 +413,118 @@ change_detection_impl!(Mut<'a, T>, T,);
407413
impl_methods!(Mut<'a, T>, T,);
408414
impl_debug!(Mut<'a, T>,);
409415

416+
/// Unique mutable borrow of an entity's component (batched version).
417+
/// Each batch changes in unison: a batch has changed if any of its elements have changed.
418+
pub struct MutBatch<'a, T, const N: usize> {
419+
pub(crate) value: &'a mut Batch<T, N>,
420+
pub(crate) ticks: TicksBatch<'a, N>,
421+
pub(crate) _marker: PhantomData<T>,
422+
}
423+
424+
impl<'a, T, const N: usize> DetectChanges for MutBatch<'a, T, N> {
425+
#[inline]
426+
fn is_added(&self) -> bool {
427+
self.ticks
428+
.added_ticks
429+
.iter()
430+
.any(|x| x.is_older_than(self.ticks.last_change_tick, self.ticks.change_tick))
431+
}
432+
433+
#[inline]
434+
fn is_changed(&self) -> bool {
435+
self.ticks
436+
.changed_ticks
437+
.iter()
438+
.any(|x| x.is_older_than(self.ticks.last_change_tick, self.ticks.change_tick))
439+
}
440+
441+
#[inline]
442+
fn set_changed(&mut self) {
443+
for ticks in self.ticks.changed_ticks.iter_mut() {
444+
ticks.set_changed(self.ticks.change_tick);
445+
}
446+
}
447+
448+
#[inline]
449+
fn last_changed(&self) -> u32 {
450+
self.ticks.last_change_tick
451+
}
452+
453+
type Inner = Batch<T, N>;
454+
455+
fn set_last_changed(&mut self, last_change_tick: u32) {
456+
self.ticks.last_change_tick = last_change_tick;
457+
}
458+
459+
fn bypass_change_detection(&mut self) -> &mut Self::Inner {
460+
self.value
461+
}
462+
463+
#[inline]
464+
fn set_if_neq<Target>(&mut self, value: Target)
465+
where
466+
Self: Deref<Target = Target> + DerefMut<Target = Target>,
467+
Target: PartialEq,
468+
{
469+
// This dereference is immutable, so does not trigger change detection
470+
if *<Self as Deref>::deref(self) != value {
471+
// `DerefMut` usage triggers change detection
472+
*<Self as DerefMut>::deref_mut(self) = value;
473+
}
474+
}
475+
}
476+
477+
impl<'a, T, const N: usize> Deref for MutBatch<'a, T, N> {
478+
type Target = Batch<T, N>;
479+
480+
#[inline]
481+
fn deref(&self) -> &Self::Target {
482+
self.value
483+
}
484+
}
485+
486+
impl<'a, T, const N: usize> DerefMut for MutBatch<'a, T, N> {
487+
#[inline]
488+
fn deref_mut(&mut self) -> &mut Self::Target {
489+
self.set_changed();
490+
self.value
491+
}
492+
}
493+
494+
impl<'a, T, const N: usize> AsRef<Batch<T, N>> for MutBatch<'a, T, N> {
495+
#[inline]
496+
fn as_ref(&self) -> &Batch<T, N> {
497+
self.deref()
498+
}
499+
}
500+
501+
impl<'a, T, const N: usize> AsMut<Batch<T, N>> for MutBatch<'a, T, N> {
502+
#[inline]
503+
fn as_mut(&mut self) -> &mut Batch<T, N> {
504+
self.deref_mut()
505+
}
506+
}
507+
508+
impl<'a, T, const N: usize> MutBatch<'a, T, N> {
509+
/// Consume `self` and return a mutable reference to the
510+
/// contained value while marking `self` as "changed".
511+
#[inline]
512+
pub fn into_inner(mut self) -> &'a mut Batch<T, N> {
513+
self.set_changed();
514+
self.value
515+
}
516+
}
517+
518+
impl<'a, T, const N: usize> std::fmt::Debug for MutBatch<'a, T, N>
519+
where
520+
Batch<T, N>: std::fmt::Debug,
521+
T: std::fmt::Debug,
522+
{
523+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
524+
f.debug_tuple(stringify!($name)).field(&self.value).finish()
525+
}
526+
}
527+
410528
/// Unique mutable borrow of resources or an entity's component.
411529
///
412530
/// Similar to [`Mut`], but not generic over the component type, instead

0 commit comments

Comments
 (0)