cranpose_app_shell/frame_scheduler.rs
1use std::cell::Cell;
2
3use crate::{FrameSchedule, PlatformFrameDriver};
4
5/// Stores the latest [`FrameSchedule`] of a surface for the platform code that drives it. A
6/// surface lives on its shell's thread, so the schedule sits in a `Cell`: on ESP-IDF a `Mutex`
7/// is a FreeRTOS mutex, which every frame took.
8#[derive(Debug, Default)]
9pub struct FrameScheduler {
10 latest: Cell<FrameSchedule>,
11 // Whether a schedule recorded since the surface's last frame asked for no
12 // frame and no update: the app held still between the two frames.
13 held_still: Cell<bool>,
14}
15
16impl FrameScheduler {
17 /// Stores `schedule` as the latest one. A schedule that needs an update drops its deadline.
18 pub fn record(&self, schedule: FrameSchedule) {
19 if !schedule.needs_frame && !schedule.needs_update {
20 self.held_still.set(true);
21 }
22 self.latest.set(FrameSchedule {
23 next_deadline: if schedule.needs_update {
24 None
25 } else {
26 schedule.next_deadline
27 },
28 ..schedule
29 });
30 }
31
32 /// Stores `schedule` and asks `driver` for the frame or wake it calls for.
33 pub fn schedule<D>(&self, schedule: FrameSchedule, driver: &D)
34 where
35 D: PlatformFrameDriver + ?Sized,
36 {
37 self.record(schedule);
38 schedule.apply_to(driver);
39 }
40
41 /// Returns the latest stored schedule.
42 pub fn snapshot(&self) -> FrameSchedule {
43 self.latest.get()
44 }
45
46 // Whether the app held still since the last call, which each frame of
47 // the surface makes.
48 pub(crate) fn take_held_still(&self) -> bool {
49 self.held_still.take()
50 }
51}