From 070bceda310676f07db2c1c330e7c9d05e780ca0 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Tue, 5 Jan 2021 22:57:59 +0100 Subject: [PATCH] [rs] Fixed inconsistent framerate in examples. Does not affect web builds. Previously, framerate would float between 30-40 fps depending on how many events would come in. Fast mouse movements over the window lead to higher framerates since request_redraw was called every 20ms (-> 50fps) AND all events were consumed, additionally the event loop would wake up only every 10ms, so actual rate of request_redraw depended on how often we'd wake up. Fixed this by setting the max sleep time of the event loop to the remaining time until hitting the desired time interval since the last frame. The difference is most visible on the spinning cubes in the shadow example since the cubes currently spin with a fixed angle per frame (independent of frame timings). --- wgpu/examples/framework.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 745610360f..3f0004d94a 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -243,22 +243,27 @@ fn start( *control_flow = if cfg!(feature = "metal-auto-capture") { ControlFlow::Exit } else { - #[cfg(not(target_arch = "wasm32"))] - { - ControlFlow::WaitUntil(Instant::now() + Duration::from_millis(10)) - } - #[cfg(target_arch = "wasm32")] - { - ControlFlow::Poll - } + ControlFlow::Poll }; match event { event::Event::MainEventsCleared => { #[cfg(not(target_arch = "wasm32"))] { - if last_update_inst.elapsed() > Duration::from_millis(20) { + // Clamp to some max framerate to avoid busy-looping too much + // (we might be in wgpu::PresentMode::Mailbox, thus discarding superfluous frames) + // + // winit has window.current_monitor().video_modes() but that is a list of all full screen video modes. + // So without extra dependencies it's a bit tricky to get the max refresh rate we can run the window on. + // Therefore we just go with 60fps - sorry 120hz+ folks! + let target_frametime = Duration::from_secs_f64(1.0 / 60.0); + let time_since_last_frame = last_update_inst.elapsed(); + if time_since_last_frame >= target_frametime { window.request_redraw(); last_update_inst = Instant::now(); + } else { + *control_flow = ControlFlow::WaitUntil( + Instant::now() + target_frametime - time_since_last_frame, + ); } pool.run_until_stalled();