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::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<Option<Arc<Window>>>, // Would prefer not to have to lock this every time.
frame_queued: AtomicBool,
frames_queued: AtomicU16,
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 {
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<Window>){
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
}
}
}
}

@ -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 { .. } => {
let frame_start = Instant::now();
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)
}
*control_flow = ControlFlow::Wait;
}) {
println!("Error during draw: {:?}", e);
*control_flow = ControlFlow::Exit
}
}
*control_flow = ControlFlow::WaitUntil(frame_start + Duration::from_secs_f32(1.0 / 60.0));
},
_ => {}

Loading…
Cancel
Save