flatland_frame_scheduling_lib/
throughput_scheduler.rs
1use crate::{
6 PresentParameters, PresentationInfo, SchedulingFuture, SchedulingFutureState, SchedulingLib,
7};
8use async_trait::async_trait;
9use fuchsia_async::MonotonicInstant as fasync_time;
10use fuchsia_trace as trace;
11use std::cell::{Cell, RefCell};
12use std::task::Waker;
13
14pub struct ThroughputScheduler {
26 data: RefCell<WakeupData>,
27 next_expected_times: Cell<PresentationInfo>,
28 wait_guard: RefCell<()>,
29}
30
31struct WakeupData {
34 frame_requested: bool,
35 next_frame_begin: bool,
36 waker: Option<Waker>,
37}
38
39impl ThroughputScheduler {
40 pub fn new() -> ThroughputScheduler {
41 let now = fasync_time::now().into_zx();
42 ThroughputScheduler {
43 data: RefCell::new(WakeupData {
44 frame_requested: false,
45 next_frame_begin: true,
46 waker: None,
47 }),
48 next_expected_times: Cell::new(PresentationInfo {
49 latch_point: now,
50 presentation_time: now,
51 }),
52 wait_guard: RefCell::new(()),
53 }
54 }
55}
56
57#[async_trait(?Send)]
58impl SchedulingLib for ThroughputScheduler {
59 fn request_present(&self) {
60 self.data.borrow_mut().frame_requested = true;
61 self.data.borrow().maybe_wakeup();
62 }
63
64 fn on_next_frame_begin(
65 &self,
66 _additional_present_credits: u32,
67 future_presentation_infos: Vec<PresentationInfo>,
68 ) {
69 assert!(!future_presentation_infos.is_empty());
70 self.next_expected_times.set(future_presentation_infos[0]);
71 self.data.borrow_mut().next_frame_begin = true;
72 self.data.borrow().maybe_wakeup();
73 }
74
75 async fn wait_to_update(&self) -> PresentParameters {
77 let _guard = self.wait_guard.try_borrow_mut().expect("Only one wait at a time allowed");
81 let _trace_guard =
83 trace::async_enter!(trace::Id::new(), c"gfx", c"ThroughputScheduler::WaitForPresent");
84
85 SchedulingFuture { sched: &self.data }.await;
87
88 {
89 let mut data = self.data.borrow_mut();
91 data.frame_requested = false;
92 data.next_frame_begin = false;
93 data.waker = None;
94 }
95
96 let PresentationInfo { latch_point, presentation_time } = self.next_expected_times.get();
97 PresentParameters {
98 expected_latch_point: latch_point,
99 expected_presentation_time: presentation_time,
100 requested_presentation_time: zx::MonotonicInstant::from_nanos(0),
101 unsquashable: false,
102 }
103 }
104}
105
106impl SchedulingFutureState for WakeupData {
107 fn ready_to_wake_up(&self) -> bool {
108 self.frame_requested && self.next_frame_begin
109 }
110
111 fn set_waker(&mut self, waker: Waker) {
112 self.waker = Some(waker);
113 }
114
115 fn get_waker(&self) -> &Option<Waker> {
116 &self.waker
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use assert_matches::assert_matches;
124 use fuchsia_async as fasync;
125 use std::task::Poll;
126
127 #[test]
128 fn wait_without_request_present_never_completes() {
129 let mut exec = fasync::TestExecutor::new();
130 let sched = ThroughputScheduler::new();
131 let mut fut = sched.wait_to_update();
132 assert!(exec.run_until_stalled(&mut fut).is_pending());
133
134 sched.request_present();
136 assert_matches!(
137 exec.run_until_stalled(&mut fut),
138 Poll::Ready(PresentParameters {
139 expected_latch_point: _,
140 expected_presentation_time: _,
141 requested_presentation_time: _,
142 unsquashable: false,
143 })
144 );
145 }
146
147 #[fasync::run_until_stalled(test)]
148 async fn wait_after_initial_request_present_completes_immediately() {
149 let sched = ThroughputScheduler::new();
150 sched.request_present();
151 assert_matches!(
152 sched.wait_to_update().await,
153 PresentParameters {
154 expected_latch_point: _,
155 expected_presentation_time: _,
156 requested_presentation_time: _,
157 unsquashable: false,
158 }
159 );
160 }
161
162 #[test]
163 fn following_waits_never_completes_without_on_next_frame_begin() {
164 let mut exec = fasync::TestExecutor::new();
165 let sched = ThroughputScheduler::new();
166 sched.request_present();
168 let mut fut = sched.wait_to_update();
169 exec.run_until_stalled(&mut fut).is_ready();
170
171 sched.request_present();
173 let mut fut = sched.wait_to_update();
174 assert!(exec.run_until_stalled(&mut fut).is_pending());
175
176 sched.on_next_frame_begin(
177 10,
178 vec![PresentationInfo {
179 latch_point: zx::MonotonicInstant::from_nanos(1),
180 presentation_time: zx::MonotonicInstant::from_nanos(1),
181 }],
182 );
183 assert_eq!(
184 exec.run_until_stalled(&mut fut),
185 Poll::Ready(PresentParameters {
186 expected_latch_point: zx::MonotonicInstant::from_nanos(1),
187 expected_presentation_time: zx::MonotonicInstant::from_nanos(1),
188 requested_presentation_time: zx::MonotonicInstant::from_nanos(0),
189 unsquashable: false,
190 })
191 );
192 }
193}