summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-18 01:21:46 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-18 01:21:46 +0100
commit0f120ca3eee991566cda704be13b0b1e41dc8d66 (patch)
treecfcf3006a73960f80bc8a9abaeb58c6e7ac1b26d /client
parent6703f1c56605ca7dca8f7fe87b79badb764bd461 (diff)
downloadweareserver-0f120ca3eee991566cda704be13b0b1e41dc8d66.tar
weareserver-0f120ca3eee991566cda704be13b0b1e41dc8d66.tar.bz2
weareserver-0f120ca3eee991566cda704be13b0b1e41dc8d66.tar.zst
more profiler things
Diffstat (limited to 'client')
-rw-r--r--client/Cargo.toml1
-rw-r--r--client/src/interfaces/mod.rs3
-rw-r--r--client/src/interfaces/profiler.rs50
-rw-r--r--client/src/renderer.rs21
-rw-r--r--client/src/scene_prepare.rs18
-rw-r--r--client/src/state.rs1
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