diff options
author | metamuffin <metamuffin@disroot.org> | 2025-01-18 01:21:46 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-01-18 01:21:46 +0100 |
commit | 0f120ca3eee991566cda704be13b0b1e41dc8d66 (patch) | |
tree | cfcf3006a73960f80bc8a9abaeb58c6e7ac1b26d /client | |
parent | 6703f1c56605ca7dca8f7fe87b79badb764bd461 (diff) | |
download | weareserver-0f120ca3eee991566cda704be13b0b1e41dc8d66.tar weareserver-0f120ca3eee991566cda704be13b0b1e41dc8d66.tar.bz2 weareserver-0f120ca3eee991566cda704be13b0b1e41dc8d66.tar.zst |
more profiler things
Diffstat (limited to 'client')
-rw-r--r-- | client/Cargo.toml | 1 | ||||
-rw-r--r-- | client/src/interfaces/mod.rs | 3 | ||||
-rw-r--r-- | client/src/interfaces/profiler.rs | 50 | ||||
-rw-r--r-- | client/src/renderer.rs | 21 | ||||
-rw-r--r-- | client/src/scene_prepare.rs | 18 | ||||
-rw-r--r-- | client/src/state.rs | 1 |
6 files changed, 83 insertions, 11 deletions
diff --git a/client/Cargo.toml b/client/Cargo.toml index c98374a..823160e 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -22,3 +22,4 @@ egui = { version = "0.30.0", features = ["bytemuck"] } bytemuck = "1.21.0" xdg = "2.5.2" nnnoiseless = "0.5.1" +humansize = "2.1.3" diff --git a/client/src/interfaces/mod.rs b/client/src/interfaces/mod.rs index 09db60f..eb0eb86 100644 --- a/client/src/interfaces/mod.rs +++ b/client/src/interfaces/mod.rs @@ -20,7 +20,7 @@ pub mod profiler; use crate::{download::Downloader, network::Network, scene_prepare::ScenePreparer}; use egui::Widget; use prefabindex::PrefabIndexInterface; -use profiler::Profiler; +use profiler::{Profiler, TimingProfiler}; use std::sync::{Arc, Mutex}; use weareshared::resources::PrefabIndex; @@ -35,6 +35,7 @@ pub struct InterfaceData { pub network: Arc<Network>, pub downloader: Arc<Downloader>, pub prefab_index: Arc<PrefabIndex>, + pub render_timing: Arc<Mutex<TimingProfiler>>, } pub fn ui_selector(idata: Arc<InterfaceData>) -> impl Fn(&egui::Context) -> bool { diff --git a/client/src/interfaces/profiler.rs b/client/src/interfaces/profiler.rs index 5c8737b..85b5858 100644 --- a/client/src/interfaces/profiler.rs +++ b/client/src/interfaces/profiler.rs @@ -15,8 +15,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ use super::InterfaceData; -use egui::Widget; -use std::sync::Arc; +use egui::{Grid, Widget}; +use std::{sync::Arc, time::Instant}; pub struct Profiler { pub idata: Arc<InterfaceData>, @@ -28,6 +28,52 @@ impl Widget for &mut Profiler { ui.add(&*self.idata.scene_prepare); ui.heading("Download"); ui.add(&*self.idata.downloader); + ui.heading("Render"); + ui.add(&*self.idata.render_timing.lock().unwrap()); ui.response() } } + +pub struct TimingProfiler { + last_cp: Instant, + cur_cp: &'static str, + checkpoints: Vec<(&'static str, f32)>, +} + +impl Default for TimingProfiler { + fn default() -> Self { + Self { + last_cp: Instant::now(), + checkpoints: Default::default(), + cur_cp: "none", + } + } +} +impl TimingProfiler { + pub fn begin(&mut self, name: &'static str) { + self.checkpoints.clear(); + self.last_cp = Instant::now(); + self.cur_cp = name; + } + pub fn checkpoint(&mut self, name: &'static str) { + let now = Instant::now(); + let dur = (now - self.last_cp).as_secs_f32(); + self.last_cp = now; + self.checkpoints.push((self.cur_cp, dur)); + self.cur_cp = name; + } +} +impl Widget for &TimingProfiler { + fn ui(self, ui: &mut egui::Ui) -> egui::Response { + Grid::new("tp") + .num_columns(2) + .show(ui, |ui| { + for (name, dur) in &self.checkpoints { + ui.label(*name); + ui.label(format!("{:.02}ms", dur * 1000.)); + ui.end_row(); + } + }) + .response + } +} diff --git a/client/src/renderer.rs b/client/src/renderer.rs index b4c2c05..2777526 100644 --- a/client/src/renderer.rs +++ b/client/src/renderer.rs @@ -15,14 +15,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ use crate::{ - camera::Camera, download::Downloader, scene_prepare::ScenePreparer, - scene_render::ScenePipeline, state::InputState, ui::UiRenderer, + camera::Camera, download::Downloader, interfaces::profiler::TimingProfiler, + scene_prepare::ScenePreparer, scene_render::ScenePipeline, state::InputState, ui::UiRenderer, }; use anyhow::{Result, anyhow}; use log::{info, warn}; use pollster::FutureExt; use std::{ - sync::Arc, + mem::swap, + sync::{Arc, Mutex}, thread::{sleep, spawn}, time::Duration, }; @@ -45,6 +46,8 @@ pub struct Renderer<'a> { pub scene_prepare: Arc<ScenePreparer>, surface_needs_reconfigure: bool, depth: TextureView, + pub timing: TimingProfiler, + pub timing_submit: Arc<Mutex<TimingProfiler>>, } impl<'a> Renderer<'a> { pub fn new(window: &'a Window, downloader: Arc<Downloader>) -> Result<Self> { @@ -138,6 +141,8 @@ impl<'a> Renderer<'a> { surface_configuration, ui_renderer, surface_needs_reconfigure: false, + timing: Default::default(), + timing_submit: Default::default(), }) } @@ -172,6 +177,7 @@ impl<'a> Renderer<'a> { camera: &Camera, input_state: &mut InputState, ) -> Result<()> { + self.timing.begin("prepare"); if self.surface_needs_reconfigure { self.surface .configure(&self.device, &self.surface_configuration); @@ -192,6 +198,7 @@ impl<'a> Renderer<'a> { let projection = camera.to_matrix(); + self.timing.checkpoint("draw scene"); self.scene_pipeline.draw( &mut commands, &target_view, @@ -201,6 +208,7 @@ impl<'a> Renderer<'a> { projection, ); + self.timing.checkpoint("draw ui"); self.ui_renderer.draw( &mut commands, &target_view, @@ -210,11 +218,18 @@ impl<'a> Renderer<'a> { &self.surface_configuration, ); + self.timing.checkpoint("submit"); let i = self.queue.submit(Some(commands.finish())); + self.timing.checkpoint("poll"); self.device.poll(MaintainBase::WaitForSubmissionIndex(i)); + self.timing.checkpoint("present"); target.present(); + self.timing.checkpoint(""); + + let mut ts = self.timing_submit.lock().unwrap(); + swap(&mut *ts, &mut self.timing); Ok(()) } } diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs index cee55f7..5c5102d 100644 --- a/client/src/scene_prepare.rs +++ b/client/src/scene_prepare.rs @@ -17,6 +17,7 @@ use crate::download::Downloader; use anyhow::Result; use egui::{Grid, Widget}; +use humansize::DECIMAL; use image::ImageReader; use log::debug; use std::{ @@ -45,6 +46,7 @@ pub struct DemandMap<K, V> { struct DemandMapState<K, V> { values: HashMap<K, V>, needed: HashSet<K>, + size_metric: usize, } impl<K: Hash + Eq + Clone, V: Clone> DemandMap<K, V> { pub fn new() -> Self { @@ -52,6 +54,7 @@ impl<K: Hash + Eq + Clone, V: Clone> DemandMap<K, V> { inner: DemandMapState { needed: HashSet::new(), values: HashMap::new(), + size_metric: 0, } .into(), } @@ -59,10 +62,11 @@ impl<K: Hash + Eq + Clone, V: Clone> DemandMap<K, V> { pub fn needed(&self) -> Vec<K> { self.inner.read().unwrap().needed.iter().cloned().collect() } - pub fn insert(&self, key: K, value: V) { + pub fn insert(&self, key: K, value: V, size: usize) { let mut s = self.inner.write().unwrap(); s.needed.remove(&key); s.values.insert(key, value); + s.size_metric += size; } pub fn try_get(&self, key: K) -> Option<V> { let mut s = self.inner.write().unwrap(); @@ -127,7 +131,7 @@ impl ScenePreparer { } } if rprefab.0.len() == prefab.mesh.len() { - self.prefabs.insert(pres.clone(), Arc::new(rprefab)); + self.prefabs.insert(pres.clone(), Arc::new(rprefab), 0); debug!("prefab created ({pres})"); num_done += 1; } @@ -149,6 +153,7 @@ impl ScenePreparer { self.index_buffers.insert( pres.clone(), (Arc::new(buffer), (buf.len() / size_of::<u32>()) as u32), + buf.len(), ); debug!( "index buffer created (len={}, took {:?}) {pres}", @@ -173,6 +178,7 @@ impl ScenePreparer { self.vertex_buffers.insert( pres.clone(), (Arc::new(buffer), (buf.len() / size_of::<f32>()) as u32), + buf.len(), ); debug!( "vertex attribute buffer created (len={}, took {:?}) {pres}", @@ -198,7 +204,7 @@ impl ScenePreparer { dims.0, dims.1, ); - self.textures.insert(pres.clone(), tex_bg); + self.textures.insert(pres.clone(), tex_bg, image.len()); debug!( "texture created (res={}x{}, took {:?})", dims.0, @@ -218,7 +224,7 @@ impl ScenePreparer { 1, 1, ); - self.placeholder_textures.insert(variant, tex_bg); + self.placeholder_textures.insert(variant, tex_bg, 4); num_done += 1; } for pres in self.mesh_parts.needed() { @@ -294,6 +300,7 @@ impl ScenePreparer { tex_normal, double_sided: part.g_double_sided.is_some(), }), + 0, ); num_done += 1; } @@ -361,6 +368,7 @@ impl<K, V> Widget for &DemandMap<K, V> { let state = self.inner.read().unwrap(); ui.label(state.needed.len().to_string()); ui.label(state.values.len().to_string()); + ui.label(humansize::format_size(state.size_metric, DECIMAL)); ui.end_row(); ui.response() } @@ -369,7 +377,7 @@ impl<K, V> Widget for &DemandMap<K, V> { impl Widget for &ScenePreparer { fn ui(self, ui: &mut egui::Ui) -> egui::Response { Grid::new("sp") - .num_columns(3) + .num_columns(4) .show(ui, |ui| { ui.label("prefabs"); self.prefabs.ui(ui); diff --git a/client/src/state.rs b/client/src/state.rs index 439b7ca..2912e14 100644 --- a/client/src/state.rs +++ b/client/src/state.rs @@ -108,6 +108,7 @@ impl<'a> State<'a> { downloader: self.downloader.clone(), network: self.network.clone(), prefab_index: self.prefab_index.clone(), + render_timing: self.renderer.timing_submit.clone(), }); self.renderer .ui_renderer |