diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index ed6544eb8c..740a649dd8 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -23,7 +23,7 @@ struct TerrainChunk { struct ChunkMeshState { pos: Vec2, started_tick: u64, - active_worker: bool, + active_worker: Option, } /// A type produced by mesh worker threads corresponding to the position and mesh of a chunk. @@ -129,7 +129,7 @@ impl Terrain { ChunkMeshState { pos, started_tick: current_tick, - active_worker: false, + active_worker: None, }, ); } @@ -147,8 +147,16 @@ impl Terrain { .mesh_todo .values_mut() // Only spawn workers for meshing jobs without an active worker already. - .filter(|todo| !todo.active_worker) + .filter(|todo| { + todo.active_worker + .map(|worker_tick| worker_tick < todo.started_tick) + .unwrap_or(true) + }) { + if client.thread_pool().queued_count() > 0 { + break; + } + // Find the area of the terrain we want. Because meshing needs to compute things like // ambient occlusion and edge elision, we also need the borders of the chunk's // neighbours too (hence the `- 1` and `+ 1`). @@ -189,16 +197,17 @@ impl Terrain { let pos = todo.pos; // Queue the worker thread. + let started_tick = todo.started_tick; client.thread_pool().execute(move || { let _ = send.send(mesh_worker( pos, (min_z as f32, max_z as f32), - current_tick, + started_tick, volume, aabb, )); }); - todo.active_worker = true; + todo.active_worker = Some(todo.started_tick); } // Receive a chunk mesh from a worker thread and upload it to the GPU, then store it. @@ -208,7 +217,7 @@ impl Terrain { match self.mesh_todo.get(&response.pos) { // It's the mesh we want, insert the newly finished model into the terrain model // data structure (convert the mesh to a model first of course). - Some(todo) if response.started_tick == todo.started_tick => { + Some(todo) if response.started_tick <= todo.started_tick => { self.chunks.insert( response.pos, TerrainChunk { @@ -230,7 +239,9 @@ impl Terrain { }, ); - self.mesh_todo.remove(&response.pos); + if response.started_tick == todo.started_tick { + self.mesh_todo.remove(&response.pos); + } } // Chunk must have been removed, or it was spawned on an old tick. Drop the mesh // since it's either out of date or no longer needed.