Skip to content

Commit bf49be4

Browse files
committed
Waker support in standalone!
1 parent 53b6c01 commit bf49be4

7 files changed

Lines changed: 307 additions & 65 deletions

File tree

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ percent-encoding = "2.3.2"
5050
bytemuck = { version = "1.25.2", features = ["extern_crate_alloc"] }
5151
libloading = "0.8.9" # Libloading 0.9 is out but its MSRV is 1.88
5252
bitflags = "2.13.2"
53+
rustix = "1.1.4"
5354

5455
[target.'cfg(target_os="windows")'.dependencies]
5556
windows = { version = "0.62.2", features = [

‎src/platform/x11/event_loop.rs‎

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub(crate) struct EventLoop {
3737

3838
impl EventLoop {
3939
pub fn waker(&self) -> WindowWaker {
40-
todo!()
40+
self.shared.waker_source.create_waker()
4141
}
4242

4343
pub fn request_poll(&self) -> PlatformResult<()> {
@@ -55,13 +55,11 @@ impl EventLoop {
5555

5656
pub fn host_timer_callback(&self, timer_id: TimerId) {
5757
if let Some(timer) = self.shared.timer_manager.get_handle_if_exists(timer_id) {
58-
self.handler.on_timer(&timer.into())
59-
} else if let Some(redraw_timer) =
60-
self.shared.redraw_delayed_timers.get_handle_if_exists(timer_id)
61-
{
62-
self.shared.present_state.request_present_notify();
63-
self.shared.redraw_delayed_timers.destroy_timer(redraw_timer, &self.host);
64-
} else {
58+
self.handler.on_timer(&timer.into());
59+
return;
60+
}
61+
62+
if !self.shared.present_state.trigger_if_redraw_timer(timer_id, &self.host) {
6563
self.present_state.trigger_possible_fallback_frame_timer(timer_id);
6664
}
6765
}
@@ -95,17 +93,25 @@ impl EventLoop {
9593
self.show()?;
9694

9795
let connection = Rc::clone(&self.shared.connection);
98-
let mut poller = ConnectionPoller::new(&connection.conn)?;
96+
let waker_fd = self.shared.waker_source.inner_fd();
97+
let mut poller = ConnectionPoller::new(&connection.conn, &waker_fd)?;
9998

10099
self.shared.stop_own_event_loop.set(false);
101100

102101
while !self.shared.stop_own_event_loop.get() {
103102
let next_deadline = self.tick_all_timers();
104103
self.handle_idle()?;
105104

106-
if let PollStatus::ReadAvailable = poller.wait(next_deadline)? {
107-
self.flush_drain_xcb_events()?;
105+
match poller.wait(next_deadline)? {
106+
PollStatus::ReadAvailable => {
107+
self.flush_drain_xcb_events()?;
108+
}
109+
PollStatus::WakerTriggered => {
110+
self.shared.waker_source.poll_requests(&self.shared.present_state, &self.host);
111+
}
112+
_ => {}
108113
}
114+
109115
/*
110116
// Check if the user has requested the window to close
111117
if self.window.close_requested.get() {
@@ -157,7 +163,7 @@ impl EventLoop {
157163
fd_support.register_fd(self.shared.connection.conn.as_fd())?;
158164
self.fd_registered.set(true);
159165
} else {
160-
todo!()
166+
// TODO
161167
}
162168

163169
Ok(())
@@ -170,13 +176,7 @@ impl EventLoop {
170176
self.handler.on_timer(&triggered_timer.into());
171177
}
172178

173-
let (deadline_2, triggered_timer) = self.shared.redraw_delayed_timers.tick_next_timer();
174-
175-
if let Some(h) = triggered_timer {
176-
self.shared.present_state.request_present_notify();
177-
self.shared.redraw_delayed_timers.destroy_timer(h, &self.host);
178-
}
179-
179+
let deadline_2 = self.shared.present_state.tick_timers(&self.host);
180180
let deadline_3 = self.present_state.tick_fallback_frame_timer();
181181

182182
fn min_deadline(d1: Option<Instant>, d2: Option<Instant>) -> Option<Instant> {
@@ -386,7 +386,7 @@ impl Drop for EventLoop {
386386
fn drop(&mut self) {
387387
// Deinit timers & FD watchers
388388
self.shared.timer_manager.destroy_all(&self.host);
389-
self.shared.redraw_delayed_timers.destroy_all(&self.host);
389+
self.shared.present_state.destroy_redraw_timers(&self.host);
390390

391391
if self.fd_registered.get() {
392392
let Some(fd_support) = self.host.fd_support() else { unreachable!() };

‎src/platform/x11/present.rs‎

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,62 @@ use x11rb::protocol::xproto::ExposeEvent;
1414
pub struct PresentStateShared {
1515
present_notify_requested: Cell<bool>,
1616
poll_requested: Cell<bool>,
17+
redraw_delayed_timers: TimerManager,
1718
}
1819

1920
impl PresentStateShared {
20-
pub fn new() -> Self {
21-
Self { present_notify_requested: false.into(), poll_requested: false.into() }
21+
pub fn new(host: &HostHandle) -> Self {
22+
Self {
23+
present_notify_requested: false.into(),
24+
poll_requested: false.into(),
25+
redraw_delayed_timers: TimerManager::new(host),
26+
}
2227
}
2328

2429
pub fn request_present_notify(&self) {
2530
self.present_notify_requested.set(true)
2631
}
2732

28-
pub fn request_present_notify_after(
29-
&self, duration: Duration, host: &HostHandle, redraw_timers: &TimerManager,
30-
) {
33+
pub fn trigger_if_redraw_timer(&self, timer_id: TimerId, host: &HostHandle) -> bool {
34+
if let Some(redraw_timer) = self.redraw_delayed_timers.get_handle_if_exists(timer_id) {
35+
self.request_present_notify();
36+
self.redraw_delayed_timers.destroy_timer(redraw_timer, host);
37+
true
38+
} else {
39+
false
40+
}
41+
}
42+
43+
pub fn tick_timers(&self, host: &HostHandle) -> Option<Instant> {
44+
let (deadline, triggered_timer) = self.redraw_delayed_timers.tick_next_timer();
45+
46+
if let Some(h) = triggered_timer {
47+
self.request_present_notify();
48+
self.redraw_delayed_timers.destroy_timer(h, host);
49+
}
50+
51+
deadline
52+
}
53+
54+
pub fn destroy_redraw_timers(&self, host: &HostHandle) {
55+
self.redraw_delayed_timers.destroy_all(host);
56+
}
57+
58+
pub fn request_present_notify_after(&self, duration: Duration, host: &HostHandle) {
3159
if duration.is_zero() || duration.as_millis() < 1 {
3260
self.request_present_notify();
3361
return;
3462
}
3563

36-
if let Err(e) = redraw_timers.create_timer(duration, host) {
64+
if let Err(e) = self.redraw_delayed_timers.create_timer(duration, host) {
3765
warn!("{}", e);
3866
self.request_present_notify();
3967
}
4068
}
69+
70+
pub fn request_poll(&self) {
71+
self.poll_requested.set(true);
72+
}
4173
}
4274

4375
pub struct PresentState {

‎src/platform/x11/waker.rs‎

Lines changed: 147 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,171 @@
1-
use crate::platform::prelude::PlatformResult;
21
use crate::platform::x11::host_handle::HostHandle;
3-
use calloop::LoopSignal;
4-
use std::task::Waker;
5-
use std::time::Duration;
2+
use std::os::fd::{AsFd, BorrowedFd};
3+
use std::sync::atomic::{AtomicU8, Ordering};
4+
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError};
5+
use std::sync::Arc;
6+
use std::time::{Duration, Instant};
67

7-
pub(crate) struct WakerSource {}
8+
mod eventfd;
9+
use crate::platform::prelude::PresentStateShared;
10+
use crate::DropData;
11+
use eventfd::*;
12+
13+
// TODO: only instanciate FDs and stuff when first waker is created
14+
pub(crate) struct WakerSource {
15+
inner: EventFdWakerSource,
16+
flags: Arc<SharedFlags>,
17+
redraw_channel_send: SyncSender<Instant>,
18+
redraw_channel_recv: Receiver<Instant>,
19+
}
820

921
impl WakerSource {
1022
pub fn new(host: &HostHandle) -> Self {
11-
todo!()
23+
if host.fd_support().is_some() {
24+
} else if host.timer_support().is_some() {
25+
todo!()
26+
} else {
27+
}
28+
29+
let (send, recv) = std::sync::mpsc::sync_channel(100);
30+
31+
Self {
32+
inner: EventFdWakerSource::new(),
33+
flags: Arc::new(SharedFlags::new()),
34+
redraw_channel_recv: recv,
35+
redraw_channel_send: send,
36+
}
37+
}
38+
39+
pub fn create_waker(&self) -> WindowWaker {
40+
WindowWaker {
41+
inner: self.inner.create_waker(),
42+
flag: Arc::clone(&self.flags),
43+
redraw_channel_send: self.redraw_channel_send.clone(),
44+
}
1245
}
1346

14-
pub fn new_waker(&self) -> Waker {
15-
todo!()
47+
pub fn poll_requests(&self, present_state_shared: &PresentStateShared, host: &HostHandle) {
48+
if !self.inner.poll() {
49+
return;
50+
}
51+
52+
let flags = self.flags.take();
53+
let requests = self.get_all_redraw_requests();
54+
55+
for instant in requests {
56+
if let Some(duration) = instant.checked_duration_since(Instant::now()) {
57+
present_state_shared.request_present_notify_after(duration, host);
58+
} else {
59+
present_state_shared.request_present_notify()
60+
}
61+
}
62+
63+
if flags.poll() {
64+
present_state_shared.request_poll();
65+
}
66+
67+
if flags.redraw() {
68+
present_state_shared.request_present_notify();
69+
}
70+
71+
if flags.dropped() {
72+
// TODO
73+
}
74+
}
75+
76+
fn get_all_redraw_requests(&self) -> Vec<Instant> {
77+
let mut requests = vec![];
78+
79+
loop {
80+
match self.redraw_channel_recv.try_recv() {
81+
Ok(instant) => requests.push(instant),
82+
Err(TryRecvError::Empty) => break,
83+
Err(TryRecvError::Disconnected) => unreachable!(), // We always hold onto one sender
84+
}
85+
}
86+
87+
requests
88+
}
89+
90+
pub fn inner_fd(&self) -> BorrowedFd<'_> {
91+
self.inner.as_fd()
1692
}
1793
}
1894

1995
#[derive(Clone)]
2096
pub struct WindowWaker {
21-
pub(crate) loop_signal: LoopSignal,
97+
inner: EventFdWaker,
98+
flag: Arc<SharedFlags>,
99+
redraw_channel_send: SyncSender<Instant>,
22100
}
23101

24102
impl WindowWaker {
25103
pub fn request_redraw(&self) {
26-
self.request_redraw_after(Duration::ZERO)
104+
self.flag.set_redraw();
105+
self.inner.wake();
27106
}
28107

29108
pub fn request_redraw_after(&self, duration: Duration) {
30-
todo!()
109+
if duration.is_zero() {
110+
return self.request_redraw();
111+
}
112+
113+
self.redraw_channel_send.send(Instant::now() + duration).unwrap();
114+
self.inner.wake()
31115
}
32116

33117
pub fn request_poll(&self) {
34-
todo!()
118+
self.flag.set_poll();
119+
self.inner.wake();
120+
}
121+
}
122+
123+
impl Drop for WindowWaker {
124+
fn drop(&mut self) {
125+
self.flag.set_dropped();
126+
}
127+
}
128+
129+
struct SharedFlags(AtomicU8);
130+
131+
impl SharedFlags {
132+
pub fn new() -> Self {
133+
Self(AtomicU8::new(0))
134+
}
135+
136+
const POLL: u8 = 1 << 0;
137+
const REDRAW: u8 = 1 << 1;
138+
const DROPPED: u8 = 1 << 2;
139+
140+
fn set_poll(&self) {
141+
self.0.fetch_or(Self::POLL, Ordering::Release);
142+
}
143+
144+
fn set_redraw(&self) {
145+
self.0.fetch_or(Self::REDRAW, Ordering::Release);
146+
}
147+
148+
fn set_dropped(&self) {
149+
self.0.fetch_or(Self::DROPPED, Ordering::Release);
150+
}
151+
152+
fn take(&self) -> FlagsValues {
153+
FlagsValues(self.0.swap(0, Ordering::Acquire))
154+
}
155+
}
156+
157+
pub struct FlagsValues(u8);
158+
159+
impl FlagsValues {
160+
fn poll(&self) -> bool {
161+
self.0 & SharedFlags::POLL != 0
162+
}
163+
164+
fn redraw(&self) -> bool {
165+
self.0 & SharedFlags::REDRAW != 0
166+
}
167+
168+
fn dropped(&self) -> bool {
169+
self.0 & SharedFlags::DROPPED != 0
35170
}
36171
}

0 commit comments

Comments
 (0)