Skip to content

Commit

Permalink
Implement batched query support
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
InBetweenNames committed Nov 7, 2022
1 parent 02fbf16 commit 31ed43c
Show file tree
Hide file tree
Showing 18 changed files with 1,757 additions and 64 deletions.
1 change: 1 addition & 0 deletions crates/bevy_ecs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ serde = { version = "1", features = ["derive"] }

[dev-dependencies]
rand = "0.8"
bevy_math = { path = "../bevy_math", version = "0.9.0-dev" }

[[example]]
name = "events"
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_ecs/src/archetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
bundle::BundleId,
component::{ComponentId, StorageType},
entity::{Entity, EntityLocation},
storage::{SparseArray, SparseSet, SparseSetIndex, TableId},
storage::{aligned_vec::SimdAlignedVec, SparseArray, SparseSet, SparseSetIndex, TableId},
};
use std::{
collections::HashMap,
Expand Down Expand Up @@ -181,7 +181,7 @@ pub struct Archetype {
id: ArchetypeId,
table_id: TableId,
edges: Edges,
entities: Vec<ArchetypeEntity>,
entities: SimdAlignedVec<ArchetypeEntity>,
table_components: Box<[ComponentId]>,
sparse_set_components: Box<[ComponentId]>,
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
Expand Down Expand Up @@ -225,7 +225,7 @@ impl Archetype {
Self {
id,
table_id,
entities: Vec::new(),
entities: SimdAlignedVec::new(),
components,
table_components,
sparse_set_components,
Expand Down
145 changes: 144 additions & 1 deletion crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
//! Types that detect when their internal data mutate.
use crate::ptr::{
batch::AlignedBatch,
elain::{Align, Alignment},
};

use crate::{component::ComponentTicks, ptr::PtrMut, system::Resource};
use std::ops::{Deref, DerefMut};
use std::{
marker::PhantomData,
ops::{Deref, DerefMut},
};

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

pub(crate) struct TicksBatch<'a, const N: usize, const MIN_ALIGN: usize>
where
Align<MIN_ALIGN>: Alignment,
{
pub(crate) component_ticks: &'a mut AlignedBatch<ComponentTicks, N, MIN_ALIGN>,
pub(crate) last_change_tick: u32,
pub(crate) change_tick: u32,
}

/// Unique mutable borrow of a [`Resource`].
///
/// See the [`Resource`] documentation for usage.
Expand Down Expand Up @@ -352,6 +369,132 @@ change_detection_impl!(Mut<'a, T>, T,);
impl_methods!(Mut<'a, T>, T,);
impl_debug!(Mut<'a, T>,);

/// Unique mutable borrow of an entity's component (batched version).
/// Each batch changes in unison: a batch has changed if any of its elements have changed.
pub struct MutBatch<'a, T, const N: usize, const MIN_ALIGN: usize>
where
Align<MIN_ALIGN>: Alignment,
{
pub(crate) value: &'a mut AlignedBatch<T, N, MIN_ALIGN>,
pub(crate) ticks: TicksBatch<'a, N, MIN_ALIGN>,
pub(crate) _marker: PhantomData<T>,
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> DetectChanges for MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
{
#[inline]
fn is_added(&self) -> bool {
self.ticks
.component_ticks
.as_array()
.iter()
.any(|x| x.is_added(self.ticks.last_change_tick, self.ticks.change_tick))
}

#[inline]
fn is_changed(&self) -> bool {
self.ticks
.component_ticks
.as_array()
.iter()
.any(|x| x.is_changed(self.ticks.last_change_tick, self.ticks.change_tick))
}

#[inline]
fn set_changed(&mut self) {
for ticks in self.ticks.component_ticks.as_array_mut().iter_mut() {
ticks.set_changed(self.ticks.change_tick);
}
}

#[inline]
fn last_changed(&self) -> u32 {
self.ticks.last_change_tick
}

type Inner = AlignedBatch<T, N, MIN_ALIGN>;

fn set_last_changed(&mut self, last_change_tick: u32) {
self.ticks.last_change_tick = last_change_tick;
}

fn bypass_change_detection(&mut self) -> &mut Self::Inner {
self.value
}
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> Deref for MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
{
type Target = AlignedBatch<T, N, MIN_ALIGN>;

#[inline]
fn deref(&self) -> &Self::Target {
self.value
}
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> DerefMut for MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.set_changed();
self.value
}
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> AsRef<AlignedBatch<T, N, MIN_ALIGN>>
for MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
{
#[inline]
fn as_ref(&self) -> &AlignedBatch<T, N, MIN_ALIGN> {
self.deref()
}
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> AsMut<AlignedBatch<T, N, MIN_ALIGN>>
for MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
{
#[inline]
fn as_mut(&mut self) -> &mut AlignedBatch<T, N, MIN_ALIGN> {
self.deref_mut()
}
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
{
/// Consume `self` and return a mutable reference to the
/// contained value while marking `self` as "changed".
#[inline]
pub fn into_inner(mut self) -> &'a mut AlignedBatch<T, N, MIN_ALIGN> {
self.set_changed();
self.value
}
}

impl<'a, T, const N: usize, const MIN_ALIGN: usize> std::fmt::Debug
for MutBatch<'a, T, N, MIN_ALIGN>
where
Align<MIN_ALIGN>: Alignment,
AlignedBatch<T, N, MIN_ALIGN>: std::fmt::Debug,
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(stringify!($name)).field(&self.value).finish()
}
}

/// Unique mutable borrow of resources or an entity's component.
///
/// Similar to [`Mut`], but not generic over the component type, instead
Expand Down
Loading

0 comments on commit 31ed43c

Please sign in to comment.