compositing/
refresh_driver.rs1use std::cell::Cell;
6use std::collections::hash_map::Values;
7use std::sync::Arc;
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::thread::{self, JoinHandle};
10use std::time::Duration;
11
12use base::id::WebViewId;
13use constellation_traits::EmbedderToConstellationMessage;
14use crossbeam_channel::{Sender, select};
15use embedder_traits::EventLoopWaker;
16use log::warn;
17use timers::{BoxedTimerCallback, TimerEventRequest, TimerScheduler};
18
19use crate::compositor::RepaintReason;
20use crate::webview_renderer::WebViewRenderer;
21
22const FRAME_DURATION: Duration = Duration::from_millis(1000 / 120);
23
24pub(crate) struct RefreshDriver {
31 pub(crate) constellation_sender: Sender<EmbedderToConstellationMessage>,
33
34 pub(crate) animating: Cell<bool>,
36
37 pub(crate) waiting_for_frame_timeout: Arc<AtomicBool>,
39
40 timer_thread: TimerThread,
42
43 event_loop_waker: Box<dyn EventLoopWaker>,
46}
47
48impl RefreshDriver {
49 pub(crate) fn new(
50 constellation_sender: Sender<EmbedderToConstellationMessage>,
51 event_loop_waker: Box<dyn EventLoopWaker>,
52 ) -> Self {
53 Self {
54 constellation_sender,
55 animating: Default::default(),
56 waiting_for_frame_timeout: Default::default(),
57 timer_thread: Default::default(),
58 event_loop_waker,
59 }
60 }
61
62 fn timer_callback(&self) -> BoxedTimerCallback {
63 let waiting_for_frame_timeout = self.waiting_for_frame_timeout.clone();
64 let event_loop_waker = self.event_loop_waker.clone_box();
65 Box::new(move || {
66 waiting_for_frame_timeout.store(false, Ordering::Relaxed);
67 event_loop_waker.wake();
68 })
69 }
70
71 pub(crate) fn notify_will_paint(
74 &self,
75 webview_renderers: Values<'_, WebViewId, WebViewRenderer>,
76 ) {
77 if self.waiting_for_frame_timeout.load(Ordering::Relaxed) {
81 return;
82 }
83
84 let animating_webviews: Vec<_> = webview_renderers
86 .filter_map(|webview_renderer| {
87 if webview_renderer.animating() {
88 Some(webview_renderer.id)
89 } else {
90 None
91 }
92 })
93 .collect();
94
95 if animating_webviews.is_empty() {
98 self.animating.set(false);
99 return;
100 }
101
102 if let Err(error) =
103 self.constellation_sender
104 .send(EmbedderToConstellationMessage::TickAnimation(
105 animating_webviews,
106 ))
107 {
108 warn!("Sending tick to constellation failed ({error:?}).");
109 }
110
111 self.animating.set(true);
113 self.waiting_for_frame_timeout
114 .store(true, Ordering::Relaxed);
115 self.timer_thread
116 .queue_timer(FRAME_DURATION, self.timer_callback());
117 }
118
119 pub(crate) fn notify_animation_state_changed(&self, webview_renderer: &WebViewRenderer) {
124 if !webview_renderer.animating() {
125 return;
128 }
129
130 if let Err(error) =
131 self.constellation_sender
132 .send(EmbedderToConstellationMessage::TickAnimation(vec![
133 webview_renderer.id,
134 ]))
135 {
136 warn!("Sending tick to constellation failed ({error:?}).");
137 }
138
139 if self.animating.get() {
140 return;
141 }
142
143 self.animating.set(true);
144 self.waiting_for_frame_timeout
145 .store(true, Ordering::Relaxed);
146 self.timer_thread
147 .queue_timer(FRAME_DURATION, self.timer_callback());
148 }
149
150 pub(crate) fn wait_to_paint(&self, repaint_reason: RepaintReason) -> bool {
155 if !self.animating.get() || repaint_reason != RepaintReason::NewWebRenderFrame {
156 return false;
157 }
158
159 self.waiting_for_frame_timeout.load(Ordering::Relaxed)
160 }
161}
162
163enum TimerThreadMessage {
164 Request(TimerEventRequest),
165 Quit,
166}
167
168struct TimerThread {
177 sender: Sender<TimerThreadMessage>,
178 join_handle: Option<JoinHandle<()>>,
179}
180
181impl Drop for TimerThread {
182 fn drop(&mut self) {
183 let _ = self.sender.send(TimerThreadMessage::Quit);
184 if let Some(join_handle) = self.join_handle.take() {
185 let _ = join_handle.join();
186 }
187 }
188}
189
190impl Default for TimerThread {
191 fn default() -> Self {
192 let (sender, receiver) = crossbeam_channel::unbounded::<TimerThreadMessage>();
193 let join_handle = thread::Builder::new()
194 .name(String::from("CompositorTimerThread"))
195 .spawn(move || {
196 let mut scheduler = TimerScheduler::default();
197
198 loop {
199 select! {
200 recv(receiver) -> message => {
201 match message {
202 Ok(TimerThreadMessage::Request(request)) => {
203 scheduler.schedule_timer(request);
204 },
205 _ => return,
206 }
207 },
208 recv(scheduler.wait_channel()) -> _message => {
209 scheduler.dispatch_completed_timers();
210 },
211 };
212 }
213 })
214 .expect("Could not create RefreshDriver timer thread.");
215
216 Self {
217 sender,
218 join_handle: Some(join_handle),
219 }
220 }
221}
222
223impl TimerThread {
224 fn queue_timer(&self, duration: Duration, callback: BoxedTimerCallback) {
225 let _ = self
226 .sender
227 .send(TimerThreadMessage::Request(TimerEventRequest {
228 callback,
229 duration,
230 }));
231 }
232}