Extract brickgrid to module
This commit is contained in:
parent
03a74d1b02
commit
c26f3c8ffb
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod brickgrid;
|
||||||
mod brickmap;
|
mod brickmap;
|
||||||
mod brickmap_cache;
|
mod brickmap_cache;
|
||||||
mod shading_table;
|
mod shading_table;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue