Skip to content

Commit cc6e5ab

Browse files
Implement batched query support
* Only Dense queries are accelerated currently * Certain features are awaiting on GATs/generic const expressions * Code refactored to use GATs * `elain` crate now used to provide const generic alignments (PhantomData method) * Code still requires a fixed alignment request across whole query (in progress) * Batches support AsRef, AsMut, etc * Simplified calling for_each_{mut_}batched (no longer need _ arguments) * Add convenience functions for treating AlignedBatch16<f32, 4> as Vec4s * Add a map API for creating projections of aligned batches * Add a compile-time error in case a greater alignment is needed than the current batch alignment to satisfy T * Documentation about SIMD and batching * ALIGN now referred to as MIN_ALIGN for clarity
1 parent 02fbf16 commit cc6e5ab

18 files changed

+1738
-68
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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
bundle::BundleId,
66
component::{ComponentId, StorageType},
77
entity::{Entity, EntityLocation},
8-
storage::{SparseArray, SparseSet, SparseSetIndex, TableId},
8+
storage::{aligned_vec::SimdAlignedVec, SparseArray, SparseSet, SparseSetIndex, TableId},
99
};
1010
use std::{
1111
collections::HashMap,
@@ -181,7 +181,7 @@ pub struct Archetype {
181181
id: ArchetypeId,
182182
table_id: TableId,
183183
edges: Edges,
184-
entities: Vec<ArchetypeEntity>,
184+
entities: SimdAlignedVec<ArchetypeEntity>,
185185
table_components: Box<[ComponentId]>,
186186
sparse_set_components: Box<[ComponentId]>,
187187
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
@@ -225,7 +225,7 @@ impl Archetype {
225225
Self {
226226
id,
227227
table_id,
228-
entities: Vec::new(),
228+
entities: SimdAlignedVec::new(),
229229
components,
230230
table_components,
231231
sparse_set_components,

crates/bevy_ecs/src/change_detection.rs

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
//! Types that detect when their internal data mutate.
22
3+
use crate::ptr::{
4+
batch::AlignedBatch,
5+
elain::{Align, Alignment},
6+
};
7+
38
use crate::{component::ComponentTicks, ptr::PtrMut, system::Resource};
4-
use std::ops::{Deref, DerefMut};
9+
use std::{
10+
marker::PhantomData,
11+
ops::{Deref, DerefMut},
12+
};
513

614
/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
715
///
@@ -229,6 +237,15 @@ pub(crate) struct Ticks<'a> {
229237
pub(crate) change_tick: u32,
230238
}
231239

240+
pub(crate) struct TicksBatch<'a, const N: usize, const MIN_ALIGN: usize>
241+
where
242+
Align<MIN_ALIGN>: Alignment,
243+
{
244+
pub(crate) component_ticks: &'a mut AlignedBatch<ComponentTicks, N, MIN_ALIGN>,
245+
pub(crate) last_change_tick: u32,
246+
pub(crate) change_tick: u32,
247+
}
248+
232249
/// Unique mutable borrow of a [`Resource`].
233250
///
234251
/// See the [`Resource`] documentation for usage.
@@ -352,6 +369,132 @@ change_detection_impl!(Mut<'a, T>, T,);
352369
impl_methods!(Mut<'a, T>, T,);
353370
impl_debug!(Mut<'a, T>,);
354371

372+
/// Unique mutable borrow of an entity's component (batched version).
373+
/// Each batch changes in unison: a batch has changed if any of its elements have changed.
374+
pub struct MutBatch<'a, T, const N: usize, const MIN_ALIGN: usize>
375+
where
376+
Align<MIN_ALIGN>: Alignment,
377+
{
378+
pub(crate) value: &'a mut AlignedBatch<T, N, MIN_ALIGN>,
379+
pub(crate) ticks: TicksBatch<'a, N, MIN_ALIGN>,
380+
pub(crate) _marker: PhantomData<T>,
381+
}
382+
383+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> DetectChanges for MutBatch<'a, T, N, MIN_ALIGN>
384+
where
385+
Align<MIN_ALIGN>: Alignment,
386+
{
387+
#[inline]
388+
fn is_added(&self) -> bool {
389+
self.ticks
390+
.component_ticks
391+
.as_array()
392+
.iter()
393+
.any(|x| x.is_added(self.ticks.last_change_tick, self.ticks.change_tick))
394+
}
395+
396+
#[inline]
397+
fn is_changed(&self) -> bool {
398+
self.ticks
399+
.component_ticks
400+
.as_array()
401+
.iter()
402+
.any(|x| x.is_changed(self.ticks.last_change_tick, self.ticks.change_tick))
403+
}
404+
405+
#[inline]
406+
fn set_changed(&mut self) {
407+
for ticks in self.ticks.component_ticks.as_array_mut().iter_mut() {
408+
ticks.set_changed(self.ticks.change_tick);
409+
}
410+
}
411+
412+
#[inline]
413+
fn last_changed(&self) -> u32 {
414+
self.ticks.last_change_tick
415+
}
416+
417+
type Inner = AlignedBatch<T, N, MIN_ALIGN>;
418+
419+
fn set_last_changed(&mut self, last_change_tick: u32) {
420+
self.ticks.last_change_tick = last_change_tick;
421+
}
422+
423+
fn bypass_change_detection(&mut self) -> &mut Self::Inner {
424+
self.value
425+
}
426+
}
427+
428+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> Deref for MutBatch<'a, T, N, MIN_ALIGN>
429+
where
430+
Align<MIN_ALIGN>: Alignment,
431+
{
432+
type Target = AlignedBatch<T, N, MIN_ALIGN>;
433+
434+
#[inline]
435+
fn deref(&self) -> &Self::Target {
436+
self.value
437+
}
438+
}
439+
440+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> DerefMut for MutBatch<'a, T, N, MIN_ALIGN>
441+
where
442+
Align<MIN_ALIGN>: Alignment,
443+
{
444+
#[inline]
445+
fn deref_mut(&mut self) -> &mut Self::Target {
446+
self.set_changed();
447+
self.value
448+
}
449+
}
450+
451+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> AsRef<AlignedBatch<T, N, MIN_ALIGN>>
452+
for MutBatch<'a, T, N, MIN_ALIGN>
453+
where
454+
Align<MIN_ALIGN>: Alignment,
455+
{
456+
#[inline]
457+
fn as_ref(&self) -> &AlignedBatch<T, N, MIN_ALIGN> {
458+
self.deref()
459+
}
460+
}
461+
462+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> AsMut<AlignedBatch<T, N, MIN_ALIGN>>
463+
for MutBatch<'a, T, N, MIN_ALIGN>
464+
where
465+
Align<MIN_ALIGN>: Alignment,
466+
{
467+
#[inline]
468+
fn as_mut(&mut self) -> &mut AlignedBatch<T, N, MIN_ALIGN> {
469+
self.deref_mut()
470+
}
471+
}
472+
473+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> MutBatch<'a, T, N, MIN_ALIGN>
474+
where
475+
Align<MIN_ALIGN>: Alignment,
476+
{
477+
/// Consume `self` and return a mutable reference to the
478+
/// contained value while marking `self` as "changed".
479+
#[inline]
480+
pub fn into_inner(mut self) -> &'a mut AlignedBatch<T, N, MIN_ALIGN> {
481+
self.set_changed();
482+
self.value
483+
}
484+
}
485+
486+
impl<'a, T, const N: usize, const MIN_ALIGN: usize> std::fmt::Debug
487+
for MutBatch<'a, T, N, MIN_ALIGN>
488+
where
489+
Align<MIN_ALIGN>: Alignment,
490+
AlignedBatch<T, N, MIN_ALIGN>: std::fmt::Debug,
491+
T: std::fmt::Debug,
492+
{
493+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
494+
f.debug_tuple(stringify!($name)).field(&self.value).finish()
495+
}
496+
}
497+
355498
/// Unique mutable borrow of resources or an entity's component.
356499
///
357500
/// Similar to [`Mut`], but not generic over the component type, instead

0 commit comments

Comments
 (0)