diff --git a/src/redraw_scheduler.rs b/src/redraw_scheduler.rs index 5a24d8e..1673919 100644 --- a/src/redraw_scheduler.rs +++ b/src/redraw_scheduler.rs @@ -1,5 +1,5 @@ use std::sync::{Arc, Mutex}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicU16, Ordering}; use std::time::{Duration, Instant}; use std::thread; @@ -9,56 +9,17 @@ lazy_static! { pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new(); } +const BUFFER_FRAMES: u16 = 60; + pub struct RedrawScheduler { - window: Mutex>>, // Would prefer not to have to lock this every time. - frame_queued: AtomicBool, + frames_queued: AtomicU16, scheduled_frame: Mutex> } -pub fn redraw_loop() { - thread::spawn(|| { - loop { - let frame_start = Instant::now(); - - let request_redraw = { - if REDRAW_SCHEDULER.frame_queued.load(Ordering::Relaxed) { - REDRAW_SCHEDULER.frame_queued.store(false, Ordering::Relaxed); - true - } else { - let mut next_scheduled_frame = REDRAW_SCHEDULER.scheduled_frame.lock().unwrap(); - if let Some(scheduled_frame) = next_scheduled_frame.clone() { - if scheduled_frame < frame_start { - *next_scheduled_frame = None; - true - } else { - false - } - } else { - false - } - } - }; - - if request_redraw { - let window = REDRAW_SCHEDULER.window.lock().unwrap(); - if let Some(window) = &*window { - window.request_redraw(); - } - } - - if let Some(time_to_sleep) = Duration::from_secs_f32(1.0 / 60.0).checked_sub(frame_start.elapsed()) { - thread::sleep(time_to_sleep) - } - } - }); -} - impl RedrawScheduler { pub fn new() -> RedrawScheduler { - redraw_loop(); RedrawScheduler { - window: Mutex::new(None), - frame_queued: AtomicBool::new(false), + frames_queued: AtomicU16::new(1), scheduled_frame: Mutex::new(None) } } @@ -75,11 +36,26 @@ impl RedrawScheduler { } pub fn queue_next_frame(&self) { - self.frame_queued.store(true, Ordering::Relaxed); + self.frames_queued.store(BUFFER_FRAMES, Ordering::Relaxed); } - pub fn set_window(&self, window: &Arc){ - let mut window_ref = self.window.lock().unwrap(); - window_ref.replace(window.clone()); + pub fn should_draw(&self) -> bool { + let frames_queued = self.frames_queued.load(Ordering::Relaxed); + if frames_queued > 0 { + self.frames_queued.store(frames_queued - 1, Ordering::Relaxed); + true + } else { + let mut next_scheduled_frame = self.scheduled_frame.lock().unwrap(); + if let Some(scheduled_frame) = next_scheduled_frame.clone() { + if scheduled_frame < Instant::now() { + *next_scheduled_frame = None; + true + } else { + false + } + } else { + false + } + } } } diff --git a/src/window.rs b/src/window.rs index b68823d..53f5b58 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use std::time::{Duration, Instant}; use image::{load_from_memory, GenericImageView, Pixel}; use skulpin::{CoordinateSystem, RendererBuilder, PresentMode}; @@ -54,8 +55,6 @@ pub fn ui_loop() { .build(&event_loop) .expect("Failed to create window")); - REDRAW_SCHEDULER.set_window(&window); - let mut skulpin_renderer = RendererBuilder::new() .prefer_integrated_gpu() .use_vulkan_debug_layer(true) @@ -71,7 +70,10 @@ pub fn ui_loop() { event_loop.run(move |event, _window_target, control_flow| { match event { - Event::NewEvents(StartCause::Init) => window.request_redraw(), + Event::NewEvents(StartCause::Init) | + Event::NewEvents(StartCause::ResumeTimeReached { .. }) => { + window.request_redraw() + }, Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -166,16 +168,20 @@ pub fn ui_loop() { } Event::RedrawRequested { .. } => { - if let Err(e) = skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| { - if renderer.draw(canvas, coordinate_system_helper) { - handle_new_grid_size(window.inner_size(), &renderer) - } + let frame_start = Instant::now(); - *control_flow = ControlFlow::Wait; - }) { - println!("Error during draw: {:?}", e); - *control_flow = ControlFlow::Exit + if REDRAW_SCHEDULER.should_draw() { + if let Err(e) = skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| { + if renderer.draw(canvas, coordinate_system_helper) { + handle_new_grid_size(window.inner_size(), &renderer) + } + + }) { + println!("Error during draw: {:?}", e); + } } + + *control_flow = ControlFlow::WaitUntil(frame_start + Duration::from_secs_f32(1.0 / 60.0)); }, _ => {}