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}