1
0
Fork 0

Ensure a consistent frame pacing in X11 windows

The next frame's time stamp needs to be computed based on the last
frame's, not based on the current time, unless the last frame took too
long to process.
This commit is contained in:
Robbert van der Helm 2022-11-18 14:47:41 +01:00
parent 1780c89baf
commit 13cc12d4e7

View file

@ -445,19 +445,21 @@ impl Window {
xcb::ffi::xcb_get_file_descriptor(raw_conn) xcb::ffi::xcb_get_file_descriptor(raw_conn)
}; };
let mut next_frame = Instant::now() + self.frame_interval; let mut last_frame = Instant::now();
self.event_loop_running = true; self.event_loop_running = true;
while self.event_loop_running { while self.event_loop_running {
let now = Instant::now(); // We'll try to keep a consistent frame pace. If the last frame couldn't be processed in
let until_next_frame = if now > next_frame { // the expected frame time, this will throttle down to prevent multiple frames from
// being queued up. The conditional here is needed because event handling and frame
// drawing is interleaved. The `poll()` function below will wait until the next frame
// can be drawn, or until the window receives an event. We thus need to manually check
// if it's already time to draw a new frame.
let next_frame = last_frame + self.frame_interval;
if Instant::now() >= next_frame {
handler.on_frame(&mut crate::Window::new(self)); handler.on_frame(&mut crate::Window::new(self));
last_frame = Instant::max(next_frame, Instant::now() - self.frame_interval);
next_frame = Instant::now() + self.frame_interval; }
self.frame_interval
} else {
next_frame - now
};
let mut fds = [PollFd::new(xcb_fd, PollFlags::POLLIN)]; let mut fds = [PollFd::new(xcb_fd, PollFlags::POLLIN)];
@ -466,7 +468,8 @@ impl Window {
self.drain_xcb_events(handler); self.drain_xcb_events(handler);
// FIXME: handle errors // FIXME: handle errors
poll(&mut fds, until_next_frame.subsec_millis() as i32).unwrap(); poll(&mut fds, next_frame.duration_since(Instant::now()).subsec_millis() as i32)
.unwrap();
if let Some(revents) = fds[0].revents() { if let Some(revents) = fds[0].revents() {
if revents.contains(PollFlags::POLLERR) { if revents.contains(PollFlags::POLLERR) {