[frame_stats] Add a VSync toggle key; show the current VSync state in stats UI

This commit is contained in:
Arman Uguray 2023-03-16 01:02:49 -07:00
parent 306aeab6df
commit 1250cdcf86
4 changed files with 50 additions and 38 deletions

View file

@ -20,4 +20,5 @@ $ cargo run -p with_winit --release -- [SVG FILES]
- Space resets the position and zoom of the image. - Space resets the position and zoom of the image.
- S toggles the frame statistics layer - S toggles the frame statistics layer
- C resets the min/max frame time tracked by statistics - C resets the min/max frame time tracked by statistics
- V toggles VSync on/off (default: on)
- Escape exits the program. - Escape exits the program.

View file

@ -100,6 +100,7 @@ fn run(
let mut images = ImageCache::new(); let mut images = ImageCache::new();
let mut stats = stats::Stats::new(); let mut stats = stats::Stats::new();
let mut stats_shown = true; let mut stats_shown = true;
let mut vsync_on = true;
let start = Instant::now(); let start = Instant::now();
let mut touch_state = multi_touch::TouchState::new(); let mut touch_state = multi_touch::TouchState::new();
@ -151,6 +152,17 @@ fn run(
Some(VirtualKeyCode::C) => { Some(VirtualKeyCode::C) => {
stats.clear_min_and_max(); stats.clear_min_and_max();
} }
Some(VirtualKeyCode::V) => {
vsync_on = !vsync_on;
render_cx.set_present_mode(
&mut render_state.surface,
if vsync_on {
wgpu::PresentMode::Fifo
} else {
wgpu::PresentMode::Immediate
},
);
}
Some(VirtualKeyCode::Escape) => { Some(VirtualKeyCode::Escape) => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
@ -314,6 +326,7 @@ fn run(
width as f64, width as f64,
height as f64, height as f64,
stats.samples(), stats.samples(),
vsync_on,
); );
} }
let surface_texture = render_state let surface_texture = render_state

View file

@ -40,17 +40,17 @@ impl Snapshot {
viewport_width: f64, viewport_width: f64,
viewport_height: f64, viewport_height: f64,
samples: T, samples: T,
vsync: bool,
) where ) where
T: Iterator<Item = &'a u64>, T: Iterator<Item = &'a u64>,
{ {
let width = (viewport_width * 0.4).max(200.).min(600.); let width = (viewport_width * 0.4).max(200.).min(600.);
let height = width * 0.6; let height = width * 0.7;
let x_offset = viewport_width - width; let x_offset = viewport_width - width;
let y_offset = viewport_height - height; let y_offset = viewport_height - height;
let offset = Affine::translate((x_offset, y_offset)); let offset = Affine::translate((x_offset, y_offset));
let text_height = height * 0.1;
let left_margin = width * 0.01; // Draw the background
let text_size = (text_height * 0.9) as f32;
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
offset, offset,
@ -58,38 +58,29 @@ impl Snapshot {
None, None,
&Rect::new(0., 0., width, height), &Rect::new(0., 0., width, height),
); );
text.add(
sb, let labels = [
None, format!("Frame Time: {:.2} ms", self.frame_time_ms),
text_size, format!("Frame Time (min): {:.2} ms", self.frame_time_min_ms),
Some(&Brush::Solid(Color::WHITE)), format!("Frame Time (max): {:.2} ms", self.frame_time_max_ms),
offset * Affine::translate((left_margin, text_height)), format!("VSync: {}", if vsync { "on" } else { "off" }),
&format!("Frame Time: {:.2} ms", self.frame_time_ms), format!("Resolution: {viewport_width}x{viewport_height}"),
); ];
text.add(
sb, // height / 2 is dedicated to the text labels and the rest is filled by the bar graph.
None, let text_height = height * 0.5 / (1 + labels.len()) as f64;
text_size, let left_margin = width * 0.01;
Some(&Brush::Solid(Color::WHITE)), let text_size = (text_height * 0.9) as f32;
offset * Affine::translate((left_margin, 2. * text_height)), for (i, label) in labels.iter().enumerate() {
&format!("Frame Time (min): {:.2} ms", self.frame_time_min_ms), text.add(
); sb,
text.add( None,
sb, text_size,
None, Some(&Brush::Solid(Color::WHITE)),
text_size, offset * Affine::translate((left_margin, (i + 1) as f64 * text_height)),
Some(&Brush::Solid(Color::WHITE)), &label,
offset * Affine::translate((left_margin, 3. * text_height)), );
&format!("Frame Time (max): {:.2} ms", self.frame_time_max_ms), }
);
text.add(
sb,
None,
text_size,
Some(&Brush::Solid(Color::WHITE)),
offset * Affine::translate((left_margin, 4. * text_height)),
&format!("Resolution: {viewport_width}x{viewport_height}"),
);
text.add( text.add(
sb, sb,
None, None,
@ -112,7 +103,7 @@ impl Snapshot {
LineTo((bar_width, graph_max_height).into()), LineTo((bar_width, graph_max_height).into()),
]; ];
for (i, sample) in samples.enumerate() { for (i, sample) in samples.enumerate() {
let t = offset * Affine::translate(((i as f64) * bar_extent, graph_max_height)); let t = offset * Affine::translate((i as f64 * bar_extent, graph_max_height));
// The height of each sample is based on its ratio to the maximum observed frame time. // The height of each sample is based on its ratio to the maximum observed frame time.
// Currently this maximum scale is sticky and a high temporary spike will permanently // Currently this maximum scale is sticky and a high temporary spike will permanently
// shrink the draw size of the overall average sample, so scale the size non-linearly to // shrink the draw size of the overall average sample, so scale the size non-linearly to
@ -121,7 +112,7 @@ impl Snapshot {
let s = Affine::scale_non_uniform(1., -h.sqrt()); let s = Affine::scale_non_uniform(1., -h.sqrt());
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
t * Affine::translate((left_margin, 5. * text_height)) * s, t * Affine::translate((left_margin, (1 + labels.len()) as f64 * text_height)) * s,
Color::rgb8(0, 240, 0), Color::rgb8(0, 240, 0),
None, None,
&bar, &bar,

View file

@ -92,6 +92,13 @@ impl RenderContext {
.configure(&self.devices[surface.dev_id].device, &surface.config); .configure(&self.devices[surface.dev_id].device, &surface.config);
} }
pub fn set_present_mode(&self, surface: &mut RenderSurface, present_mode: wgpu::PresentMode) {
surface.config.present_mode = present_mode;
surface
.surface
.configure(&self.devices[surface.dev_id].device, &surface.config);
}
/// Finds or creates a compatible device handle id. /// Finds or creates a compatible device handle id.
pub async fn device(&mut self, compatible_surface: Option<&Surface>) -> Option<usize> { pub async fn device(&mut self, compatible_surface: Option<&Surface>) -> Option<usize> {
let compatible = match compatible_surface { let compatible = match compatible_surface {