From 132bc995409912e16e07541b8da3819c3323ae1f Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Sat, 23 Mar 2024 10:28:24 +0000 Subject: [PATCH] Move shading table to own module --- src/voxel/brickworld/brickmap.rs | 140 +------------------------- src/voxel/brickworld/mod.rs | 1 + src/voxel/brickworld/shading_table.rs | 137 +++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 138 deletions(-) create mode 100644 src/voxel/brickworld/shading_table.rs diff --git a/src/voxel/brickworld/brickmap.rs b/src/voxel/brickworld/brickmap.rs index 3fcdce9..6f8ba92 100644 --- a/src/voxel/brickworld/brickmap.rs +++ b/src/voxel/brickworld/brickmap.rs @@ -5,6 +5,8 @@ use crate::{ voxel::world::{Voxel, WorldManager}, }; +use super::shading_table::ShadingTableAllocator; + #[repr(C)] #[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] struct Brickmap { @@ -480,141 +482,3 @@ impl BrickmapManager { (chunk_pos.as_ivec3(), block_pos.as_uvec3()) } } - -#[derive(Debug)] -struct ShadingBucket { - global_offset: u32, - slot_count: u32, - slot_size: u32, - free: Vec, - used: Vec, -} - -impl ShadingBucket { - fn new(global_offset: u32, slot_count: u32, slot_size: u32) -> Self { - let mut free = Vec::with_capacity(slot_count as usize); - for i in (0..slot_count).rev() { - free.push(i); - } - - let used = Vec::with_capacity(slot_count as usize); - Self { - global_offset, - slot_count, - slot_size, - free, - used, - } - } - - fn contains_address(&self, address: u32) -> bool { - let min = self.global_offset; - let max = min + self.slot_count * self.slot_size; - min <= address && address < max - } - - fn try_alloc(&mut self) -> Option { - // Mark the first free index as used - let bucket_index = self.free.pop()?; - self.used.push(bucket_index); - - // Convert the bucket index into a global address - Some(self.global_offset + bucket_index * self.slot_size) - } - - fn try_dealloc(&mut self, address: u32) -> Result<(), String> { - log::trace!("Dealloc address: {}", address); - if !self.contains_address(address) { - let msg = format!("Address ({}) is not within bucket range.", address); - return Err(msg); - } - - let local_address = address - self.global_offset; - if local_address % self.slot_size != 0 { - return Err("Address is not aligned to bucket element size.".to_string()); - } - - let bucket_index = local_address / self.slot_size; - if !self.used.contains(&bucket_index) { - return Err("Address is not currently allocated.".to_string()); - } - - // All the potential errors are out of the way, time to actually deallocate - let position = self.used.iter().position(|x| *x == bucket_index).unwrap(); - self.used.swap_remove(position); - self.free.push(bucket_index); - Ok(()) - } -} - -#[derive(Debug)] -struct ShadingTableAllocator { - buckets: Vec, - bucket_count: u32, - elements_per_bucket: u32, - total_elements: u32, - used_elements: u32, -} - -impl ShadingTableAllocator { - fn new(bucket_count: u32, elements_per_bucket: u32) -> Self { - let total_elements = bucket_count * elements_per_bucket; - let used_elements = 0; - - // Build the buckets. Ordered in ascending size - let mut buckets = Vec::with_capacity(bucket_count as usize); - for i in (0..bucket_count).rev() { - let global_offset = i * elements_per_bucket; - let slot_size = u32::pow(2, 9 - i); - let slot_count = elements_per_bucket / slot_size; - log::info!( - "Creating bucket: offset({}), slot_size({}), slot_count({})", - global_offset, - slot_size, - slot_count - ); - buckets.push(ShadingBucket::new(global_offset, slot_count, slot_size)); - } - - Self { - buckets, - bucket_count, - elements_per_bucket, - total_elements, - used_elements, - } - } - - fn try_alloc(&mut self, size: u32) -> Option { - for i in 0..self.bucket_count as usize { - let bucket = &mut self.buckets[i]; - if bucket.slot_size < size { - continue; - } - - let idx = bucket.try_alloc(); - if idx.is_some() { - self.used_elements += bucket.slot_size; - log::trace!( - "Allocated to shader table at {}. {}/{} ({}%)", - idx.unwrap(), - self.used_elements, - self.total_elements, - ((self.used_elements as f32 / self.total_elements as f32) * 100.0).floor() - ); - return idx; - } - } - - None - } - - fn try_dealloc(&mut self, address: u32) -> Result<(), String> { - // Buckets are reverse order of their global offset so we need to reverse our idx - let mut bucket_idx = address / self.elements_per_bucket; - bucket_idx = self.bucket_count - bucket_idx - 1; - let bucket = &mut self.buckets[bucket_idx as usize]; - self.used_elements -= bucket.slot_size; - bucket.try_dealloc(address) - } -} diff --git a/src/voxel/brickworld/mod.rs b/src/voxel/brickworld/mod.rs index caa798e..2631a60 100644 --- a/src/voxel/brickworld/mod.rs +++ b/src/voxel/brickworld/mod.rs @@ -1,3 +1,4 @@ mod brickmap; +mod shading_table; pub use brickmap::BrickmapManager; diff --git a/src/voxel/brickworld/shading_table.rs b/src/voxel/brickworld/shading_table.rs new file mode 100644 index 0000000..ceeb59e --- /dev/null +++ b/src/voxel/brickworld/shading_table.rs @@ -0,0 +1,137 @@ +#[derive(Debug)] +pub struct ShadingBucket { + global_offset: u32, + slot_count: u32, + slot_size: u32, + free: Vec, + used: Vec, +} + +impl ShadingBucket { + fn new(global_offset: u32, slot_count: u32, slot_size: u32) -> Self { + let mut free = Vec::with_capacity(slot_count as usize); + for i in (0..slot_count).rev() { + free.push(i); + } + + let used = Vec::with_capacity(slot_count as usize); + Self { + global_offset, + slot_count, + slot_size, + free, + used, + } + } + + fn contains_address(&self, address: u32) -> bool { + let min = self.global_offset; + let max = min + self.slot_count * self.slot_size; + min <= address && address < max + } + + fn try_alloc(&mut self) -> Option { + // Mark the first free index as used + let bucket_index = self.free.pop()?; + self.used.push(bucket_index); + + // Convert the bucket index into a global address + Some(self.global_offset + bucket_index * self.slot_size) + } + + fn try_dealloc(&mut self, address: u32) -> Result<(), String> { + log::trace!("Dealloc address: {}", address); + if !self.contains_address(address) { + let msg = format!("Address ({}) is not within bucket range.", address); + return Err(msg); + } + + let local_address = address - self.global_offset; + if local_address % self.slot_size != 0 { + return Err("Address is not aligned to bucket element size.".to_string()); + } + + let bucket_index = local_address / self.slot_size; + if !self.used.contains(&bucket_index) { + return Err("Address is not currently allocated.".to_string()); + } + + // All the potential errors are out of the way, time to actually deallocate + let position = self.used.iter().position(|x| *x == bucket_index).unwrap(); + self.used.swap_remove(position); + self.free.push(bucket_index); + Ok(()) + } +} + +#[derive(Debug)] +pub struct ShadingTableAllocator { + buckets: Vec, + bucket_count: u32, + elements_per_bucket: u32, + pub total_elements: u32, + used_elements: u32, +} + +impl ShadingTableAllocator { + pub fn new(bucket_count: u32, elements_per_bucket: u32) -> Self { + let total_elements = bucket_count * elements_per_bucket; + let used_elements = 0; + + // Build the buckets. Ordered in ascending size + let mut buckets = Vec::with_capacity(bucket_count as usize); + for i in (0..bucket_count).rev() { + let global_offset = i * elements_per_bucket; + let slot_size = u32::pow(2, 9 - i); + let slot_count = elements_per_bucket / slot_size; + log::info!( + "Creating bucket: offset({}), slot_size({}), slot_count({})", + global_offset, + slot_size, + slot_count + ); + buckets.push(ShadingBucket::new(global_offset, slot_count, slot_size)); + } + + Self { + buckets, + bucket_count, + elements_per_bucket, + total_elements, + used_elements, + } + } + + pub fn try_alloc(&mut self, size: u32) -> Option { + for i in 0..self.bucket_count as usize { + let bucket = &mut self.buckets[i]; + if bucket.slot_size < size { + continue; + } + + let idx = bucket.try_alloc(); + if idx.is_some() { + self.used_elements += bucket.slot_size; + log::trace!( + "Allocated to shader table at {}. {}/{} ({}%)", + idx.unwrap(), + self.used_elements, + self.total_elements, + ((self.used_elements as f32 / self.total_elements as f32) * 100.0).floor() + ); + return idx; + } + } + + None + } + + pub fn try_dealloc(&mut self, address: u32) -> Result<(), String> { + // Buckets are reverse order of their global offset so we need to reverse our idx + let mut bucket_idx = address / self.elements_per_bucket; + bucket_idx = self.bucket_count - bucket_idx - 1; + let bucket = &mut self.buckets[bucket_idx as usize]; + self.used_elements -= bucket.slot_size; + bucket.try_dealloc(address) + } +}