compositing/
refresh_driver.rs1use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7use std::sync::Arc;
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::thread::{self, JoinHandle};
10use std::time::Duration;
11
12use constellation_traits::EmbedderToConstellationMessage;
13use crossbeam_channel::{Sender, select};
14use embedder_traits::{EventLoopWaker, RefreshDriver};
15use log::warn;
16use timers::{BoxedTimerCallback, TimerEventRequest, TimerScheduler};
17
18use crate::compositor::RepaintReason;
19use crate::painter::Painter;
20use crate::webview_renderer::WebViewRenderer;
21
22pub(crate) struct BaseRefreshDriver {
28    waiting_for_frame: Arc<AtomicBool>,
31    event_loop_waker: Box<dyn EventLoopWaker>,
33    observers: RefCell<Vec<Rc<dyn RefreshDriverObserver>>>,
35    refresh_driver: Rc<dyn RefreshDriver>,
38}
39
40impl BaseRefreshDriver {
41    pub(crate) fn new(
42        event_loop_waker: Box<dyn EventLoopWaker>,
43        refresh_driver: Option<Rc<dyn RefreshDriver>>,
44    ) -> Self {
45        let refresh_driver =
46            refresh_driver.unwrap_or_else(|| Rc::new(TimerRefreshDriver::default()));
47        Self {
48            waiting_for_frame: Arc::new(AtomicBool::new(false)),
49            event_loop_waker,
50            observers: Default::default(),
51            refresh_driver,
52        }
53    }
54
55    pub(crate) fn add_observer(&self, observer: Rc<dyn RefreshDriverObserver>) {
56        let mut observers = self.observers.borrow_mut();
57        observers.push(observer);
58
59        if observers.len() == 1 {
61            self.observe_next_frame();
62        }
63    }
64
65    pub(crate) fn notify_will_paint(&self, painter: &mut Painter) {
66        if self.waiting_for_frame.load(Ordering::Relaxed) {
70            return;
71        }
72
73        let still_has_observers = {
75            let mut observers = self.observers.borrow_mut();
76            observers.retain(|observer| observer.frame_started(painter));
77            !observers.is_empty()
78        };
79
80        if still_has_observers {
81            self.observe_next_frame();
82        }
83    }
84
85    fn observe_next_frame(&self) {
86        self.waiting_for_frame.store(true, Ordering::Relaxed);
87
88        let waiting_for_frame = self.waiting_for_frame.clone();
89        let event_loop_waker = self.event_loop_waker.clone_box();
90        self.refresh_driver.observe_next_frame(Box::new(move || {
91            waiting_for_frame.store(false, Ordering::Relaxed);
92            event_loop_waker.wake();
93        }));
94    }
95
96    pub(crate) fn wait_to_paint(&self, repaint_reason: RepaintReason) -> bool {
101        if self.observers.borrow().is_empty() || repaint_reason != RepaintReason::NewWebRenderFrame
102        {
103            return false;
104        }
105
106        self.waiting_for_frame.load(Ordering::Relaxed)
107    }
108}
109
110pub(crate) trait RefreshDriverObserver {
115    fn frame_started(&self, painter: &mut Painter) -> bool;
119}
120
121pub(crate) struct AnimationRefreshDriverObserver {
126    pub(crate) constellation_sender: Sender<EmbedderToConstellationMessage>,
128
129    pub(crate) animating: Cell<bool>,
131}
132
133impl AnimationRefreshDriverObserver {
134    pub(crate) fn new(constellation_sender: Sender<EmbedderToConstellationMessage>) -> Self {
135        Self {
136            constellation_sender,
137            animating: Default::default(),
138        }
139    }
140
141    pub(crate) fn notify_animation_state_changed(
142        &self,
143        webview_renderer: &WebViewRenderer,
144    ) -> bool {
145        if !webview_renderer.animating() {
146            return false;
149        }
150
151        if let Err(error) =
152            self.constellation_sender
153                .send(EmbedderToConstellationMessage::TickAnimation(vec![
154                    webview_renderer.id,
155                ]))
156        {
157            warn!("Sending tick to constellation failed ({error:?}).");
158        }
159
160        if self.animating.get() {
161            return false;
162        }
163
164        self.animating.set(true);
165        true
166    }
167}
168
169impl RefreshDriverObserver for AnimationRefreshDriverObserver {
170    fn frame_started(&self, painter: &mut Painter) -> bool {
171        let animating_webviews = painter.animating_webviews();
173
174        if animating_webviews.is_empty() {
177            self.animating.set(false);
178            return false;
179        }
180
181        if let Err(error) =
183            self.constellation_sender
184                .send(EmbedderToConstellationMessage::TickAnimation(
185                    animating_webviews,
186                ))
187        {
188            warn!("Sending tick to constellation failed ({error:?}).");
189            return false;
190        }
191
192        self.animating.set(true);
193        true
194    }
195}
196
197enum TimerThreadMessage {
198    Request(TimerEventRequest),
199    Quit,
200}
201
202struct TimerRefreshDriver {
211    sender: Sender<TimerThreadMessage>,
212    join_handle: Option<JoinHandle<()>>,
213}
214
215impl Default for TimerRefreshDriver {
216    fn default() -> Self {
217        let (sender, receiver) = crossbeam_channel::unbounded::<TimerThreadMessage>();
218        let join_handle = thread::Builder::new()
219            .name(String::from("CompositorTimerThread"))
220            .spawn(move || {
221                let mut scheduler = TimerScheduler::default();
222
223                loop {
224                    select! {
225                        recv(receiver) -> message => {
226                            match message {
227                                Ok(TimerThreadMessage::Request(request)) => {
228                                    scheduler.schedule_timer(request);
229                                },
230                                _ => return,
231                            }
232                        },
233                        recv(scheduler.wait_channel()) -> _message => {
234                            scheduler.dispatch_completed_timers();
235                        },
236                    };
237                }
238            })
239            .expect("Could not create RefreshDriver timer thread.");
240
241        Self {
242            sender,
243            join_handle: Some(join_handle),
244        }
245    }
246}
247
248impl TimerRefreshDriver {
249    fn queue_timer(&self, duration: Duration, callback: BoxedTimerCallback) {
250        let _ = self
251            .sender
252            .send(TimerThreadMessage::Request(TimerEventRequest {
253                callback,
254                duration,
255            }));
256    }
257}
258
259impl RefreshDriver for TimerRefreshDriver {
260    fn observe_next_frame(&self, new_start_frame_callback: Box<dyn Fn() + Send + 'static>) {
261        const FRAME_DURATION: Duration = Duration::from_millis(1000 / 120);
262        self.queue_timer(FRAME_DURATION, new_start_frame_callback);
263    }
264}
265
266impl Drop for TimerRefreshDriver {
267    fn drop(&mut self) {
268        let _ = self.sender.send(TimerThreadMessage::Quit);
269        if let Some(join_handle) = self.join_handle.take() {
270            let _ = join_handle.join();
271        }
272    }
273}