Display gpu timing info in the HUD when enabled

This commit is contained in:
Imbris 2021-03-20 00:40:14 -04:00 committed by Avi Weinstock
parent 2de13f3a87
commit e31353df88
2 changed files with 87 additions and 25 deletions

View File

@ -237,6 +237,7 @@ widget_ids! {
num_lights,
num_figures,
num_particles,
gpu_timings[],
// Game Version
version,
@ -2189,6 +2190,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(
@ -2197,7 +2225,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);

View File

@ -118,6 +118,7 @@ pub struct Renderer {
resolution: Vec2<u32>,
profiler: wgpu_profiler::GpuProfiler,
profile_times: Vec<wgpu_profiler::GpuTimerScopeResult>,
}
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<u32>) -> 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<image::DynamicImage,
// RenderError> {
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();