From c26f3c8ffb7dd570b6349fbebfb2fde9fd273c1d Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Mon, 25 Mar 2024 13:59:24 +0000 Subject: [PATCH] Extract brickgrid to module --- src/math.rs | 1 + src/voxel/brickworld/brickgrid.rs | 139 ++++++++++++++++++++++++++++++ src/voxel/brickworld/brickmap.rs | 73 +++------------- src/voxel/brickworld/mod.rs | 1 + src/voxel/brickworld/util.rs | 2 +- 5 files changed, 154 insertions(+), 62 deletions(-) create mode 100644 src/voxel/brickworld/brickgrid.rs diff --git a/src/math.rs b/src/math.rs index 5547b27..a520178 100644 --- a/src/math.rs +++ b/src/math.rs @@ -78,6 +78,7 @@ pub fn tri_lerp_block(p: &[f32], dims: &[u32], vals: &mut [f32]) { } /// Maps a 3d index to a 1d index +// TODO: Handle out of range!! pub fn to_1d_index(p: glam::UVec3, dim: glam::UVec3) -> usize { (p.x + p.y * dim.x + p.z * dim.x * dim.y) as usize } diff --git a/src/voxel/brickworld/brickgrid.rs b/src/voxel/brickworld/brickgrid.rs new file mode 100644 index 0000000..1be50c1 --- /dev/null +++ b/src/voxel/brickworld/brickgrid.rs @@ -0,0 +1,139 @@ +use std::collections::HashSet; + +use crate::{ + gfx::{BulkBufferBuilder, Context}, + math, +}; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum BrickgridFlag { + Empty = 0, + Unloaded = 1, + Loading = 2, + Loaded = 4, +} + +impl From for BrickgridFlag { + fn from(value: u32) -> Self { + match value { + x if x == Self::Unloaded as u32 => Self::Unloaded, + x if x == Self::Loading as u32 => Self::Loading, + x if x == Self::Loaded as u32 => Self::Loaded, + _ => Self::Empty, + } + } +} + +#[repr(C)] +#[derive(Debug, Default, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] +pub struct BrickgridElement(pub u32); + +impl BrickgridElement { + pub fn new(brickmap_cache_idx: usize, flag: BrickgridFlag) -> Self { + Self(((brickmap_cache_idx as u32) << 8) + flag as u32) + } + + pub fn get_pointer(&self) -> usize { + (self.0 >> 8) as usize + } + + pub fn get_flag(&self) -> BrickgridFlag { + BrickgridFlag::from(self.0 & 0xF) + } +} + +#[derive(Debug)] +pub struct Brickgrid { + dimensions: glam::UVec3, + data: Vec, + staged: HashSet, + max_upload_count: usize, + buffer: wgpu::Buffer, + upload_buffer: wgpu::Buffer, +} + +impl Brickgrid { + pub fn new(context: &Context, dimensions: glam::UVec3, max_upload_count: usize) -> Self { + let element_count = (dimensions.x * dimensions.y * dimensions.z) as usize; + let data = vec![BrickgridElement::new(0, BrickgridFlag::Unloaded); element_count]; + + // TODO: change type of upload data. Will need some messyness with bytemucking probably + // but should lead to clearer data definitions + let mut upload_data = vec![0u32; 4 + 4 * max_upload_count]; + upload_data[0] = max_upload_count as u32; + + let mut buffers = BulkBufferBuilder::new() + .set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST) + .with_init_buffer_bm("Brickgrid", &data) + .with_init_buffer_bm("Brickgrid Upload", &upload_data) + .build(context); + + Self { + dimensions, + data, + staged: HashSet::new(), + max_upload_count, + buffer: buffers.remove(0), + upload_buffer: buffers.remove(0), + } + } + + /// Panics if position maps to out of range index + // pub fn set(&mut self, pos: glam::UVec3, value: BrickgridElement) -> BrickgridElement { + // let index = math::to_1d_index(pos, self.dimensions); + pub fn set(&mut self, index: usize, value: BrickgridElement) -> BrickgridElement { + let current = self.data[index]; + self.data[index] = value; + self.staged.insert(index); + current + } + + /// Panics if position maps to out of range index + // pub fn get(&mut self, pos: glam::UVec3) -> BrickgridElement { + // let index = math::to_1d_index(pos, self.dimensions); + pub fn get(&mut self, index: usize) -> BrickgridElement { + self.data[index] + } + + pub fn upload(&mut self, context: &Context) { + let mut upload_data = Vec::new(); + let mut idx = 0; + self.staged.retain(|e| { + // We have a limit of how many elements to upload each frame. So we need + // to keep any excess + if idx >= self.max_upload_count { + return true; + } + + // Index of the brickgrid element, and the value of it + upload_data.push(*e as u32); + upload_data.push(self.data[*e].0); + + idx += 1; + false + }); + + // Upload buffer is {max_count, count, pad, pad, bricks[]}. So we need to add + // the count and pads, and upload at an offset to skip max_count + let data = [&[upload_data.len() as u32, 0, 0], &upload_data[..]].concat(); + context + .queue + .write_buffer(&self.upload_buffer, 4, bytemuck::cast_slice(&data)); + + if idx != 0 { + log::info!( + "Uploading {} brickgrid entries. ({} remaining)", + idx, + self.staged.len() + ); + } + } + + pub fn get_buffer(&self) -> &wgpu::Buffer { + &self.buffer + } + + pub fn get_upload_buffer(&self) -> &wgpu::Buffer { + &self.upload_buffer + } +} diff --git a/src/voxel/brickworld/brickmap.rs b/src/voxel/brickworld/brickmap.rs index 1491478..e9cc48b 100644 --- a/src/voxel/brickworld/brickmap.rs +++ b/src/voxel/brickworld/brickmap.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - use crate::{ gfx::{self, BufferExt}, math, @@ -7,6 +5,7 @@ use crate::{ }; use super::{ + brickgrid::{Brickgrid, BrickgridElement, BrickgridFlag}, brickmap_cache::{BrickmapCache, BrickmapCacheEntry}, shading_table::ShadingTableAllocator, }; @@ -35,27 +34,17 @@ struct BrickmapUnpackElement { shading_elements: [u32; 512], } -pub enum BrickgridFlag { - _Empty = 0, - _Unloaded = 1, - _Loading = 2, - Loaded = 4, -} - #[derive(Debug)] pub struct BrickmapManager { state_uniform: WorldState, state_buffer: wgpu::Buffer, - brickgrid: Vec, - brickgrid_buffer: wgpu::Buffer, + brickgrid: Brickgrid, brickmap_cache: BrickmapCache, shading_table_buffer: wgpu::Buffer, shading_table_allocator: ShadingTableAllocator, feedback_buffer: wgpu::Buffer, feedback_result_buffer: wgpu::Buffer, unpack_max_count: usize, - brickgrid_staged: HashSet, - brickgrid_unpack_buffer: wgpu::Buffer, brickmap_staged: Vec, brickmap_unpack_buffer: wgpu::Buffer, } @@ -76,8 +65,7 @@ impl BrickmapManager { ..Default::default() }; - let brickgrid = - vec![1u32; (brickgrid_dims.x * brickgrid_dims.y * brickgrid_dims.z) as usize]; + let brickgrid = Brickgrid::new(context, brickgrid_dims, max_uploaded_brickmaps as usize); let brickmap_cache = BrickmapCache::new(context, brickmap_cache_size); @@ -88,10 +76,6 @@ impl BrickmapManager { feedback_data[0] = max_requested_brickmaps; let feedback_data_u8 = bytemuck::cast_slice(&feedback_data); - let mut brickgrid_upload_data = vec![0u32; 4 + 4 * max_uploaded_brickmaps as usize]; - brickgrid_upload_data[0] = max_uploaded_brickmaps; - let brickgrid_staged = HashSet::new(); - let mut brickmap_upload_data = vec![0u32; 4 + 532 * max_uploaded_brickmaps as usize]; brickmap_upload_data[0] = max_uploaded_brickmaps; let brickmap_staged = Vec::new(); @@ -99,9 +83,7 @@ impl BrickmapManager { let mut buffers = gfx::BulkBufferBuilder::new() .with_init_buffer_bm("Brick World State", &[state_uniform]) .set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST) - .with_init_buffer_bm("Brickgrid", &brickgrid) .with_init_buffer_bm("Shading Table", &shading_table) - .with_init_buffer_bm("Brickgrid Unpack", &brickgrid_upload_data) .with_init_buffer_bm("Brickmap Unpack", &brickmap_upload_data) .set_usage( wgpu::BufferUsages::STORAGE @@ -119,13 +101,10 @@ impl BrickmapManager { brickmap_cache, shading_table_allocator, unpack_max_count: max_uploaded_brickmaps as usize, - brickgrid_staged, brickmap_staged, state_buffer: buffers.remove(0), - brickgrid_buffer: buffers.remove(0), shading_table_buffer: buffers.remove(0), - brickgrid_unpack_buffer: buffers.remove(0), brickmap_unpack_buffer: buffers.remove(0), feedback_buffer: buffers.remove(0), feedback_result_buffer: buffers.remove(0), @@ -133,7 +112,7 @@ impl BrickmapManager { } pub fn get_brickgrid_buffer(&self) -> &wgpu::Buffer { - &self.brickgrid_buffer + self.brickgrid.get_buffer() } pub fn get_worldstate_buffer(&self) -> &wgpu::Buffer { @@ -161,7 +140,7 @@ impl BrickmapManager { } pub fn get_brickgrid_unpack_buffer(&self) -> &wgpu::Buffer { - &self.brickgrid_unpack_buffer + self.brickgrid.get_upload_buffer() } pub fn get_unpack_max_count(&self) -> usize { @@ -211,6 +190,7 @@ impl BrickmapManager { // empty. We don't need to upload it, just mark the relevant brickgrid entry. if albedo_data.is_empty() { if let Some(entry) = self.update_brickgrid_element(grid_idx, 0) { + // TODO: We need to actually remove the cache entry lmao // The brickgrid element had a brickmap entry so we need to unload it's // shading data if let Err(e) = self @@ -241,6 +221,7 @@ impl BrickmapManager { BrickgridFlag::Loaded, ), ) { + // TODO: We need to actually remove the cache entry lmao // The brickgrid element had a brickmap entry so we need to unload it's // shading data if let Err(e) = self @@ -273,50 +254,20 @@ impl BrickmapManager { fn update_brickgrid_element(&mut self, index: usize, data: u32) -> Option { let mut brickmap_cache_entry = None; - if (self.brickgrid[index] & 0xF) == 4 { - let cache_index = (self.brickgrid[index] >> 8) as usize; + let current = self.brickgrid.get(index); + if current.get_flag() == BrickgridFlag::Loaded { + let cache_index = current.get_pointer(); brickmap_cache_entry = self.brickmap_cache.get_entry(cache_index); } // We're safe to overwrite the CPU brickgrid and mark for GPU upload now - self.brickgrid[index] = data; - self.brickgrid_staged.insert(index); + self.brickgrid.set(index, BrickgridElement(data)); brickmap_cache_entry } // TODO: Tidy this up more fn upload_unpack_buffers(&mut self, context: &gfx::Context) { - // Brickgrid - let mut data = Vec::new(); - let mut iter = self.brickgrid_staged.iter(); - let mut to_remove = Vec::new(); - for _ in 0..self.unpack_max_count { - match iter.next() { - Some(val) => { - to_remove.push(*val); - data.push(*val as u32); - data.push(self.brickgrid[*val]); - } - None => break, - } - } - for val in &to_remove { - self.brickgrid_staged.remove(val); - } - - if !data.is_empty() { - log::info!( - "Uploading {} brickgrid entries. ({} remaining)", - to_remove.len(), - self.brickgrid_staged.len() - ); - } - - context.queue.write_buffer( - &self.brickgrid_unpack_buffer, - 4, - bytemuck::cast_slice(&[&[data.len() as u32, 0, 0], &data[..]].concat()), - ); + self.brickgrid.upload(context); // Brickmap let end = self.unpack_max_count.min(self.brickmap_staged.len()); diff --git a/src/voxel/brickworld/mod.rs b/src/voxel/brickworld/mod.rs index 88a517d..274bef9 100644 --- a/src/voxel/brickworld/mod.rs +++ b/src/voxel/brickworld/mod.rs @@ -1,3 +1,4 @@ +mod brickgrid; mod brickmap; mod brickmap_cache; mod shading_table; diff --git a/src/voxel/brickworld/util.rs b/src/voxel/brickworld/util.rs index d00a864..7da4453 100644 --- a/src/voxel/brickworld/util.rs +++ b/src/voxel/brickworld/util.rs @@ -1,6 +1,6 @@ use crate::voxel::world::{Voxel, WorldManager}; -use super::brickmap::BrickgridFlag; +use super::brickgrid::BrickgridFlag; pub fn cull_interior_voxels( world: &mut WorldManager,