Skip to content
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

feat: Better performance #71

Merged
merged 16 commits into from
Jan 27, 2024
178 changes: 122 additions & 56 deletions src/chunk_group.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use core::slice;

use crate::prelude::*;
use async_channel::Sender;
use itertools::Itertools;

pub type ChunkCenter<'a> = Option<&'a mut [Atom; CHUNK_LEN]>;
pub type ChunkCorners<'a> = [Option<[&'a mut Atom; QUARTER_CHUNK_LEN]>; 4];
pub type ChunkSides<'a> = [Option<[&'a mut Atom; HALF_CHUNK_LEN]>; 4];

pub struct ChunkGroup<'a> {
pub center: ChunkCenter<'a>,
pub center: &'a mut [Atom],
pub corners: ChunkCorners<'a>,
pub sides: ChunkSides<'a>,
/// Position of the center chunk.
Expand Down Expand Up @@ -41,7 +42,7 @@ impl<'a> ChunkGroup<'a> {
let mut pos = idx.0;
match idx.1 {
// Center
4 => Some(&self.center.as_ref().unwrap()[idx.0.d1()]),
4 => Some(&self.center[idx.0.d1()]),
// Corners
0 | 2 | 6 | 8 => {
// Offset position
Expand Down Expand Up @@ -94,7 +95,7 @@ impl<'a> ChunkGroup<'a> {
let mut pos = idx.0;
match idx.1 {
// Center
4 => Some(&mut self.center.as_mut().unwrap()[idx.0.d1()]),
4 => Some(&mut self.center[idx.0.d1()]),
// Corners
0 | 2 | 6 | 8 => {
// Offset position
Expand Down Expand Up @@ -229,7 +230,7 @@ pub fn local_to_global(pos: (IVec2, i32)) -> IVec2 {
IVec2::new(global_x, global_y)
}

//This function gets the chunk groups and spawns a scope to update them
//This function gets and updates the chunk groups parallely
pub fn update_chunk_groups<'a>(
chunks: &'a mut HashMap<IVec2, Chunk>,
(x_toff, y_toff): (i32, i32),
Expand All @@ -240,39 +241,49 @@ pub fn update_chunk_groups<'a>(
&'a Sender<DeferredDirtyRectUpdate>,
),
update: (u8, &'a Materials),

scope: &Scope<'a, '_, ()>,
) {
puffin::profile_function!();

let (dirty_update_rect_send, dirty_render_rect_send) = senders;
let (dt, materials) = update;

let mut chunk_groups = vec![];
let mut indices = HashMap::new();

for chunk_pos in dirty_rects.keys() {
let same_x = (chunk_pos.x + x_toff + manager_pos.x.abs() % 2) % 2 == 0;
let same_y = (chunk_pos.y + y_toff + manager_pos.y.abs() % 2) % 2 == 0;

if !same_x || !same_y || !chunks.contains_key(chunk_pos) {
continue;
//Get chunks mutable reference from it's pointer
let chunks_ptr: *mut HashMap<IVec2, Chunk> = chunks;
let chunks;
unsafe {
chunks = chunks_ptr.as_mut().unwrap();
}

let mut chunk_group = ChunkGroup {
center: None,
sides: [None, None, None, None],
corners: [None, None, None, None],
center_pos: *chunk_pos,
};
indices.insert(chunk_pos, chunk_groups.len());
scope.spawn(async move {
//If not a center chunk in our current update step, or we don't have the chunk, continue
let same_x = (chunk_pos.x + x_toff + manager_pos.x.abs() % 2) % 2 == 0;
let same_y = (chunk_pos.y + y_toff + manager_pos.y.abs() % 2) % 2 == 0;

for (x_off, y_off) in (-1..=1).cartesian_product(-1..=1) {
let off = ivec2(x_off, y_off);
if !same_x || !same_y || !chunks.contains_key(chunk_pos) {
return;
}

//Get center and create group
let first = chunks.get_mut(chunk_pos).unwrap().atoms.as_mut_ptr();
let center;
unsafe {
center = slice::from_raw_parts_mut(first, CHUNK_LEN);
}

let mut chunk_group = ChunkGroup {
center,
sides: [None, None, None, None],
corners: [None, None, None, None],
center_pos: *chunk_pos,
};

//Get chunk surroundings
for (x_off, y_off) in (-1..=1).cartesian_product(-1..=1) {
let off = ivec2(x_off, y_off);

match (x_off, y_off) {
// CENTER
(0, 0) => {}
// UP and DOWN
(0, -1) | (0, 1) => {
let Some(chunk) = chunks.get_mut(&(*chunk_pos + off)) else {
Expand All @@ -281,12 +292,16 @@ pub fn update_chunk_groups<'a>(

let mut start_ptr = chunk.atoms.as_mut_ptr();
if y_off == -1 {
start_ptr = start_ptr.add(HALF_CHUNK_LEN);
unsafe {
start_ptr = start_ptr.add(HALF_CHUNK_LEN);
}
}

let mut atoms = vec![];
for i in 0..HALF_CHUNK_LEN {
atoms.push(start_ptr.add(i).as_mut().unwrap());
unsafe {
atoms.push(start_ptr.add(i).as_mut().unwrap());
}
}

chunk_group.sides[if y_off == -1 { 0 } else { 3 }] =
Expand All @@ -312,7 +327,9 @@ pub fn update_chunk_groups<'a>(
add_off += HALF_CHUNK_LENGHT;
}

atoms.push(start_ptr.add(i + add_off).as_mut().unwrap());
unsafe {
atoms.push(start_ptr.add(i + add_off).as_mut().unwrap());
}
}

chunk_group.sides[if x_off == -1 { 1 } else { 2 }] =
Expand Down Expand Up @@ -341,7 +358,9 @@ pub fn update_chunk_groups<'a>(
add_off += HALF_CHUNK_LENGHT;
}

atoms.push(start_ptr.add(i + add_off).as_mut().unwrap());
unsafe {
atoms.push(start_ptr.add(i + add_off).as_mut().unwrap());
}
}

let corner_idx = match (x_off, y_off) {
Expand All @@ -355,37 +374,84 @@ pub fn update_chunk_groups<'a>(

chunk_group.corners[corner_idx] = Some(atoms.try_into().unwrap());
}

// CENTER
(0, 0) => { /*We alredy got the center*/ }
_ => unreachable!(),
}
}
}

chunk_groups.push(chunk_group);
let rect = dirty_rects.get(&chunk_group.center_pos).unwrap();
update_chunks(
&mut UpdateChunksType {
group: &mut chunk_group,
dirty_update_rect_send,
dirty_render_rect_send,
materials,
},
dt,
rect,
)
});
}
}

/*#[test]
fn update_test() {
//Get Chunk Manager
let mut chunk_manager = ChunkManager::default();

//Get materials
let materials = &Materials(vec![
Material::Void,
Material::Object,
Material::Powder {
inertial_resistance: 0.1,
},
Material::Liquid { flow: 5 },
Material::Powder {
inertial_resistance: 0.92,
},
Material::Liquid { flow: 1 },
Material::Solid,
Material::Solid,
Material::Solid,
]);

//Add some chunks with full dirty rects
let mut dirty_rects = HashMap::new();
for (x, y) in (chunk_manager.pos.x..chunk_manager.pos.x + 1)
.cartesian_product(chunk_manager.pos.y..chunk_manager.pos.y + 1)
{
let index = ivec2(x, y);
chunk_manager
.chunks
.insert(index, Chunk::new(Handle::default(), index));
dirty_rects.insert(index, URect::new(0, 0, 63, 63));
}

//TODO This can maybe be done with a par_iter_mut()
for (chunk_pos, chunk) in chunks.iter_mut() {
if let Some(i) = indices.get(chunk_pos) {
let chunk_group;
unsafe {
chunk_group = chunk_groups.as_mut_ptr().add(*i).as_mut().unwrap();
}
chunk_group.center = Some(&mut chunk.atoms);
let rect = dirty_rects.get(chunk_pos).unwrap();

scope.spawn(async move {
update_chunks(
&mut UpdateChunksType {
group: chunk_group,
dirty_update_rect_send,
dirty_render_rect_send,
materials,
},
dt,
rect,
)
});
}
let manager_pos = ivec2(chunk_manager.pos.x, chunk_manager.pos.y);
let dt = 0;

//Update
// Create channel for sending dirty update rects
let (dirty_update_rects_send, _) = async_channel::unbounded::<DeferredDirtyRectUpdate>();
let dirty_update_rect_send = &dirty_update_rects_send;

// Create channel for sending dirty render rect updates
let (dirty_render_rects_send, _) = async_channel::unbounded::<DeferredDirtyRectUpdate>();
let dirty_render_rect_send = &dirty_render_rects_send;

for (y_toff, x_toff) in rand_range(0..2)
.into_iter()
.cartesian_product(rand_range(0..2).into_iter())
{
update_chunk_groups(
&mut chunk_manager.chunks,
(x_toff, y_toff),
&dirty_rects,
manager_pos,
(dirty_update_rect_send, dirty_render_rect_send),
(dt, materials),
);
}
}
}*/
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn main() {
ParticlesPlugin,
MaterialsPlugin,
CameraPlugin,
RigidbodyPlugin,
//RigidbodyPlugin,
))
.add_plugins((
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(6.),
Expand Down
Loading