-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Contiguous access #21984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Contiguous access #21984
Changes from 6 commits
39bf69f
19c7a2a
9f391c7
564b771
667955d
6ad54b0
f3ebbc7
d66a0cb
9e54e50
c5aa426
cd000c1
420dbd5
2fb9cd3
59cd6c6
6c359ee
083f714
3881d63
7d5ba3d
8571bd7
d1d9386
28d40cc
8d64ec4
f2afb53
7477821
f02d4c9
0d74581
2c6c251
9599bfc
6ade0c9
c9c293d
495c355
7f55e03
888a473
1f765c4
bef611e
f8286d0
9b14f5f
250a359
2acfca5
42733c5
4e1cc10
6e0441f
526680b
31d6f8c
ecc13e2
99d116d
22612d7
371c52c
bddcf57
6430029
c4bd5ae
6c0c771
c8b1548
3ee7dd3
e941398
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| use bevy_ecs::prelude::*; | ||
| use glam::*; | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Transform(Mat4); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Position(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Rotation(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Velocity(Vec3); | ||
|
|
||
| pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>); | ||
|
|
||
| impl<'w> Benchmark<'w> { | ||
| pub fn new() -> Self { | ||
| let mut world = World::new(); | ||
|
|
||
| world.spawn_batch(core::iter::repeat_n( | ||
| ( | ||
| Transform(Mat4::from_scale(Vec3::ONE)), | ||
| Position(Vec3::X), | ||
| Rotation(Vec3::X), | ||
| Velocity(Vec3::X), | ||
| ), | ||
| 10_000, | ||
| )); | ||
|
|
||
| let query = world.query::<(&Velocity, &mut Position)>(); | ||
| Self(world, query) | ||
| } | ||
|
|
||
| #[inline(never)] | ||
| pub fn run(&mut self) { | ||
| let mut iter = self.1.iter_mut(&mut self.0); | ||
| for (velocity, (position, mut ticks)) in iter.as_contiguous_iter().unwrap() { | ||
| for (v, p) in velocity.iter().zip(position.iter_mut()) { | ||
| p.0 += v.0; | ||
| } | ||
| // to match the iter_simple benchmark | ||
| ticks.mark_all_as_updated(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| use bevy_ecs::prelude::*; | ||
| use glam::*; | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Transform(Mat4); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Position(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Rotation(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Velocity(Vec3); | ||
|
|
||
| pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>); | ||
|
|
||
| impl<'w> Benchmark<'w> { | ||
| pub fn supported() -> bool { | ||
| is_x86_feature_detected!("avx2") | ||
| } | ||
|
|
||
| pub fn new() -> Option<Self> { | ||
| if !Self::supported() { | ||
| return None; | ||
| } | ||
|
|
||
| let mut world = World::new(); | ||
|
|
||
| world.spawn_batch(core::iter::repeat_n( | ||
| ( | ||
| Transform(Mat4::from_scale(Vec3::ONE)), | ||
| Position(Vec3::X), | ||
| Rotation(Vec3::X), | ||
| Velocity(Vec3::X), | ||
| ), | ||
| 10_000, | ||
| )); | ||
|
|
||
| let query = world.query::<(&Velocity, &mut Position)>(); | ||
| Some(Self(world, query)) | ||
| } | ||
|
|
||
| #[inline(never)] | ||
| pub fn run(&mut self) { | ||
| #[target_feature(enable = "avx2")] | ||
| fn exec(position: &mut [Position], velocity: &[Velocity]) { | ||
| for i in 0..position.len() { | ||
| position[i].0 += velocity[i].0; | ||
| } | ||
| } | ||
|
|
||
| let mut iter = self.1.iter_mut(&mut self.0); | ||
| for (velocity, (position, mut ticks)) in iter.as_contiguous_iter().unwrap() { | ||
| // SAFETY: checked in new | ||
| unsafe { | ||
| exec(position, velocity); | ||
| } | ||
| // to match the iter_simple benchmark | ||
| ticks.mark_all_as_updated(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| use bevy_ecs::prelude::*; | ||
| use glam::*; | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Transform(Mat4); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Position(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Rotation(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Velocity(Vec3); | ||
|
|
||
| pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>); | ||
|
|
||
| impl<'w> Benchmark<'w> { | ||
| pub fn new() -> Self { | ||
| let mut world = World::new(); | ||
|
|
||
| world.spawn_batch(core::iter::repeat_n( | ||
| ( | ||
| Transform(Mat4::from_scale(Vec3::ONE)), | ||
| Position(Vec3::X), | ||
| Rotation(Vec3::X), | ||
| Velocity(Vec3::X), | ||
| ), | ||
| 10_000, | ||
| )); | ||
|
|
||
| let query = world.query::<(&Velocity, &mut Position)>(); | ||
| Self(world, query) | ||
| } | ||
|
|
||
| #[inline(never)] | ||
| pub fn run(&mut self) { | ||
| for (velocity, mut position) in self.1.iter_mut(&mut self.0) { | ||
| position.bypass_change_detection().0 += velocity.0; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| use bevy_ecs::prelude::*; | ||
| use glam::*; | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Transform(Mat4); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Position(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Rotation(Vec3); | ||
|
|
||
| #[derive(Component, Copy, Clone)] | ||
| struct Velocity(Vec3); | ||
|
|
||
| pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>); | ||
|
|
||
| impl<'w> Benchmark<'w> { | ||
| pub fn new() -> Self { | ||
| let mut world = World::new(); | ||
|
|
||
| world.spawn_batch(core::iter::repeat_n( | ||
| ( | ||
| Transform(Mat4::from_scale(Vec3::ONE)), | ||
| Position(Vec3::X), | ||
| Rotation(Vec3::X), | ||
| Velocity(Vec3::X), | ||
| ), | ||
| 10_000, | ||
| )); | ||
|
|
||
| let query = world.query::<(&Velocity, &mut Position)>(); | ||
| Self(world, query) | ||
| } | ||
|
|
||
| #[inline(never)] | ||
| pub fn run(&mut self) { | ||
| let mut iter = self.1.iter_mut(&mut self.0); | ||
| for (velocity, (position, _ticks)) in iter.as_contiguous_iter().unwrap() { | ||
| for (v, p) in velocity.iter().zip(position.iter_mut()) { | ||
| p.0 += v.0; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,8 +3,9 @@ use crate::{ | |||||||||||||||||||||||||
| ptr::PtrMut, | ||||||||||||||||||||||||||
| resource::Resource, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| use bevy_ptr::{Ptr, UnsafeCellDeref}; | ||||||||||||||||||||||||||
| use bevy_ptr::{Ptr, ThinSlicePtr, UnsafeCellDeref}; | ||||||||||||||||||||||||||
| use core::{ | ||||||||||||||||||||||||||
| cell::UnsafeCell, | ||||||||||||||||||||||||||
| ops::{Deref, DerefMut}, | ||||||||||||||||||||||||||
| panic::Location, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
@@ -463,6 +464,82 @@ impl<'w, T: ?Sized> Mut<'w, T> { | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /// Used by [`Mut`] for [`crate::query::ContiguousQueryData`] to allow marking component's changes | ||||||||||||||||||||||||||
| pub struct ContiguousComponentTicks<'w, const MUTABLE: bool> { | ||||||||||||||||||||||||||
| added: ThinSlicePtr<'w, UnsafeCell<Tick>>, | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| changed: ThinSlicePtr<'w, UnsafeCell<Tick>>, | ||||||||||||||||||||||||||
| changed_by: MaybeLocation<ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>>, | ||||||||||||||||||||||||||
| count: usize, | ||||||||||||||||||||||||||
| last_run: Tick, | ||||||||||||||||||||||||||
| this_run: Tick, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| impl<'w> ContiguousComponentTicks<'w, true> { | ||||||||||||||||||||||||||
| /// Returns mutable changed ticks slice | ||||||||||||||||||||||||||
| pub fn get_changed_ticks_mut(&mut self) -> &mut [Tick] { | ||||||||||||||||||||||||||
| // SAFETY: `changed` slice is `self.count` long, aliasing rules are uphold by `new`. | ||||||||||||||||||||||||||
| unsafe { self.changed.as_mut_slice(self.count) } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /// Marks all components as updated | ||||||||||||||||||||||||||
| pub fn mark_all_as_updated(&mut self) { | ||||||||||||||||||||||||||
| let this_run = self.this_run; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| for i in 0..self.count { | ||||||||||||||||||||||||||
| // SAFETY: `changed_by` slice is `self.count` long, aliasing rules are uphold by `new` | ||||||||||||||||||||||||||
| self.changed_by | ||||||||||||||||||||||||||
| .map(|v| unsafe { v.get_unchecked(i).deref_mut() }) | ||||||||||||||||||||||||||
| .assign(MaybeLocation::caller()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| for i in 0..self.count { | |
| // SAFETY: `changed_by` slice is `self.count` long, aliasing rules are uphold by `new` | |
| self.changed_by | |
| .map(|v| unsafe { v.get_unchecked(i).deref_mut() }) | |
| .assign(MaybeLocation::caller()); | |
| } | |
| self.changed_by.map(|v| { | |
| for i in 0..self.count { | |
| // SAFETY: `changed_by` slice is `self.count` long, aliasing rules are uphold by `new` | |
| *unsafe { v.get_unchecked(i).deref_mut() } = Location::caller(); | |
| } | |
| }); |
Uh oh!
There was an error while loading. Please reload this page.