From a3739d6baddfc411b6223d1d4352f1f4f80f2b4c Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Wed, 11 Sep 2019 08:28:21 +0200 Subject: [PATCH] wayland: instantly wake up if events are pending (#1153) Just before starting to poll/wait on calloop(mio), check if there are already events pending in the internal buffer of our wayland event queue. If so, dispatch them and force an instant wakeup from the polling, in order to behave as if we were instantly woken up by incoming wayland events. When using OpenGL, mesa shares our wayland socket, and also reads from it, especially if vsync is enabled as it'll do blocking reads. When doing so, it may enqueue events in the internal buffer of our event queue. As the socket has been read, mio will thus not notify it to calloop as read, and thus calloop will not know it needs to dispatch. In some cases this can lead to some events being delivered much later than they should. Combined with key repetition this can actually cause some flooding of the event queue making this effect event worse. Fixes #1148 --- src/platform_impl/linux/wayland/event_loop.rs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index fa1ef347..af8c8079 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -314,6 +314,25 @@ impl EventLoop { // send pending events to the server self.display.flush().expect("Wayland connection lost."); + // During the run of the user callback, some other code monitoring and reading the + // wayland socket may have been run (mesa for example does this with vsync), if that + // is the case, some events may have been enqueued in our event queue. + // + // If some messages are there, the event loop needs to behave as if it was instantly + // woken up by messages arriving from the wayland socket, to avoid getting stuck. + let instant_wakeup = { + let window_target = match self.window_target.p { + crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, + _ => unreachable!(), + }; + let dispatched = window_target + .evq + .borrow_mut() + .dispatch_pending() + .expect("Wayland connection lost."); + dispatched > 0 + }; + match control_flow { ControlFlow::Exit => break, ControlFlow::Poll => { @@ -328,7 +347,12 @@ impl EventLoop { ); } ControlFlow::Wait => { - self.inner_loop.dispatch(None, &mut ()).unwrap(); + let timeout = if instant_wakeup { + Some(::std::time::Duration::from_millis(0)) + } else { + None + }; + self.inner_loop.dispatch(timeout, &mut ()).unwrap(); callback( crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled { start: Instant::now(), @@ -341,7 +365,7 @@ impl EventLoop { ControlFlow::WaitUntil(deadline) => { let start = Instant::now(); // compute the blocking duration - let duration = if deadline > start { + let duration = if deadline > start && !instant_wakeup { deadline - start } else { ::std::time::Duration::from_millis(0)