From f2d97345e582b310273c2722e41e6786a562c0de Mon Sep 17 00:00:00 2001 From: Imbris Date: Sat, 20 Mar 2021 00:40:14 -0400 Subject: [PATCH] Display gpu timing info in the HUD when enabled --- voxygen/src/hud/mod.rs | 30 ++++++++++++- voxygen/src/render/renderer.rs | 82 ++++++++++++++++++++++++---------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 2a2b5f90a1..951113aaee 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -229,6 +229,7 @@ widget_ids! { num_lights, num_figures, num_particles, + gpu_timings[], // Game Version version, @@ -2048,6 +2049,33 @@ impl Hud { .font_size(self.fonts.cyri.scale(14)) .set(self.ids.num_particles, ui_widgets); + // GPU timing for different pipelines + let gpu_timings = global_state.window.renderer().timings(); + if !gpu_timings.is_empty() { + let num_timings = gpu_timings.len(); + // Make sure we have enoung ids + if self.ids.gpu_timings.len() < num_timings { + self.ids + .gpu_timings + .resize(num_timings, &mut ui_widgets.widget_id_generator()); + } + for (i, timing) in gpu_timings.iter().enumerate() { + Text::new(&format!( + "{:16}{:.3} ms", + &format!("{}:", timing.1), + timing.2 * 1000.0, + )) + .color(TEXT_COLOR) + .down(5.0) + .x_place_on( + ui_widgets.window, + conrod_core::position::Place::Start(Some(5.0 + 10.0 * timing.0 as f64)), + ) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(14)) + .set(self.ids.gpu_timings[i], ui_widgets); + } + } // Help Window if let Some(help_key) = global_state.settings.controls.get_binding(GameInput::Help) { Text::new( @@ -2056,7 +2084,7 @@ impl Hud { .replace("{key}", help_key.display_string(key_layout).as_str()), ) .color(TEXT_COLOR) - .down_from(self.ids.num_particles, 5.0) + .down(5.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(14)) .set(self.ids.help_info, ui_widgets); diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index a767c20520..a7eb4dc9c8 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -118,6 +118,7 @@ pub struct Renderer { resolution: Vec2, profiler: wgpu_profiler::GpuProfiler, + profile_times: Vec, } impl Renderer { @@ -341,7 +342,7 @@ impl Renderer { create_quad_index_buffer_u16(&device, QUAD_INDEX_BUFFER_U16_START_VERT_LEN as usize); let quad_index_buffer_u32 = create_quad_index_buffer_u32(&device, QUAD_INDEX_BUFFER_U32_START_VERT_LEN as usize); - let mut profiler = wgpu_profiler::GpuProfiler::new(1, queue.get_timestamp_period()); + let mut profiler = wgpu_profiler::GpuProfiler::new(4, queue.get_timestamp_period()); profiler.enable_timer = mode.profiler_enabled; profiler.enable_debug_marker = mode.profiler_enabled; @@ -371,6 +372,7 @@ impl Renderer { resolution: Vec2::new(dims.width, dims.height), profiler, + profile_times: Vec::new(), }) } @@ -380,6 +382,10 @@ impl Renderer { self.sc_desc.present_mode = self.mode.present_mode.into(); // Enable/disable profiler + if !self.mode.profiler_enabled { + // Clear the times if disabled + core::mem::take(&mut self.profile_times); + } self.profiler.enable_timer = self.mode.profiler_enabled; self.profiler.enable_debug_marker = self.mode.profiler_enabled; @@ -395,6 +401,33 @@ impl Renderer { /// Get the render mode. pub fn render_mode(&self) -> &RenderMode { &self.mode } + /// Get the current profiling times + /// Nested timings immediately follow their parent + /// Returns Vec<(how nested this timing is, label, length in seconds)> + pub fn timings(&self) -> Vec<(u8, &str, f64)> { + use wgpu_profiler::GpuTimerScopeResult; + fn recursive_collect<'a>( + vec: &mut Vec<(u8, &'a str, f64)>, + result: &'a GpuTimerScopeResult, + nest_level: u8, + ) { + vec.push(( + nest_level, + &result.label, + result.time.end - result.time.start, + )); + result + .nested_scopes + .iter() + .for_each(|child| recursive_collect(vec, child, nest_level + 1)); + } + let mut vec = Vec::new(); + self.profile_times + .iter() + .for_each(|child| recursive_collect(&mut vec, child, 0)); + vec + } + /// Resize internal render targets to match window render target dimensions. pub fn on_resize(&mut self, dims: Vec2) -> Result<(), RenderError> { // Avoid panics when creating texture with w,h of 0,0. @@ -823,6 +856,13 @@ impl Renderer { "start_recording_frame", "Renderer::start_recording_frame" ); + // Try to get the latest profiling results + if self.mode.profiler_enabled { + // Note: this lags a few frames behind + if let Some(profile_times) = self.profiler.process_finished_frame() { + self.profile_times = profile_times; + } + } // TODO: does this make sense here? self.device.poll(wgpu::Maintain::Poll); @@ -1098,32 +1138,26 @@ impl Renderer { //pub fn create_screenshot(&mut self) -> Result { pub fn create_screenshot(&mut self) { - // TODO: check if profiler enabled // TODO: save alongside a screenshot - // Ensure timestamp query data buffers are mapped - self.device.poll(wgpu::Maintain::Wait); // Take profiler snapshot - let profiling_data = if let Some(data) = self.profiler.process_finished_frame() { - data - } else { - error!("Failed to retrieve profiling data"); - return; - }; + if self.mode.profiler_enabled { + let file_name = format!( + "frame-trace_{}.json", + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or(0) + ); - let file_name = format!( - "frame-trace_{}.json", - std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .map(|d| d.as_millis()) - .unwrap_or(0) - ); - - wgpu_profiler::chrometrace::write_chrometrace( - std::path::Path::new(&file_name), - &profiling_data, - ); - - println!("{}", file_name); + if let Err(err) = wgpu_profiler::chrometrace::write_chrometrace( + std::path::Path::new(&file_name), + &self.profile_times, + ) { + error!("Failed to save GPU timing snapshot"); + } else { + info!("Saved GPU timing snapshot as: {}", file_name); + } + } //todo!() // let (width, height) = self.get_resolution().into_tuple();