Open fredizzimo opened 1 year ago
One workaround that seems to work is to move the dispatch_pending
call after calling prepare_read
only actually poll the socket and read if it returns 0.
So something like this
pub fn wait_for_vsync(&mut self) {
while !self.vsync_signaled.load(Ordering::Relaxed) {
self.event_queue.flush().unwrap();
let read_guard = self.event_queue.prepare_read().unwrap();
if self
.event_queue
.dispatch_pending(&mut self.dispatcher)
.unwrap()
== 0
{
let mut fds = [PollFd::new(
read_guard.connection_fd().as_raw_fd(),
PollFlags::POLLIN | nix::poll::PollFlags::POLLERR,
)];
let n = loop {
match nix::poll::poll(&mut fds, 1000) {
Ok(n) => break n,
Err(nix::errno::Errno::EINTR) => continue,
Err(_) => break 0,
}
};
if n > 0 {
read_guard.read().unwrap();
}
}
}
self.vsync_signaled.store(false, Ordering::Relaxed);
let _callback = self.wl_surface.frame(&self.event_queue_handle, ());
}
There could be another dispatch_pending
check before that to avoid locking if not necessary. But I don't think that matters in my use case, so I left it out.
Yeah, reading and processing events from multiple threads at the same time is kind of a pain point. I think your workaround is a good way to handle it, but I agree adding a blocking dispatch with timeout API to wayland-client would probably be the best, and I see no reason not to.
It would be nice to have a
blocking_dispatch
with a timeout.I'm trying to implement frame callbacks for Neovide, were we have the main logic and rendering loop in one thread, and the event processing in another thread. I want to add frame callbacks to the render thread, but with a timeout, so that it still can do some processing when a callback is not received for some time, maybe because the window is hidden or something.
I manged to get it to almost work by following the Integrating the event queue with other sources of events example, and polling the socket with a timeout.
However, there's one problem, I see regular short freezes, maybe once every other minute or so and tracked down the cause to the same as
blocking_read
is avoiding https://github.com/Smithay/wayland-rs/blob/90a9ad1f8f1fdef72e96d3c48bdb76b53a7722ff/wayland-client/src/event_queue.rs#L396-L404And I confirmed it by adding a short sleep between
dispatch_pending
andprepare_read
, a 2 ms delay make the short pauses very frequent.The problem is that I can't use the same workaround myself, since
inner
is private. So either that needs to be exposed, or better, provide a timeout forblocking_dispatch
.Edit: I think I could create yet another thread, and call 'blocking_dispatch` from that and handles the frame callbacks, and then uses a condition variable for example to signal when the frame callback happens, so that the rendering thread can wait for that with a timeout instead. But that seems like an unnecessary complicated thing to do.
My current work in progress code is here https://github.com/fredizzimo/neovide/blob/12aa5c74f330aed918a84eed561b262cbd1980c8/src/renderer/vsync_wayland.rs