diff --git a/examples/with_winit/README.md b/examples/with_winit/README.md index 8dc1a8e..f1c0910 100644 --- a/examples/with_winit/README.md +++ b/examples/with_winit/README.md @@ -20,4 +20,5 @@ $ cargo run -p with_winit --release -- [SVG FILES] - Space resets the position and zoom of the image. - S toggles the frame statistics layer - C resets the min/max frame time tracked by statistics +- V toggles VSync on/off (default: on) - Escape exits the program. diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 760ec99..34553f2 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -100,6 +100,7 @@ fn run( let mut images = ImageCache::new(); let mut stats = stats::Stats::new(); let mut stats_shown = true; + let mut vsync_on = true; let start = Instant::now(); let mut touch_state = multi_touch::TouchState::new(); @@ -151,6 +152,17 @@ fn run( Some(VirtualKeyCode::C) => { 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) => { *control_flow = ControlFlow::Exit; } @@ -314,6 +326,7 @@ fn run( width as f64, height as f64, stats.samples(), + vsync_on, ); } let surface_texture = render_state diff --git a/examples/with_winit/src/stats.rs b/examples/with_winit/src/stats.rs index 0e68e63..76c3e04 100644 --- a/examples/with_winit/src/stats.rs +++ b/examples/with_winit/src/stats.rs @@ -40,17 +40,17 @@ impl Snapshot { viewport_width: f64, viewport_height: f64, samples: T, + vsync: bool, ) where T: Iterator, { 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 y_offset = viewport_height - height; let offset = Affine::translate((x_offset, y_offset)); - let text_height = height * 0.1; - let left_margin = width * 0.01; - let text_size = (text_height * 0.9) as f32; + + // Draw the background sb.fill( Fill::NonZero, offset, @@ -58,38 +58,29 @@ impl Snapshot { None, &Rect::new(0., 0., width, height), ); - text.add( - sb, - None, - text_size, - Some(&Brush::Solid(Color::WHITE)), - offset * Affine::translate((left_margin, text_height)), - &format!("Frame Time: {:.2} ms", self.frame_time_ms), - ); - text.add( - sb, - None, - text_size, - Some(&Brush::Solid(Color::WHITE)), - offset * Affine::translate((left_margin, 2. * text_height)), - &format!("Frame Time (min): {:.2} ms", self.frame_time_min_ms), - ); - text.add( - sb, - None, - text_size, - Some(&Brush::Solid(Color::WHITE)), - 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}"), - ); + + let labels = [ + format!("Frame Time: {:.2} ms", self.frame_time_ms), + format!("Frame Time (min): {:.2} ms", self.frame_time_min_ms), + format!("Frame Time (max): {:.2} ms", self.frame_time_max_ms), + format!("VSync: {}", if vsync { "on" } else { "off" }), + format!("Resolution: {viewport_width}x{viewport_height}"), + ]; + + // height / 2 is dedicated to the text labels and the rest is filled by the bar graph. + let text_height = height * 0.5 / (1 + labels.len()) as f64; + let left_margin = width * 0.01; + let text_size = (text_height * 0.9) as f32; + for (i, label) in labels.iter().enumerate() { + text.add( + sb, + None, + text_size, + Some(&Brush::Solid(Color::WHITE)), + offset * Affine::translate((left_margin, (i + 1) as f64 * text_height)), + &label, + ); + } text.add( sb, None, @@ -112,7 +103,7 @@ impl Snapshot { LineTo((bar_width, graph_max_height).into()), ]; 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. // 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 @@ -121,7 +112,7 @@ impl Snapshot { let s = Affine::scale_non_uniform(1., -h.sqrt()); sb.fill( 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), None, &bar, diff --git a/src/util.rs b/src/util.rs index e33d940..d73778a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -92,6 +92,13 @@ impl RenderContext { .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. pub async fn device(&mut self, compatible_surface: Option<&Surface>) -> Option { let compatible = match compatible_surface {