rework animation loop and add back animation buffer

macos-click-through
Keith Simmons 5 years ago
parent b60132132e
commit 9308d1d81f

@ -1,5 +1,5 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicU16, Ordering};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::thread; use std::thread;
@ -9,56 +9,17 @@ lazy_static! {
pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new(); pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new();
} }
const BUFFER_FRAMES: u16 = 60;
pub struct RedrawScheduler { pub struct RedrawScheduler {
window: Mutex<Option<Arc<Window>>>, // Would prefer not to have to lock this every time. frames_queued: AtomicU16,
frame_queued: AtomicBool,
scheduled_frame: Mutex<Option<Instant>> scheduled_frame: Mutex<Option<Instant>>
} }
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 { impl RedrawScheduler {
pub fn new() -> RedrawScheduler { pub fn new() -> RedrawScheduler {
redraw_loop();
RedrawScheduler { RedrawScheduler {
window: Mutex::new(None), frames_queued: AtomicU16::new(1),
frame_queued: AtomicBool::new(false),
scheduled_frame: Mutex::new(None) scheduled_frame: Mutex::new(None)
} }
} }
@ -75,11 +36,26 @@ impl RedrawScheduler {
} }
pub fn queue_next_frame(&self) { 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<Window>){ pub fn should_draw(&self) -> bool {
let mut window_ref = self.window.lock().unwrap(); let frames_queued = self.frames_queued.load(Ordering::Relaxed);
window_ref.replace(window.clone()); 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
}
}
} }
} }

@ -1,4 +1,5 @@
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant};
use image::{load_from_memory, GenericImageView, Pixel}; use image::{load_from_memory, GenericImageView, Pixel};
use skulpin::{CoordinateSystem, RendererBuilder, PresentMode}; use skulpin::{CoordinateSystem, RendererBuilder, PresentMode};
@ -54,8 +55,6 @@ pub fn ui_loop() {
.build(&event_loop) .build(&event_loop)
.expect("Failed to create window")); .expect("Failed to create window"));
REDRAW_SCHEDULER.set_window(&window);
let mut skulpin_renderer = RendererBuilder::new() let mut skulpin_renderer = RendererBuilder::new()
.prefer_integrated_gpu() .prefer_integrated_gpu()
.use_vulkan_debug_layer(true) .use_vulkan_debug_layer(true)
@ -71,7 +70,10 @@ pub fn ui_loop() {
event_loop.run(move |event, _window_target, control_flow| { event_loop.run(move |event, _window_target, control_flow| {
match event { match event {
Event::NewEvents(StartCause::Init) => window.request_redraw(), Event::NewEvents(StartCause::Init) |
Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
window.request_redraw()
},
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
@ -166,16 +168,20 @@ pub fn ui_loop() {
} }
Event::RedrawRequested { .. } => { Event::RedrawRequested { .. } => {
if let Err(e) = skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| { let frame_start = Instant::now();
if renderer.draw(canvas, coordinate_system_helper) {
handle_new_grid_size(window.inner_size(), &renderer)
}
*control_flow = ControlFlow::Wait; if REDRAW_SCHEDULER.should_draw() {
}) { if let Err(e) = skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| {
println!("Error during draw: {:?}", e); if renderer.draw(canvas, coordinate_system_helper) {
*control_flow = ControlFlow::Exit 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));
}, },
_ => {} _ => {}

Loading…
Cancel
Save