Update more than 1 chunk per frame if the framerate allows

This commit is contained in:
Sijmen 2021-06-06 13:34:57 +02:00
parent 4bba01058b
commit 0e53db6ffc
Signed by: vijfhoek
GPG key ID: 82D05C89B28B0DAE
7 changed files with 429 additions and 112 deletions

287
Cargo.lock generated
View file

@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff"
[[package]]
name = "adler"
version = "1.0.2"
@ -38,6 +44,19 @@ dependencies = [
"memchr",
]
[[package]]
name = "andrew"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf"
dependencies = [
"bitflags",
"rusttype",
"walkdir",
"xdg",
"xml-rs",
]
[[package]]
name = "anyhow"
version = "1.0.40"
@ -65,7 +84,7 @@ version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06063a002a77d2734631db74e8f4ce7148b77fe522e6bca46f2ae7774fd48112"
dependencies = [
"libloading",
"libloading 0.7.0",
]
[[package]]
@ -150,6 +169,16 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "calloop"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c"
dependencies = [
"log",
"nix 0.18.0",
]
[[package]]
name = "cc"
version = "1.0.68"
@ -406,7 +435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091ed1b25fe47c7ff129fc440c23650b6114f36aa00bc7212cc8041879294428"
dependencies = [
"bitflags",
"libloading",
"libloading 0.7.0",
"winapi",
]
@ -472,6 +501,30 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dlib"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76"
dependencies = [
"libloading 0.6.7",
]
[[package]]
name = "dlib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
dependencies = [
"libloading 0.7.0",
]
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "either"
version = "1.6.1"
@ -674,7 +727,7 @@ dependencies = [
"bitflags",
"gfx-auxil",
"gfx-hal",
"libloading",
"libloading 0.7.0",
"log",
"parking_lot",
"range-alloc",
@ -732,7 +785,7 @@ dependencies = [
"glow",
"js-sys",
"khronos-egl",
"libloading",
"libloading 0.7.0",
"log",
"naga",
"parking_lot",
@ -981,9 +1034,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
@ -1050,7 +1100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
dependencies = [
"libc",
"libloading",
"libloading 0.7.0",
]
[[package]]
@ -1065,6 +1115,16 @@ version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
[[package]]
name = "libloading"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
dependencies = [
"cfg-if 1.0.0",
"winapi",
]
[[package]]
name = "libloading"
version = "0.7.0"
@ -1114,6 +1174,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memmap2"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.6.4"
@ -1276,6 +1345,30 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
[[package]]
name = "nix"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055"
dependencies = [
"bitflags",
"cc",
"cfg-if 0.1.10",
"libc",
]
[[package]]
name = "nix"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
]
[[package]]
name = "noise"
version = "0.7.0"
@ -1287,6 +1380,16 @@ dependencies = [
"rand_xorshift",
]
[[package]]
name = "nom"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
dependencies = [
"memchr",
"version_check",
]
[[package]]
name = "ntapi"
version = "0.3.6"
@ -1394,6 +1497,15 @@ version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "owned_ttf_parser"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3"
dependencies = [
"ttf-parser",
]
[[package]]
name = "parking_lot"
version = "0.11.1"
@ -1653,12 +1765,37 @@ dependencies = [
"serde",
]
[[package]]
name = "rusttype"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
@ -1748,6 +1885,25 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "smithay-client-toolkit"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80"
dependencies = [
"andrew",
"bitflags",
"calloop",
"dlib 0.4.2",
"lazy_static",
"log",
"memmap2",
"nix 0.18.0",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
[[package]]
name = "spirv_cross"
version = "0.23.1"
@ -1850,6 +2006,12 @@ dependencies = [
"serde",
]
[[package]]
name = "ttf-parser"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
name = "unicode-width"
version = "0.1.8"
@ -1868,6 +2030,17 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@ -1946,6 +2119,79 @@ version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "wayland-client"
version = "0.28.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ca44d86554b85cf449f1557edc6cc7da935cc748c8e4bf1c507cbd43bae02c"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix 0.20.0",
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
name = "wayland-commons"
version = "0.28.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bd75ae380325dbcff2707f0cd9869827ea1d2d6d534cff076858d3f0460fd5a"
dependencies = [
"nix 0.20.0",
"once_cell",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-cursor"
version = "0.28.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b37e5455ec72f5de555ec39b5c3704036ac07c2ecd50d0bffe02d5fe2d4e65ab"
dependencies = [
"nix 0.20.0",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.28.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95df3317872bcf9eec096c864b69aa4769a1d5d6291a5b513f8ba0af0efbd52c"
dependencies = [
"bitflags",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.28.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389d680d7bd67512dc9c37f39560224327038deb0f0e8d33f870900441b68720"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.28.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2907bd297eef464a95ba9349ea771611771aa285b932526c633dc94d5400a8e2"
dependencies = [
"dlib 0.5.0",
"lazy_static",
"pkg-config",
]
[[package]]
name = "web-sys"
version = "0.3.50"
@ -2078,8 +2324,8 @@ dependencies = [
"percent-encoding",
"raw-window-handle",
"scopeguard",
"wasm-bindgen",
"web-sys",
"smithay-client-toolkit",
"wayland-client",
"winapi",
"x11-dl",
]
@ -2105,6 +2351,27 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "xcursor"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08"
dependencies = [
"nom",
]
[[package]]
name = "xdg"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
[[package]]
name = "xml-rs"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
[[package]]
name = "zstd"
version = "0.5.4+zstd.1.4.7"

View file

@ -18,7 +18,7 @@ log = "0.4.14"
noise = "0.7.0"
rayon = "1.5.1"
wgpu = "0.8.1"
winit = { version = "0.25.0", default_features = false, features = ["x11", "web-sys"] }
winit = { version = "0.25.0" }
serde_repr = "0.1.7"
rmp-serde = "0.15.4"
itertools = "0.10.0"

View file

@ -5,6 +5,7 @@ mod geometry;
mod npc;
mod quad;
mod render_context;
mod renderable;
mod state;
mod text_renderer;
mod texture;
@ -156,25 +157,32 @@ fn main() {
frametime_max = Duration::from_secs(0);
}
let dt = last_render_time.elapsed();
let now = Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Err(root_cause) => match root_cause.downcast_ref::<SwapChainError>() {
// Recreate the swap_chain if lost
Some(wgpu::SwapChainError::Lost) => state.resize(state.window_size),
// The system is out of memory, we should probably quit
Some(wgpu::SwapChainError::OutOfMemory) => {
*control_flow = ControlFlow::Exit
}
// All other errors (Outdated, Timeout) should be resolved by the next frame
Some(_) | None => eprintln!("{:?}", root_cause),
},
let render_time = match state.render() {
Err(root_cause) => {
match root_cause.downcast_ref::<SwapChainError>() {
// Recreate the swap_chain if lost
Some(wgpu::SwapChainError::Lost) => state.resize(state.window_size),
// The system is out of memory, we should probably quit
Some(wgpu::SwapChainError::OutOfMemory) => {
*control_flow = ControlFlow::Exit
}
// All other errors (Outdated, Timeout) should be resolved by the next frame
Some(_) | None => eprintln!("{:?}", root_cause),
};
return;
}
Ok(v) => triangle_count = v,
}
Ok((triangle_count_, render_time)) => {
triangle_count = triangle_count_;
render_time
}
};
state.update(dt, render_time);
}
Event::MainEventsCleared => {
// RedrawRequested will only trigger once, unless we manually

16
src/renderable.rs Normal file
View file

@ -0,0 +1,16 @@
use std::time::Duration;
use wgpu::RenderPass;
use crate::{camera::Camera, render_context::RenderContext, view::View};
pub trait Renderable {
fn update(
&mut self,
render_context: &RenderContext,
dt: Duration,
render_time: Duration,
camera: &Camera,
);
fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize;
}

View file

@ -1,7 +1,7 @@
pub mod hud_state;
pub mod world_state;
use std::time::Duration;
use std::time::{Duration, Instant};
use cgmath::EuclideanSpace;
use winit::{
@ -189,30 +189,36 @@ impl State {
}
}
pub fn update(&mut self, dt: Duration) {
self.world_state.update(dt, &self.render_context);
pub fn update(&mut self, dt: Duration, render_time: Duration) {
self.world_state
.update(dt, render_time, &self.render_context);
self.hud_state.update(
&self.render_context,
&self.world_state.camera.position.to_vec(),
);
}
pub fn render(&mut self) -> anyhow::Result<usize> {
let frame = self.render_context.swap_chain.get_current_frame()?.output;
pub fn render(&mut self) -> anyhow::Result<(usize, Duration)> {
let render_start = Instant::now();
let mut render_encoder = self
.render_context
.device
.create_command_encoder(&Default::default());
Ok({
let frame = self.render_context.swap_chain.get_current_frame()?.output;
let mut triangle_count = 0;
triangle_count += self.world_state.render(&frame, &mut render_encoder);
triangle_count += self.hud_state.render(&frame, &mut render_encoder)?;
let mut render_encoder = self
.render_context
.device
.create_command_encoder(&Default::default());
self.render_context
.queue
.submit(std::iter::once(render_encoder.finish()));
let mut triangle_count = 0;
triangle_count += self.world_state.render(&frame, &mut render_encoder);
triangle_count += self.hud_state.render(&frame, &mut render_encoder)?;
Ok(triangle_count)
self.render_context
.queue
.submit(std::iter::once(render_encoder.finish()));
let render_time = render_start.elapsed();
(triangle_count, render_time)
})
}
}

View file

@ -13,6 +13,7 @@ use winit::{
use crate::{
camera::{Camera, Projection},
render_context::RenderContext,
renderable::Renderable,
texture::{Texture, TextureManager},
time::Time,
vertex::{BlockVertex, Vertex},
@ -425,10 +426,11 @@ impl WorldState {
}
}
pub fn update(&mut self, dt: Duration, render_context: &RenderContext) {
pub fn update(&mut self, dt: Duration, render_time: Duration, render_context: &RenderContext) {
self.update_position(dt);
self.world.update(dt, render_context, &self.camera);
self.world
.update(render_context, dt, render_time, &self.camera);
self.view
.update_view_projection(&self.camera, &self.projection);

View file

@ -1,11 +1,13 @@
use std::time::Instant;
use std::{collections::VecDeque, time::Duration};
use crate::{
camera::Camera,
chunk::{Block, BlockType, Chunk, CHUNK_ISIZE},
chunk::{self, Block, BlockType, Chunk, CHUNK_ISIZE},
geometry::GeometryBuffers,
npc::Npc,
render_context::RenderContext,
renderable::Renderable,
view::View,
};
use ahash::AHashMap;
@ -31,72 +33,14 @@ pub const WORLD_HEIGHT: isize = 16 * 16 / CHUNK_ISIZE;
const DEBUG_IO: bool = false;
impl World {
pub fn new() -> Self {
let chunks = AHashMap::new();
let npc = Npc::load();
let chunk_database = sled::Config::new()
.path("chunks")
.mode(sled::Mode::HighThroughput)
.use_compression(true)
.open()
.unwrap();
Self {
chunks,
npc,
chunk_database,
chunk_load_queue: VecDeque::new(),
chunk_save_queue: VecDeque::new(),
chunk_generate_queue: VecDeque::new(),
highlighted: None,
unload_timer: Duration::new(0, 0),
}
}
pub fn update(&mut self, dt: Duration, render_context: &RenderContext, camera: &Camera) {
if let Some(position) = self.chunk_load_queue.pop_front() {
let chunk = self.chunks.entry(position).or_default();
match chunk.load(position, &self.chunk_database) {
Err(error) => {
eprintln!("Failed to load/generate chunk {:?}: {:?}", position, error)
}
Ok(true) => {
self.update_chunk_geometry(render_context, position);
self.enqueue_chunk_save(position, false);
if DEBUG_IO {
println!("Generated chunk {:?}", position);
}
}
Ok(false) => {
self.update_chunk_geometry(render_context, position);
if DEBUG_IO {
println!("Loaded chunk {:?}", position);
}
}
}
} else if let Some((position, unload)) = self.chunk_save_queue.pop_front() {
if let Some(chunk) = self.chunks.get(&position) {
if let Err(err) = chunk.save(position, &self.chunk_database) {
eprintln!("Failed to save chunk {:?}: {:?}", position, err);
} else if unload {
self.chunks.remove(&position);
if DEBUG_IO {
println!("Saved and unloaded chunk {:?}", position);
}
} else if DEBUG_IO {
println!("Saved chunk {:?}", position);
}
} else {
eprintln!("Tried to save unloaded chunk {:?}", position);
}
}
impl Renderable for World {
fn update(
&mut self,
render_context: &RenderContext,
dt: Duration,
render_time: Duration,
camera: &Camera,
) {
self.update_highlight(render_context, camera);
// Queue up new chunks for loading, if necessary
@ -142,9 +86,55 @@ impl World {
self.enqueue_chunk_save(point, true);
}
}
let start = Instant::now() - render_time;
let mut chunk_updates = 0;
while chunk_updates == 0 || start.elapsed() < Duration::from_millis(16) {
if let Some(position) = self.chunk_load_queue.pop_front() {
let chunk = self.chunks.entry(position).or_default();
match chunk.load(position, &self.chunk_database) {
Err(error) => {
eprintln!("Failed to load/generate chunk {:?}: {:?}", position, error)
}
Ok(true) => {
self.update_chunk_geometry(render_context, position);
self.enqueue_chunk_save(position, false);
if DEBUG_IO {
println!("Generated chunk {:?}", position);
}
}
Ok(false) => {
self.update_chunk_geometry(render_context, position);
if DEBUG_IO {
println!("Loaded chunk {:?}", position);
}
}
}
} else if let Some((position, unload)) = self.chunk_save_queue.pop_front() {
if let Some(chunk) = self.chunks.get(&position) {
if let Err(err) = chunk.save(position, &self.chunk_database) {
eprintln!("Failed to save chunk {:?}: {:?}", position, err);
} else if unload {
self.chunks.remove(&position);
if DEBUG_IO {
println!("Saved and unloaded chunk {:?}", position);
}
} else if DEBUG_IO {
println!("Saved chunk {:?}", position);
}
} else {
eprintln!("Tried to save unloaded chunk {:?}", position);
}
} else {
break;
}
chunk_updates += 1;
}
}
pub fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize {
fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize {
let mut triangle_count = 0;
for (position, chunk) in &self.chunks {
@ -166,6 +156,34 @@ impl World {
triangle_count
}
}
impl World {
pub fn new() -> Self {
let chunks = AHashMap::new();
let npc = Npc::load();
let chunk_database = sled::Config::new()
.path("chunks")
.mode(sled::Mode::HighThroughput)
.use_compression(true)
.open()
.unwrap();
Self {
chunks,
npc,
chunk_database,
chunk_load_queue: VecDeque::new(),
chunk_save_queue: VecDeque::new(),
chunk_generate_queue: VecDeque::new(),
highlighted: None,
unload_timer: Duration::new(0, 0),
}
}
pub fn enqueue_chunk_save(&mut self, position: Point3<isize>, unload: bool) {
if let Some((_, unload_)) = self