Moved node buffer logic to Nodes struct

This commit is contained in:
Piotrek
2021-05-16 14:25:03 +02:00
parent 77c74be02f
commit 57e1a9134e
5 changed files with 93 additions and 59 deletions
-1
View File
@@ -104,7 +104,6 @@ impl Game {
}
// Send dirty chunks to renderer
// TODO: Only send chunks in rendering range
// TODO: Unload chunks above certain radius
self.world.update();
for (pos, chunk) in self.world.all_chunks() {
+28 -56
View File
@@ -4,17 +4,15 @@ use std::convert::TryInto;
use cgmath::Vector3;
use std::cmp::{min, max};
use crate::game::world::block::WorldBlock;
use super::nodes::{Nodes, NODE_TEX_SIZE, NODE_TEX_SIZE_QB};
//note: remember to update in main.frag
pub const BLOCK_SIZE : usize = 32; // 32x32x32 block size
pub const BLOCK_TEX_SIZE : usize = 40; // number of blocks in texture (32^3 = 1GB, 40^3 = 2GB)
pub const NODE_TEX_SIZE: usize = 128; // 32x32x32 nodes in texture
const BLOCK_SIZE_QB: usize = BLOCK_SIZE*BLOCK_SIZE*BLOCK_SIZE;
const BLOCK_TEX_SIZE_SQ: usize = BLOCK_TEX_SIZE*BLOCK_TEX_SIZE;
const BLOCK_TEX_SIZE_QB: usize = BLOCK_TEX_SIZE*BLOCK_TEX_SIZE*BLOCK_TEX_SIZE;
const NODE_TEX_SIZE_SQ: usize = NODE_TEX_SIZE*NODE_TEX_SIZE;
const NODE_TEX_SIZE_QB: usize = NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE;
pub struct ContentStats {
pub node_tex_size: f64, // MB
@@ -26,9 +24,8 @@ pub struct ContentStats {
}
pub struct Content {
node_buffer: Box<[u32]>,
nodes: Nodes,
node_texture: wgpu::Texture,
node_dirty: bool,
block_freed: Vec<u32>,
block_freeidx: usize,
block_texture: wgpu::Texture,
@@ -39,9 +36,6 @@ pub struct Content {
impl Content {
pub fn new(device: &wgpu::Device) -> Self {
// Create node buffer
let node_buffer = vec![0_u32; (NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE) as usize].into_boxed_slice();
// Create textures
let node_texture = device.create_texture(
&wgpu::TextureDescriptor {
@@ -87,10 +81,11 @@ impl Content {
);
// Done
let nodes = Nodes::new();
let block_freeidx = 0;
let node_dirty = false;
let block_freed = Vec::new();
Self { node_buffer, node_dirty, block_freed, node_texture, block_freeidx, block_texture, bind_layout, bind_group }
Self { nodes, block_freed, node_texture, block_freeidx, block_texture, bind_layout, bind_group }
}
pub fn stats(&self) -> ContentStats {
@@ -115,7 +110,7 @@ impl Content {
// Get node
let index = (block_pos.x + NODE_TEX_SIZE as i32 * (block_pos.y + NODE_TEX_SIZE as i32 * block_pos.z)) as usize;
let mut value = self.node_buffer[index] as usize;
let mut value = self.nodes.get_node(index) as usize;
// Allocate new block
if value == 0 {
@@ -127,10 +122,8 @@ impl Content {
}
// Assign
self.node_buffer[index] = value as u32;
self.block_freeidx = value;
// Mark node buffer as dirty
self.node_dirty = true;
self.nodes.set_node(index, value as u32);
}
// Calculate position in block texture
@@ -152,54 +145,33 @@ impl Content {
}
pub fn shift(&mut self, offset: &Vector3<i32>) {
let timer = Instant::now();
let mut result = vec![0_u32; self.node_buffer.len()].into_boxed_slice();
let (ox, oy, oz) = (offset.x, offset.y, offset.z);
let size = NODE_TEX_SIZE as i32;
// let timer = Instant::now();
// let mut result = vec![0_u32; self.node_buffer.len()].into_boxed_slice();
// let (ox, oy, oz) = (offset.x, offset.y, offset.z);
// let size = NODE_TEX_SIZE as i32;
let a = max(0, -oz);
let b = min(size-oz, size);
println!("from {} to {}", a, b);
// let a = max(0, -oz);
// let b = min(size-oz, size);
// println!("from {} to {}", a, b);
for x in max(0, -ox)..min(size-ox, size) {
for y in max(0, -oy)..min(size-oy, size) {
for z in max(0, -oz)..min(size-oz, size) {
let idx0 = x + size * (y + size * z);
let idx1 = (x+ox) + size * ((y+oy) + size * (z+oz));
result[idx1 as usize] = self.node_buffer[idx0 as usize];
}
}
// for x in max(0, -ox)..min(size-ox, size) {
// for y in max(0, -oy)..min(size-oy, size) {
// for z in max(0, -oz)..min(size-oz, size) {
// let idx0 = x + size * (y + size * z);
// let idx1 = (x+ox) + size * ((y+oy) + size * (z+oz));
// result[idx1 as usize] = self.node_buffer[idx0 as usize];
// }
// }
// }
// self.node_buffer = result;
// self.node_dirty = true;
// println!("Shifted node buffer by {:?} in {} ms", offset, timer.elapsed().as_millis());
}
self.node_buffer = result;
self.node_dirty = true;
println!("Shifted node buffer by {:?} in {} ms", offset, timer.elapsed().as_millis());
}
fn write_nodes(&mut self, queue: &wgpu::Queue, z: usize) {
// Convert u32 node buffer to u8
let node_origin = wgpu::Origin3d{ x:0, y: 0, z: z as u32 };
let node_size = wgpu::Extent3d { width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: 1 };
let mut node_bytes = [0_u8; NODE_TEX_SIZE_SQ*4];
let offset = NODE_TEX_SIZE_SQ*z;
LittleEndian::write_u32_into(&self.node_buffer[offset..offset+NODE_TEX_SIZE_SQ], &mut node_bytes);
// Write nodes
queue.write_texture(
wgpu::TextureCopyView { texture: &self.node_texture, mip_level: 0, origin: node_origin }, &node_bytes,
wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4*node_size.width, rows_per_image: node_size.height }, node_size
);
}
pub fn update(&mut self, queue: &wgpu::Queue) {
if self.node_dirty {
self.node_dirty = false;
let timer = Instant::now();
for z in 0..NODE_TEX_SIZE {
self.write_nodes(queue, z);
}
println!("Write nodes: {}", timer.elapsed().as_secs_f32());
}
self.nodes.update(queue, &self.node_texture);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ pub mod content;
pub use content::Content;
mod materials;
pub use materials::Materials;
pub mod nodes;
pub struct Buffers {
pub uniforms: Uniform,
+63
View File
@@ -0,0 +1,63 @@
use byteorder::{LittleEndian, ByteOrder};
pub const NODE_TEX_SIZE: usize = 128; // 32x32x32 nodes in texture
pub const NODE_TEX_SIZE_SQ: usize = NODE_TEX_SIZE*NODE_TEX_SIZE;
pub const NODE_TEX_SIZE_QB: usize = NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE;
pub struct Nodes {
node_buffer_a: Box<[u32]>,
node_buffer_b: Box<[u32]>,
active_buffer: u8,
modified: bool
}
impl Nodes {
pub fn new() -> Self {
Self {
node_buffer_a: vec![0_u32; NODE_TEX_SIZE_QB].into_boxed_slice(),
node_buffer_b: vec![0_u32; NODE_TEX_SIZE_QB].into_boxed_slice(),
active_buffer: 0,
modified: false
}
}
pub fn get_node(&self, index: usize) -> u32 {
if self.active_buffer == 0 { self.node_buffer_a[index] }
else { self.node_buffer_b[index] }
}
pub fn set_node(&mut self, index: usize, value: u32) {
if self.active_buffer == 0 { self.node_buffer_a[index] = value; }
else { self.node_buffer_b[index] = value; }
self.modified = true;
}
pub fn update(&mut self, queue: &wgpu::Queue, texture: &wgpu::Texture) {
if self.modified {
self.modified = false;
// Select target node buffer
let node_buffer;
if self.active_buffer == 0 { node_buffer = &self.node_buffer_a; }
else { node_buffer = &self.node_buffer_b; }
// Write all nodes to gpu
for z in 0..NODE_TEX_SIZE {
// Convert u32 node buffer to u8
let node_origin = wgpu::Origin3d{ x:0, y: 0, z: z as u32 };
let node_size = wgpu::Extent3d { width: NODE_TEX_SIZE as u32, height: NODE_TEX_SIZE as u32, depth: 1 };
let mut node_bytes = [0_u8; NODE_TEX_SIZE_SQ*4];
let offset = NODE_TEX_SIZE_SQ*z;
LittleEndian::write_u32_into(&node_buffer[offset..offset+NODE_TEX_SIZE_SQ], &mut node_bytes);
// Write nodes
queue.write_texture(
wgpu::TextureCopyView { texture: texture, mip_level: 0, origin: node_origin }, &node_bytes,
wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4*node_size.width, rows_per_image: node_size.height }, node_size
);
}
}
}
}
+1 -1
View File
@@ -117,7 +117,7 @@ impl Renderer {
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
// Update uniform buffer
let half = (buffers::content::NODE_TEX_SIZE / 2) as i32;
let half = (buffers::nodes::NODE_TEX_SIZE / 2) as i32;
let offset = Vector3{x: (self.world_offset.x + half) as f32, y: (self.world_offset.y + half) as f32, z: (self.world_offset.z + half) as f32 };
self.buffers.uniforms.values.update(&self.camera, offset, self.start.elapsed().as_secs_f32());