Skip to content

Commit 1fd4d43

Browse files
Implement batched query support
* Only Dense queries are accelerated currently * Certain features are awaiting on GATs/generic const expressions
1 parent 8a26812 commit 1fd4d43

17 files changed

+1584
-75
lines changed

crates/bevy_ecs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ serde = "1"
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

+18-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use crate::{
55
bundle::BundleId,
66
component::{ComponentId, StorageType},
77
entity::{Entity, EntityLocation},
8-
storage::{Column, SparseArray, SparseSet, SparseSetIndex, TableId},
8+
ptr::ThinSimdAlignedSlicePtr,
9+
storage::{
10+
aligned_vec::SimdAlignedVec, Column, SparseArray, SparseSet, SparseSetIndex, TableId,
11+
},
912
};
1013
use std::{
1114
collections::HashMap,
@@ -120,7 +123,7 @@ impl Edges {
120123

121124
struct TableInfo {
122125
id: TableId,
123-
entity_rows: Vec<usize>,
126+
entity_rows: SimdAlignedVec<usize>,
124127
}
125128

126129
pub(crate) struct ArchetypeSwapRemoveResult {
@@ -135,7 +138,7 @@ pub(crate) struct ArchetypeComponentInfo {
135138

136139
pub struct Archetype {
137140
id: ArchetypeId,
138-
entities: Vec<Entity>,
141+
entities: SimdAlignedVec<Entity>,
139142
edges: Edges,
140143
table_info: TableInfo,
141144
table_components: Box<[ComponentId]>,
@@ -214,6 +217,18 @@ impl Archetype {
214217
&self.table_info.entity_rows
215218
}
216219

220+
//These 'aligned' functions are necessary for batching but aren't meant for general consumption.
221+
//However, we can't convert from an arbitrary slice into a ThinSimdAlignedSlicePtr.
222+
#[inline]
223+
pub(crate) fn entities_aligned(&self) -> ThinSimdAlignedSlicePtr<Entity> {
224+
self.entities.get_slice()
225+
}
226+
227+
#[inline]
228+
pub(crate) fn entity_table_rows_aligned(&self) -> ThinSimdAlignedSlicePtr<usize> {
229+
self.table_info.entity_rows.get_slice()
230+
}
231+
217232
#[inline]
218233
pub fn table_components(&self) -> &[ComponentId] {
219234
&self.table_components

crates/bevy_ecs/src/change_detection.rs

+149
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Types that detect when their internal data mutate.
22
3+
use crate::ptr::batch::{AlignedBatchGat, AlignedBatchT, AlignedBatchTrait};
4+
35
use crate::{component::ComponentTicks, ptr::PtrMut, system::Resource};
6+
use std::marker::PhantomData;
47
#[cfg(feature = "bevy_reflect")]
58
use std::ops::{Deref, DerefMut};
69

@@ -198,6 +201,15 @@ pub(crate) struct Ticks<'a> {
198201
pub(crate) change_tick: u32,
199202
}
200203

204+
pub(crate) struct TicksBatch<'a, const N: usize, const ALIGN: usize>
205+
where
206+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
207+
{
208+
pub(crate) component_ticks: &'a mut AlignedBatchT<ComponentTicks, N, ALIGN>,
209+
pub(crate) last_change_tick: u32,
210+
pub(crate) change_tick: u32,
211+
}
212+
201213
/// Unique mutable borrow of a [`Resource`].
202214
///
203215
/// See the [`Resource`] documentation for usage.
@@ -271,6 +283,143 @@ change_detection_impl!(Mut<'a, T>, T,);
271283
impl_into_inner!(Mut<'a, T>, T,);
272284
impl_debug!(Mut<'a, T>,);
273285

286+
/// Unique mutable borrow of an entity's component (batched version)
287+
/// a batch changes in unison. A batch has changed if any of its elements have changed.
288+
pub struct MutBatch<'a, T: ?Sized, const N: usize, const ALIGN: usize>
289+
where
290+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
291+
T: AlignedBatchGat<N, ALIGN>,
292+
{
293+
pub(crate) value: &'a mut AlignedBatchT<T, N, ALIGN>,
294+
pub(crate) ticks: TicksBatch<'a, N, ALIGN>,
295+
pub(crate) _marker: PhantomData<T>,
296+
}
297+
298+
impl<'a, T: ?Sized, const N: usize, const ALIGN: usize> DetectChanges for MutBatch<'a, T, N, ALIGN>
299+
where
300+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
301+
T: AlignedBatchGat<N, ALIGN>,
302+
{
303+
#[inline]
304+
fn is_added(&self) -> bool {
305+
self.ticks
306+
.component_ticks
307+
.as_array()
308+
.iter()
309+
.any(|x| x.is_added(self.ticks.last_change_tick, self.ticks.change_tick))
310+
}
311+
312+
#[inline]
313+
fn is_changed(&self) -> bool {
314+
self.ticks
315+
.component_ticks
316+
.as_array()
317+
.iter()
318+
.any(|x| x.is_changed(self.ticks.last_change_tick, self.ticks.change_tick))
319+
}
320+
321+
#[inline]
322+
fn set_changed(&mut self) {
323+
for ticks in self.ticks.component_ticks.as_array_mut().iter_mut() {
324+
ticks.set_changed(self.ticks.change_tick);
325+
}
326+
}
327+
328+
#[inline]
329+
fn last_changed(&self) -> u32 {
330+
self.ticks.last_change_tick
331+
}
332+
333+
type Inner = AlignedBatchT<T, N, ALIGN>;
334+
335+
fn set_last_changed(&mut self, last_change_tick: u32) {
336+
self.ticks.last_change_tick = last_change_tick;
337+
}
338+
339+
fn bypass_change_detection(&mut self) -> &mut Self::Inner {
340+
self.value
341+
}
342+
}
343+
344+
impl<'a, T, const N: usize, const ALIGN: usize> Deref for MutBatch<'a, T, N, ALIGN>
345+
where
346+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
347+
T: AlignedBatchGat<N, ALIGN>,
348+
{
349+
type Target = AlignedBatchT<T, N, ALIGN>;
350+
351+
#[inline]
352+
fn deref(&self) -> &Self::Target {
353+
self.value
354+
}
355+
}
356+
357+
impl<'a, T, const N: usize, const ALIGN: usize> DerefMut for MutBatch<'a, T, N, ALIGN>
358+
where
359+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
360+
T: AlignedBatchGat<N, ALIGN>,
361+
{
362+
#[inline]
363+
fn deref_mut(&mut self) -> &mut Self::Target {
364+
self.set_changed();
365+
self.value
366+
}
367+
}
368+
369+
impl<'a, T, const N: usize, const ALIGN: usize> AsRef<AlignedBatchT<T, N, ALIGN>>
370+
for MutBatch<'a, T, N, ALIGN>
371+
where
372+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
373+
T: AlignedBatchGat<N, ALIGN>,
374+
{
375+
#[inline]
376+
fn as_ref(&self) -> &AlignedBatchT<T, N, ALIGN> {
377+
self.deref()
378+
}
379+
}
380+
381+
impl<'a, T, const N: usize, const ALIGN: usize> AsMut<AlignedBatchT<T, N, ALIGN>>
382+
for MutBatch<'a, T, N, ALIGN>
383+
where
384+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
385+
T: AlignedBatchGat<N, ALIGN>,
386+
{
387+
#[inline]
388+
fn as_mut(&mut self) -> &mut AlignedBatchT<T, N, ALIGN> {
389+
self.deref_mut()
390+
}
391+
}
392+
393+
//change_detection_impl!(MutBatch<'a, T>, T,);
394+
//impl_into_inner!(MutBatch<'a, T>, T,);
395+
//impl_debug!(MutBatch<'a, T>,);
396+
397+
impl<'a, T, const N: usize, const ALIGN: usize> MutBatch<'a, T, N, ALIGN>
398+
where
399+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
400+
T: AlignedBatchGat<N, ALIGN>,
401+
{
402+
/// Consume `self` and return a mutable reference to the
403+
/// contained value while marking `self` as "changed".
404+
#[inline]
405+
pub fn into_inner(mut self) -> &'a mut AlignedBatchT<T, N, ALIGN> {
406+
self.set_changed();
407+
self.value
408+
}
409+
}
410+
411+
impl<'a, T, const N: usize, const ALIGN: usize> std::fmt::Debug for MutBatch<'a, T, N, ALIGN>
412+
where
413+
ComponentTicks: AlignedBatchGat<N, ALIGN>,
414+
T: AlignedBatchGat<N, ALIGN>,
415+
AlignedBatchT<T, N, ALIGN>: std::fmt::Debug,
416+
T: std::fmt::Debug,
417+
{
418+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419+
f.debug_tuple(stringify!($name)).field(&self.value).finish()
420+
}
421+
}
422+
274423
/// Unique mutable borrow of resources or an entity's component.
275424
///
276425
/// Similar to [`Mut`], but not generic over the component type, instead

0 commit comments

Comments
 (0)