From 291a424b4ed5b068857e95196f0058504837bfa0 Mon Sep 17 00:00:00 2001 From: Imbris Date: Mon, 27 Jun 2022 04:06:26 -0400 Subject: [PATCH 1/2] This seems to save at least 30 seconds (out of 90 to 120 secs) when tweaking TILE_SIZE in voxygen/src/mesh/greedy.rs (NOTE: I did some more timing, see associated MR description) --- assets/voxygen/voxel/sprite_manifest.ron | 14 ++++++++++---- voxygen/src/scene/terrain.rs | 16 +++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/assets/voxygen/voxel/sprite_manifest.ron b/assets/voxygen/voxel/sprite_manifest.ron index 32a0688b2b..ea021ba90c 100644 --- a/assets/voxygen/voxel/sprite_manifest.ron +++ b/assets/voxygen/voxel/sprite_manifest.ron @@ -1,5 +1,7 @@ #![enable(unwrap_newtypes)] -( +{ +// Represents the lack of a sprite. +Empty: None, // Windows Window1: Some(( variations: [ @@ -1348,7 +1350,7 @@ Ember: Some(( wind_sway: 0.0, )), // Smoke dummy -Smoke: Some(( +SmokeDummy: Some(( variations: [ ( model: "voxygen.voxel.sprite.ember.dummy", @@ -2902,7 +2904,11 @@ GiantKelp: Some(( ], wind_sway: 0.2, )), -//Seagrass +// Red Algae +RedAlgae: None, +// Underwater Vent +UnderwaterVent: None, +// Seagrass Seagrass: Some(( variations: [ ( @@ -3945,4 +3951,4 @@ Eldwood: Some(( ], wind_sway: 0.0, )), -) +} diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index e6504646a5..6857de389b 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -24,7 +24,7 @@ use common::{ assets::{self, AssetExt, DotVoxAsset}, figure::Segment, spiral::Spiral2d, - terrain::{sprite, Block, SpriteKind, TerrainChunk}, + terrain::{Block, SpriteKind, TerrainChunk}, vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol}, volumes::vol_grid_2d::{VolGrid2d, VolGrid2dError}, }; @@ -157,7 +157,7 @@ struct SpriteConfig { /// NOTE: Model is an asset path to the appropriate sprite .vox model. #[derive(Deserialize)] #[serde(transparent)] -struct SpriteSpec(sprite::sprite_kind::PureCases>>); +struct SpriteSpec(HashMap>>); impl assets::Asset for SpriteSpec { type Loader = assets::RonLoader; @@ -236,7 +236,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' continue; }; - if let Some(cfg) = sprite.elim_case_pure(&sprite_config.0) { + if let Some(cfg) = sprite_config.0.get(&sprite).and_then(Option::as_ref) { let seed = wpos.x as u64 * 3 + wpos.y as u64 * 7 + wpos.x as u64 * wpos.y as u64; // Awful PRNG @@ -394,10 +394,16 @@ impl SpriteRenderContext { let max_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32); let mut greedy = GreedyMesh::new(max_size); let mut sprite_mesh = Mesh::new(); - let sprite_config_ = &sprite_config; // NOTE: Tracks the start vertex of the next model to be meshed. let sprite_data: HashMap<(SpriteKind, usize), _> = SpriteKind::into_enum_iter() - .filter_map(|kind| Some((kind, kind.elim_case_pure(&sprite_config_.0).as_ref()?))) + .filter_map(|kind| { + let config = sprite_config + .0 + .get(&kind) + .unwrap_or_else(|| panic!("{kind:?}")) + .as_ref()?; + Some((kind, config)) + }) .flat_map(|(kind, sprite_config)| { sprite_config.variations.iter().enumerate().map( move |( From e9ed7007ec8816750b63bfa043525eb735f7a924 Mon Sep 17 00:00:00 2001 From: Imbris Date: Fri, 1 Jul 2022 01:33:18 -0400 Subject: [PATCH 2/2] Convert hashmap to array of SpriteConfigs to ensure we keep quick lookup times since this is queried for every block when processing a new chunk, --- voxygen/src/scene/terrain.rs | 69 +++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 6857de389b..e179b1800e 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -28,7 +28,7 @@ use common::{ vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol}, volumes::vol_grid_2d::{VolGrid2d, VolGrid2dError}, }; -use common_base::span; +use common_base::{prof_span, span}; use core::{f32, fmt::Debug, i32, marker::PhantomData, time::Duration}; use crossbeam_channel as channel; use enum_iterator::IntoEnumIterator; @@ -156,8 +156,58 @@ struct SpriteConfig { /// /// NOTE: Model is an asset path to the appropriate sprite .vox model. #[derive(Deserialize)] -#[serde(transparent)] -struct SpriteSpec(HashMap>>); +#[serde(try_from = "HashMap>>")] +struct SpriteSpec([Option>; 256]); + +impl SpriteSpec { + fn get(&self, kind: SpriteKind) -> Option<&SpriteConfig> { + const _: () = assert!(core::mem::size_of::() == 1); + // NOTE: This will never be out of bounds since `SpriteKind` is `repr(u8)` + self.0[kind as usize].as_ref() + } +} + +/// Conversion of SpriteSpec from a hashmap failed because some sprites were +/// missing. +struct SpritesMissing(Vec); + +use core::fmt; + +impl fmt::Display for SpritesMissing { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!( + f, + "Missing entries in the sprite manifest for these sprites: {:?}", + &self.0, + ) + } +} + +// Here we ensure all variants have an entry in the config. +impl TryFrom>>> for SpriteSpec { + type Error = SpritesMissing; + + fn try_from( + mut map: HashMap>>, + ) -> Result { + let mut array = [(); 256].map(|()| None); + let sprites_missing = SpriteKind::into_enum_iter() + .filter(|kind| match map.remove(kind) { + Some(config) => { + array[*kind as usize] = config; + false + }, + None => true, + }) + .collect::>(); + + if sprites_missing.is_empty() { + Ok(Self(array)) + } else { + Err(SpritesMissing(sprites_missing)) + } + } +} impl assets::Asset for SpriteSpec { type Loader = assets::RonLoader; @@ -216,7 +266,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' pos, // Extract sprite locations from volume sprite_instances: { - span!(_guard, "extract sprite_instances"); + prof_span!("extract sprite_instances"); let mut instances = [(); SPRITE_LOD_LEVELS].map(|()| Vec::new()); for x in 0..V::RECT_SIZE.x as i32 { @@ -236,7 +286,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' continue; }; - if let Some(cfg) = sprite_config.0.get(&sprite).and_then(Option::as_ref) { + if let Some(cfg) = sprite_config.get(sprite) { let seed = wpos.x as u64 * 3 + wpos.y as u64 * 7 + wpos.x as u64 * wpos.y as u64; // Awful PRNG @@ -396,14 +446,7 @@ impl SpriteRenderContext { let mut sprite_mesh = Mesh::new(); // NOTE: Tracks the start vertex of the next model to be meshed. let sprite_data: HashMap<(SpriteKind, usize), _> = SpriteKind::into_enum_iter() - .filter_map(|kind| { - let config = sprite_config - .0 - .get(&kind) - .unwrap_or_else(|| panic!("{kind:?}")) - .as_ref()?; - Some((kind, config)) - }) + .filter_map(|kind| Some((kind, sprite_config.get(kind)?))) .flat_map(|(kind, sprite_config)| { sprite_config.variations.iter().enumerate().map( move |(