Extract brickgrid to module

This commit is contained in:
Jarrod Doyle 2024-03-25 13:59:24 +00:00
parent 03a74d1b02
commit c26f3c8ffb
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
5 changed files with 154 additions and 62 deletions

View File

@ -78,6 +78,7 @@ pub fn tri_lerp_block(p: &[f32], dims: &[u32], vals: &mut [f32]) {
} }
/// Maps a 3d index to a 1d index /// 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 { 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 (p.x + p.y * dim.x + p.z * dim.x * dim.y) as usize
} }

View File

@ -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<u32> 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<BrickgridElement>,
staged: HashSet<usize>,
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
}
}

View File

@ -1,5 +1,3 @@
use std::collections::HashSet;
use crate::{ use crate::{
gfx::{self, BufferExt}, gfx::{self, BufferExt},
math, math,
@ -7,6 +5,7 @@ use crate::{
}; };
use super::{ use super::{
brickgrid::{Brickgrid, BrickgridElement, BrickgridFlag},
brickmap_cache::{BrickmapCache, BrickmapCacheEntry}, brickmap_cache::{BrickmapCache, BrickmapCacheEntry},
shading_table::ShadingTableAllocator, shading_table::ShadingTableAllocator,
}; };
@ -35,27 +34,17 @@ struct BrickmapUnpackElement {
shading_elements: [u32; 512], shading_elements: [u32; 512],
} }
pub enum BrickgridFlag {
_Empty = 0,
_Unloaded = 1,
_Loading = 2,
Loaded = 4,
}
#[derive(Debug)] #[derive(Debug)]
pub struct BrickmapManager { pub struct BrickmapManager {
state_uniform: WorldState, state_uniform: WorldState,
state_buffer: wgpu::Buffer, state_buffer: wgpu::Buffer,
brickgrid: Vec<u32>, brickgrid: Brickgrid,
brickgrid_buffer: wgpu::Buffer,
brickmap_cache: BrickmapCache, brickmap_cache: BrickmapCache,
shading_table_buffer: wgpu::Buffer, shading_table_buffer: wgpu::Buffer,
shading_table_allocator: ShadingTableAllocator, shading_table_allocator: ShadingTableAllocator,
feedback_buffer: wgpu::Buffer, feedback_buffer: wgpu::Buffer,
feedback_result_buffer: wgpu::Buffer, feedback_result_buffer: wgpu::Buffer,
unpack_max_count: usize, unpack_max_count: usize,
brickgrid_staged: HashSet<usize>,
brickgrid_unpack_buffer: wgpu::Buffer,
brickmap_staged: Vec<BrickmapUnpackElement>, brickmap_staged: Vec<BrickmapUnpackElement>,
brickmap_unpack_buffer: wgpu::Buffer, brickmap_unpack_buffer: wgpu::Buffer,
} }
@ -76,8 +65,7 @@ impl BrickmapManager {
..Default::default() ..Default::default()
}; };
let brickgrid = let brickgrid = Brickgrid::new(context, brickgrid_dims, max_uploaded_brickmaps as usize);
vec![1u32; (brickgrid_dims.x * brickgrid_dims.y * brickgrid_dims.z) as usize];
let brickmap_cache = BrickmapCache::new(context, brickmap_cache_size); let brickmap_cache = BrickmapCache::new(context, brickmap_cache_size);
@ -88,10 +76,6 @@ impl BrickmapManager {
feedback_data[0] = max_requested_brickmaps; feedback_data[0] = max_requested_brickmaps;
let feedback_data_u8 = bytemuck::cast_slice(&feedback_data); 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]; let mut brickmap_upload_data = vec![0u32; 4 + 532 * max_uploaded_brickmaps as usize];
brickmap_upload_data[0] = max_uploaded_brickmaps; brickmap_upload_data[0] = max_uploaded_brickmaps;
let brickmap_staged = Vec::new(); let brickmap_staged = Vec::new();
@ -99,9 +83,7 @@ impl BrickmapManager {
let mut buffers = gfx::BulkBufferBuilder::new() let mut buffers = gfx::BulkBufferBuilder::new()
.with_init_buffer_bm("Brick World State", &[state_uniform]) .with_init_buffer_bm("Brick World State", &[state_uniform])
.set_usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST) .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("Shading Table", &shading_table)
.with_init_buffer_bm("Brickgrid Unpack", &brickgrid_upload_data)
.with_init_buffer_bm("Brickmap Unpack", &brickmap_upload_data) .with_init_buffer_bm("Brickmap Unpack", &brickmap_upload_data)
.set_usage( .set_usage(
wgpu::BufferUsages::STORAGE wgpu::BufferUsages::STORAGE
@ -119,13 +101,10 @@ impl BrickmapManager {
brickmap_cache, brickmap_cache,
shading_table_allocator, shading_table_allocator,
unpack_max_count: max_uploaded_brickmaps as usize, unpack_max_count: max_uploaded_brickmaps as usize,
brickgrid_staged,
brickmap_staged, brickmap_staged,
state_buffer: buffers.remove(0), state_buffer: buffers.remove(0),
brickgrid_buffer: buffers.remove(0),
shading_table_buffer: buffers.remove(0), shading_table_buffer: buffers.remove(0),
brickgrid_unpack_buffer: buffers.remove(0),
brickmap_unpack_buffer: buffers.remove(0), brickmap_unpack_buffer: buffers.remove(0),
feedback_buffer: buffers.remove(0), feedback_buffer: buffers.remove(0),
feedback_result_buffer: buffers.remove(0), feedback_result_buffer: buffers.remove(0),
@ -133,7 +112,7 @@ impl BrickmapManager {
} }
pub fn get_brickgrid_buffer(&self) -> &wgpu::Buffer { pub fn get_brickgrid_buffer(&self) -> &wgpu::Buffer {
&self.brickgrid_buffer self.brickgrid.get_buffer()
} }
pub fn get_worldstate_buffer(&self) -> &wgpu::Buffer { pub fn get_worldstate_buffer(&self) -> &wgpu::Buffer {
@ -161,7 +140,7 @@ impl BrickmapManager {
} }
pub fn get_brickgrid_unpack_buffer(&self) -> &wgpu::Buffer { 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 { 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. // empty. We don't need to upload it, just mark the relevant brickgrid entry.
if albedo_data.is_empty() { if albedo_data.is_empty() {
if let Some(entry) = self.update_brickgrid_element(grid_idx, 0) { 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 // The brickgrid element had a brickmap entry so we need to unload it's
// shading data // shading data
if let Err(e) = self if let Err(e) = self
@ -241,6 +221,7 @@ impl BrickmapManager {
BrickgridFlag::Loaded, 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 // The brickgrid element had a brickmap entry so we need to unload it's
// shading data // shading data
if let Err(e) = self if let Err(e) = self
@ -273,50 +254,20 @@ impl BrickmapManager {
fn update_brickgrid_element(&mut self, index: usize, data: u32) -> Option<BrickmapCacheEntry> { fn update_brickgrid_element(&mut self, index: usize, data: u32) -> Option<BrickmapCacheEntry> {
let mut brickmap_cache_entry = None; let mut brickmap_cache_entry = None;
if (self.brickgrid[index] & 0xF) == 4 { let current = self.brickgrid.get(index);
let cache_index = (self.brickgrid[index] >> 8) as usize; if current.get_flag() == BrickgridFlag::Loaded {
let cache_index = current.get_pointer();
brickmap_cache_entry = self.brickmap_cache.get_entry(cache_index); brickmap_cache_entry = self.brickmap_cache.get_entry(cache_index);
} }
// We're safe to overwrite the CPU brickgrid and mark for GPU upload now // We're safe to overwrite the CPU brickgrid and mark for GPU upload now
self.brickgrid[index] = data; self.brickgrid.set(index, BrickgridElement(data));
self.brickgrid_staged.insert(index);
brickmap_cache_entry brickmap_cache_entry
} }
// TODO: Tidy this up more // TODO: Tidy this up more
fn upload_unpack_buffers(&mut self, context: &gfx::Context) { fn upload_unpack_buffers(&mut self, context: &gfx::Context) {
// Brickgrid self.brickgrid.upload(context);
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()),
);
// Brickmap // Brickmap
let end = self.unpack_max_count.min(self.brickmap_staged.len()); let end = self.unpack_max_count.min(self.brickmap_staged.len());

View File

@ -1,3 +1,4 @@
mod brickgrid;
mod brickmap; mod brickmap;
mod brickmap_cache; mod brickmap_cache;
mod shading_table; mod shading_table;

View File

@ -1,6 +1,6 @@
use crate::voxel::world::{Voxel, WorldManager}; use crate::voxel::world::{Voxel, WorldManager};
use super::brickmap::BrickgridFlag; use super::brickgrid::BrickgridFlag;
pub fn cull_interior_voxels( pub fn cull_interior_voxels(
world: &mut WorldManager, world: &mut WorldManager,