Skip to main content

FrameGate

Struct FrameGate 

Source
pub struct FrameGate { /* private fields */ }
Expand description

The per-shell skip-frame gate: a plain struct — no globals — a shell constructs once and drives each frame via decide.

Owns two pieces of state: whether the gate is enabled at all (the NO_FRAME_GATE_VAR kill switch, resolved once at construction) and the resume-warmup countdown (WARMUP_FRAMES, seeded by note_resumed) — the standalone, host-testable decision type the mobile shells wire in.

Implementations§

Source§

impl FrameGate

Source

pub fn new() -> Self

A gate honoring the NO_FRAME_GATE_VAR kill switch — what every shell constructs. When the variable is set (compile-time --define or runtime env, any non-"0" value), this is equivalent to disabled.

Source

pub fn disabled() -> Self

A gate that always Runs regardless of inputs — the explicit disabled/kill-switch form (and a test seam bypassing the env read). Mirrors FrameGate::new’s behavior when NO_FRAME_GATE_VAR is set.

Source

pub fn with_enabled(enabled: bool) -> Self

Construct with an explicit enabled flag, bypassing the env read — the test/advanced seam (mirrors crate::perf::FrameStats::new_enabled). Animation pacing follows enabled (a disabled gate never paces because it never skips); use with_flags to vary the two independently.

Source

pub fn with_flags(enabled: bool, anim_pacing: bool) -> Self

Construct with explicit enabled (whole-frame skip) and anim_pacing (paced-loop throttling) flags, bypassing both env reads — the test seam for the pacing behavior in isolation.

Source

pub fn is_enabled(&self) -> bool

Whether the gate is active (can ever return FrameDecision::Skip). false for a disabled gate or when the kill switch is engaged.

Source

pub fn note_resumed(&mut self)

Open the resume-warmup window: the next WARMUP_FRAMES decide calls force a FrameDecision::Run.

A shell calls this on resume and on surface (re)creation, where the first tick’s change signals may not yet be observable (see WARMUP_FRAMES).

Source

pub fn warmup_remaining(&self) -> u8

Frames left in the resume-warmup window (0 when not warming up). Exposed for tests/diagnostics.

Source

pub fn decide(&mut self, inputs: FrameInputs) -> FrameDecision

Decide whether this frame runs.

Returns FrameDecision::Run when any of:

otherwise FrameDecision::Skip. See FrameInputs’s docs for what each input signal means.

Takes &mut self because it advances the resume-warmup countdown.

This is the non-paced entry: a paced-only frame runs on every tick (no throttling), the conservative pre-pacing behavior. Use decide_paced to honor the theme’s cosmetic-loop cadence.

Source

pub fn decide_paced( &mut self, inputs: FrameInputs, pacing: FramePacing, ) -> FrameDecision

Decide whether this frame runs, honoring animation pacing.

Identical to decide except that when the only dirtiness is a paced (CosmeticLoop) frame request (FrameInputs::is_paced_only_frame) and pacing is enabled, the frame is throttled to FramePacing::effective_interval (the theme cap folded with the previous paint’s requested interval): it runs only once pacing.now - last_paced_run >= interval, otherwise Skips. A skip leaves last_needs_frame alive (the shell doesn’t repaint, so it never re-latches), so the gate keeps waking and never starves the loop; the interval is re-anchored to the clock of every produced frame (whatever its cause), so a transition frame mid-loop resets the cadence.

Any non-paced input (an event, a signal write, a transition request, pending change flags, …) makes is_paced_only_frame false, so the frame runs immediately — pacing never delays real work.

The focus/IME edge tightens the tick back to the theme cap. The one wake input that rides inside a paced decision (FrameInputs::focus_or_ime_changed) has its deferral bounded by the interval in force, so honoring a long per-request interval on that tick would stretch a focus/IME transition’s repaint out to (say) a caret’s 500ms. Instead a tick carrying the edge paces at FramePacing::interval — the theme’s own cap — leaving the edge’s worst-case deferral exactly what it was before per-request intervals existed: one cosmetic_loop_rate interval (33ms at the 30Hz default; ≤100ms at CosmeticLoopRate::FLOOR_HZ). The cost is at most one extra frame per focus/IME transition — an edge reporting one transition, not a per-tick level (see docs/LIMITATIONS.md’s focus-ime-edge-paced-deferral).

That bound only holds end-to-end because the shells peek the edge: the tightening itself resolves most edge-carrying ticks to Skip (the anchor is typically one vsync old, well inside the cap), so a shell that drained its generation cache at gather time would erase the edge on the very tick the tightening deferred it, and the repaint would fall back to the full FramePacing::effective_interval. The edge must keep being reported until a tick actually runs — see FrameInputs::focus_or_ime_changed.

Trait Implementations§

Source§

impl Debug for FrameGate

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for FrameGate

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> StorageAccess<T> for T

Source§

fn as_borrowed(&self) -> &T

Borrows the value.
Source§

fn into_taken(self) -> T

Takes the value.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.