mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 13:51:30 +11:00
On Wayland, reduce amount of spurious wakeups
Mark it as breaking, since some clients relied on that behavior, simply because dispatching clients queue always woke up a winit, meaning that they won't be able to use user events for this sake.
This commit is contained in:
parent
3c3a863cc9
commit
cad3277550
|
@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
|||
|
||||
# Unreleased
|
||||
|
||||
- **Breaking:** on Wayland, dispatching user created wayland queue won't wake up the loop unless winit has event to send back.
|
||||
- Removed platform-specific extensions that should be retrieved through `raw-window-handle` trait implementations instead:
|
||||
- `platform::windows::HINSTANCE`.
|
||||
- `WindowExtWindows::hinstance`.
|
||||
|
|
|
@ -90,8 +90,15 @@ impl<T: 'static> EventLoop<T> {
|
|||
// Register Wayland source.
|
||||
let wayland_source = WaylandSource::new(event_queue)?;
|
||||
let wayland_dispatcher =
|
||||
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state| {
|
||||
queue.dispatch_pending(winit_state)
|
||||
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
|
||||
let result = queue.dispatch_pending(winit_state);
|
||||
if result.is_ok()
|
||||
&& (!winit_state.events_sink.is_empty()
|
||||
|| !winit_state.window_compositor_updates.is_empty())
|
||||
{
|
||||
winit_state.dispatched_events = true;
|
||||
}
|
||||
result
|
||||
});
|
||||
|
||||
event_loop
|
||||
|
@ -102,21 +109,25 @@ impl<T: 'static> EventLoop<T> {
|
|||
let pending_user_events = Rc::new(RefCell::new(Vec::new()));
|
||||
let pending_user_events_clone = pending_user_events.clone();
|
||||
let (user_events_sender, user_events_channel) = calloop::channel::channel();
|
||||
event_loop
|
||||
.handle()
|
||||
.insert_source(user_events_channel, move |event, _, _| {
|
||||
event_loop.handle().insert_source(
|
||||
user_events_channel,
|
||||
move |event, _, winit_state: &mut WinitState| {
|
||||
if let calloop::channel::Event::Msg(msg) = event {
|
||||
winit_state.dispatched_events = true;
|
||||
pending_user_events_clone.borrow_mut().push(msg);
|
||||
}
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
|
||||
// An event's loop awakener to wake up for window events from winit's windows.
|
||||
let (event_loop_awakener, event_loop_awakener_source) = calloop::ping::make_ping()?;
|
||||
event_loop
|
||||
.handle()
|
||||
.insert_source(event_loop_awakener_source, move |_, _, _| {
|
||||
event_loop.handle().insert_source(
|
||||
event_loop_awakener_source,
|
||||
move |_, _, winit_state: &mut WinitState| {
|
||||
// No extra handling is required, we just need to wake-up.
|
||||
})?;
|
||||
winit_state.dispatched_events = true;
|
||||
},
|
||||
)?;
|
||||
|
||||
let window_target = EventLoopWindowTarget {
|
||||
connection: connection.clone(),
|
||||
|
@ -220,6 +231,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
where
|
||||
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
|
||||
{
|
||||
let cause = loop {
|
||||
let start = Instant::now();
|
||||
|
||||
// TODO(rib): remove this workaround and instead make sure that the calloop
|
||||
|
@ -246,7 +258,11 @@ impl<T: 'static> EventLoop<T> {
|
|||
};
|
||||
|
||||
match queue.dispatch_pending(state) {
|
||||
Ok(dispatched) => dispatched > 0,
|
||||
Ok(dispatched) => {
|
||||
state.dispatched_events |= !state.events_sink.is_empty()
|
||||
|| !state.window_compositor_updates.is_empty();
|
||||
dispatched > 0
|
||||
}
|
||||
Err(error) => {
|
||||
error!("Error dispatching wayland queue: {}", error);
|
||||
self.control_flow = ControlFlow::ExitWithCode(1);
|
||||
|
@ -318,6 +334,15 @@ impl<T: 'static> EventLoop<T> {
|
|||
ControlFlow::ExitWithCode(_code) => unreachable!(),
|
||||
};
|
||||
|
||||
// Reduce spurious wake-ups.
|
||||
let dispatched_events = self.with_state(|state| state.dispatched_events);
|
||||
if matches!(cause, StartCause::WaitCancelled { .. }) && !dispatched_events {
|
||||
continue;
|
||||
}
|
||||
|
||||
break cause;
|
||||
};
|
||||
|
||||
self.single_iteration(&mut callback, cause);
|
||||
}
|
||||
|
||||
|
@ -531,6 +556,11 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Reset the hint that we've dispatched events.
|
||||
self.with_state(|state| {
|
||||
state.dispatched_events = false;
|
||||
});
|
||||
|
||||
// This is always the last event we dispatch before poll again
|
||||
sticky_exit_callback(
|
||||
Event::AboutToWait,
|
||||
|
|
|
@ -20,6 +20,12 @@ impl EventSink {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
/// Return `true` if there're pending events.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.window_events.is_empty()
|
||||
}
|
||||
|
||||
/// Add new device event to a queue.
|
||||
#[inline]
|
||||
pub fn push_device_event(&mut self, event: DeviceEvent, device_id: DeviceId) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
|
@ -104,6 +105,10 @@ pub struct WinitState {
|
|||
|
||||
/// Loop handle to re-register event sources, such as keyboard repeat.
|
||||
pub loop_handle: LoopHandle<'static, Self>,
|
||||
|
||||
/// Whether we have dispatched events to the user thus we want to
|
||||
/// send `AboutToWait` and normally wakeup the user.
|
||||
pub dispatched_events: bool,
|
||||
}
|
||||
|
||||
impl WinitState {
|
||||
|
@ -167,6 +172,8 @@ impl WinitState {
|
|||
monitors: Arc::new(Mutex::new(monitors)),
|
||||
events_sink: EventSink::new(),
|
||||
loop_handle,
|
||||
// Make it true by default.
|
||||
dispatched_events: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -328,6 +335,18 @@ impl CompositorHandler for WinitState {
|
|||
None => return,
|
||||
};
|
||||
|
||||
// In case we have a redraw requested we must indicate the wake up.
|
||||
if self
|
||||
.window_requests
|
||||
.get_mut()
|
||||
.get(&window_id)
|
||||
.unwrap()
|
||||
.redraw_requested
|
||||
.load(Ordering::Relaxed)
|
||||
{
|
||||
self.dispatched_events = true;
|
||||
}
|
||||
|
||||
window.lock().unwrap().frame_callback_received();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,11 +287,15 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
self.window_requests
|
||||
if self
|
||||
.window_requests
|
||||
.redraw_requested
|
||||
.store(true, Ordering::Relaxed);
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
self.event_loop_awakener.ping();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pre_present_notify(&self) {
|
||||
|
|
Loading…
Reference in a new issue