From a09f446ecde5ecc75a3d9100baa85d8a58016c67 Mon Sep 17 00:00:00 2001 From: Piotrek Date: Mon, 10 May 2021 15:36:11 +0200 Subject: [PATCH] Pausing rendering, warnings cleanup, more statistics --- Cargo.lock | 50 ++++++++++++++++++------------------- Cargo.toml | 2 +- src/game/mod.rs | 13 +++++++--- src/game/world/block.rs | 3 --- src/game/world/chunk.rs | 24 +++++++----------- src/game/world/generator.rs | 2 +- src/game/world/mod.rs | 10 +++----- src/main.rs | 18 +++++++------ src/renderer/mod.rs | 9 ++++++- src/renderer/ui.rs | 32 ++++++++++++------------ 10 files changed, 84 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ce589b..c6f757b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,30 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "VoxelGame" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytemuck", - "byteorder", - "cgmath", - "dirs", - "flate2", - "fs_extra", - "futures", - "glob", - "image", - "linked-hash-map", - "lzzzz", - "noise", - "rand 0.8.3", - "shaderc", - "wgpu", - "wgpu_glyph", - "winit", - "yaml-rust", -] - [[package]] name = "ab_glyph" version = "0.2.10" @@ -2058,6 +2033,31 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "voxel_game" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytemuck", + "byteorder", + "cgmath", + "dirs", + "flate2", + "fs_extra", + "futures", + "glob", + "image", + "linked-hash-map", + "lzzzz", + "noise", + "rand 0.8.3", + "shaderc", + "wgpu", + "wgpu_glyph", + "winit", + "yaml-rust", +] + [[package]] name = "walkdir" version = "2.3.2" diff --git a/Cargo.toml b/Cargo.toml index 056ed3e..c7a4f6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "VoxelGame" +name = "voxel_game" version = "0.1.0" authors = ["Piotrek "] edition = "2018" diff --git a/src/game/mod.rs b/src/game/mod.rs index 4760c33..f652b7c 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -3,7 +3,7 @@ mod player; pub mod world; use std::time::Instant; use crate::renderer::content_view::ContentView; -use cgmath::{SquareMatrix, Point3, InnerSpace}; +use cgmath::Point3; use winit::event::Event; use crate::renderer::{camera::CameraTransform}; use player::Player; @@ -16,6 +16,7 @@ pub enum GameState { } pub struct Game { + state: GameState, player: Player, world: World } @@ -23,6 +24,7 @@ pub struct Game { impl Game { pub fn new(content: &mut dyn ContentView) -> Self { let mut app = Self { + state: GameState::Paused, player: Player::new(), world: World::new("default".to_string()) }; @@ -62,7 +64,7 @@ impl Game { self.player.camera_controller.handle_input(event); } - pub fn update_state(&mut self, requested_state: GameState) -> GameState { + pub fn update_state(&mut self, requested_state: GameState) -> &GameState { match requested_state { GameState::Paused => { self.player.camera_controller.set_enabled(false); @@ -73,7 +75,12 @@ impl Game { }; // Currently we are not preventing any state changes, just return requested state - requested_state + self.state = requested_state; + &self.state + } + + pub fn get_state(&self) -> &GameState { + &self.state } pub fn update_camera(&mut self, delta: f32, camera_transform: &mut dyn CameraTransform) { diff --git a/src/game/world/block.rs b/src/game/world/block.rs index 8d2a9e8..fb96597 100644 --- a/src/game/world/block.rs +++ b/src/game/world/block.rs @@ -1,7 +1,4 @@ use cgmath::Point3; -use std::iter::FromIterator; -use std::io::Write; -use flate2::{write::DeflateEncoder, Compression}; pub const SIZE: usize = 32; pub const SIZE_QB: usize = SIZE*SIZE*SIZE; diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs index 30164d5..c98a37a 100644 --- a/src/game/world/chunk.rs +++ b/src/game/world/chunk.rs @@ -1,20 +1,20 @@ -use std::time::Instant; -use flate2::Compression; -use flate2::write::DeflateEncoder; -use flate2::read::DeflateDecoder; use byteorder::LittleEndian; use byteorder::ByteOrder; use cgmath::Point3; -use std::io::Write; -use std::convert::TryInto; use lzzzz::lz4; -use std::io::Read; use crate::game::world::{WorldBlock, block}; pub const SIZE: usize = 32; const SIZE_SQ: usize = SIZE*SIZE; const SIZE_QB: usize = SIZE*SIZE*SIZE; +// 1 chunk times on i7-5930K +// alg | size | compr | decom +// raw 32.89kB 0.06s 1.19s +// deflate fast 1.23kB 1.22s 5.46s +// lz4 1.6kB 0.07s 1.23s + + pub struct WorldChunk { nodes: Box<[u32]>, blocks: Vec @@ -30,15 +30,15 @@ impl WorldChunk { pub fn from_bytes(bytes: Vec) -> Self { let mut instance = Self::new(); - let (header_bytes, bytes) = bytes.split_at(128); - let (node_bytes, block_bytes_compressed) = bytes.split_at((SIZE_QB*4) as usize); // Header + let (header_bytes, bytes) = bytes.split_at(128); let file_ver = header_bytes[0]; let num_blocks = LittleEndian::read_u32(&header_bytes[1..5]) as usize; assert_eq!(file_ver, 1); // Nodes + let (node_bytes, block_bytes_compressed) = bytes.split_at((SIZE_QB*4) as usize); for i in 0..SIZE_QB { let idx = (i*4) as usize; let val = u32::from_le_bytes([node_bytes[idx], node_bytes[idx+1], node_bytes[idx+2], node_bytes[idx+3]]); @@ -79,12 +79,6 @@ impl WorldChunk { } lz4::compress_to_vec(&buf, &mut bytes, lz4::ACC_LEVEL_DEFAULT).unwrap(); - - // alg | size | compr | decom - // raw 32.89kB 0.06s 1.19s - // deflate fast 1.23kB 1.22s 5.46s - // lz4 1.6kB 0.07s 1.23s - bytes } diff --git a/src/game/world/generator.rs b/src/game/world/generator.rs index c0990d8..afae184 100644 --- a/src/game/world/generator.rs +++ b/src/game/world/generator.rs @@ -44,7 +44,7 @@ impl WorldGen { let noise = Perlin::new(); // Generate height map - let (map, max) = WorldGen::gen_height_map(block_pos.x as usize, block_pos.z as usize, &mut rng, &noise); + let (map, _max) = WorldGen::gen_height_map(block_pos.x as usize, block_pos.z as usize, &mut rng, &noise); // Fill for x in 0..block::SIZE { diff --git a/src/game/world/mod.rs b/src/game/world/mod.rs index ad046f4..85b3a6a 100644 --- a/src/game/world/mod.rs +++ b/src/game/world/mod.rs @@ -1,19 +1,17 @@ mod generator; pub mod chunk; pub mod block; -use std::time::Instant; use linked_hash_map::LinkedHashMap; use std::path::PathBuf; -use std::path::Path; use std::io::Write; use std::io::Read; use std::fs; -use cgmath::{Point3, InnerSpace}; +use cgmath::Point3; use std::collections::HashMap; use generator::WorldGen; use chunk::WorldChunk; use block::WorldBlock; -use yaml_rust::{Yaml, YamlLoader, YamlEmitter}; +use yaml_rust::{Yaml, YamlEmitter}; pub struct World { @@ -101,7 +99,7 @@ impl World { file.read_to_end(&mut bytes).expect("Failed to read file"); let chunk = WorldChunk::from_bytes(bytes); - println!("loaded {:?}", pos); + println!("Load: Chunk {}, {}, {}", pos.x, pos.y, pos.z); self.chunks.insert(pos, chunk); count += 1; } @@ -117,7 +115,7 @@ impl World { // Create chunk if does not exist if let None = self.chunks.get(&ch_pos) { self.chunks.insert(ch_pos.clone(), WorldChunk::new()); - println!("Alloc chunk [{}, {}, {}]", ch_pos.x, ch_pos.y, ch_pos.z); + println!("Alloc: Chunk [{}, {}, {}]", ch_pos.x, ch_pos.y, ch_pos.z); } // Generate block for chunk let chunk = self.chunks.get_mut(&ch_pos).unwrap(); diff --git a/src/main.rs b/src/main.rs index c371891..77e3240 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,7 @@ fn main() { .expect("Failed to create window"); let mut renderer = Renderer::new(&window); - let mut app = Game::new(&mut renderer); + let mut game = Game::new(&mut renderer); // Stats let mut fps_timer = std::time::Instant::now(); @@ -34,7 +34,7 @@ fn main() { // Run event loop events.run(move |ev, _, c| { // App input - app.input(&ev); + game.input(&ev); // Other match ev { @@ -46,7 +46,7 @@ fn main() { // Escape key WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. }, .. } => { // Request pause - if let GameState::Paused = app.update_state(GameState::Paused) { + if let GameState::Paused = game.update_state(GameState::Paused) { window.set_cursor_grab(false).unwrap(); window.set_cursor_visible(true); } @@ -54,7 +54,7 @@ fn main() { // Window clicked WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => { // Request unpause - if let GameState::Running = app.update_state(GameState::Running) { + if let GameState::Running = game.update_state(GameState::Running) { window.set_cursor_grab(true).unwrap(); window.set_cursor_visible(false); } @@ -73,11 +73,13 @@ fn main() { Event::MainEventsCleared => { // Update let delta = delta_timer.elapsed().as_secs_f32(); - app.update_camera(delta, &mut renderer.camera); + game.update_camera(delta, &mut renderer.camera); delta_timer = std::time::Instant::now(); - // Redraw - window.request_redraw(); + // Redraw if running + if let GameState::Running = game.get_state() { + window.request_redraw(); + } } // Draw Event::RedrawRequested(_) => { @@ -87,7 +89,7 @@ fn main() { if elapsed >= 0.5 { let mut fps = (fps_counter as f64) / elapsed; fps = (fps*100.0_f64).floor() / 100.0; - renderer.ui.set_fps(fps as f32); + renderer.ui.set_text(0, format!("FPS: {}", fps)); fps_timer = std::time::Instant::now(); fps_counter = 0; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 4b8a37f..d266e43 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,4 +1,4 @@ -use wgpu_glyph::Text; +use std::time::Instant; use winit::{window::Window, dpi::PhysicalSize}; pub mod buffers; use buffers::Buffers; @@ -118,10 +118,14 @@ impl Renderer { self.queue.write_buffer(&self.buffers.uniforms.buffer, 0, bytemuck::cast_slice(&[self.buffers.uniforms.values])); // Update content + let timer = Instant::now(); self.buffers.content.update(&self.queue); + self.ui.set_text(2, format!("Update content: {}ms", timer.elapsed().as_micros() as f64 / 1000.0)); // Get next frame to render to + let timer = Instant::now(); let frame = self.swapchain.get_current_frame()?.output; + self.ui.set_text(3, format!("Swapchain get frame: {}ms", timer.elapsed().as_micros() as f64 / 1000.0)); // Create encoder that will build command buffer for us let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"),}); @@ -130,7 +134,10 @@ impl Renderer { self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720); // Submit encoder (command buffer) + let timer = Instant::now(); self.queue.submit(std::iter::once(encoder.finish())); + self.ui.set_text(4, format!("Submit queue: {}ms", timer.elapsed().as_micros() as f64 / 1000.0)); + self.ui.recall(); // Return ok diff --git a/src/renderer/ui.rs b/src/renderer/ui.rs index a1c6614..6665358 100644 --- a/src/renderer/ui.rs +++ b/src/renderer/ui.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use wgpu_glyph::{GlyphBrush, ab_glyph::FontArc, GlyphBrushBuilder, Section, Text}; use wgpu::util::StagingBelt; use futures::executor::LocalPool; @@ -11,7 +12,7 @@ pub struct UserInterface { local_pool: LocalPool, brush: GlyphBrush<()>, // Texts - fps_text: String + texts: HashMap } impl UserInterface { @@ -22,27 +23,26 @@ impl UserInterface { staging_belt: StagingBelt::new(1024), local_pool: LocalPool::new(), brush: GlyphBrushBuilder::using_font(font).build(device, render_format), - fps_text: "-".to_string() + texts: HashMap::new() } } - fn print(&mut self, x: u32, y: u32, msg: &str) { - let text = Text::new(msg).with_color(WHITE); - self.brush.queue(Section { - screen_position: (x as f32, y as f32), - bounds: (text.scale.x * text.text.len() as f32, text.scale.y), - text: vec![text], - ..Section::default() - }); - } - - pub fn set_fps(&mut self, fps: f32) { - self.fps_text = format!("FPS: {}", fps); + pub fn set_text(&mut self, index: u32, text: String) { + self.texts.insert(index, text); } pub fn render(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, width: u32, height: u32) { - // Print texts - self.print(5, 5, &self.fps_text.clone()); + for (id, text) in self.texts.iter() { + + let text = Text::new(text).with_color(WHITE); + self.brush.queue(Section { + screen_position: (5 as f32, (5 + id*15) as f32), + bounds: (text.scale.x * text.text.len() as f32, text.scale.y), + text: vec![text], + ..Section::default() + }); + } + // Draw self.brush.draw_queued(&device, &mut self.staging_belt, encoder, target, width, height).expect("Draw queued"); self.staging_belt.finish();