Skip to main content

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}