Selkie.git | lib/Selkie/App/Internal/ | IdleBudget.rakumod
=begin pod
=head1 NAME
Selkie::App::Internal::IdleBudget - internal frame-budget helpers for Selkie::App
=head1 DESCRIPTION
Implementation detail for C<Selkie::App>. Use C<Selkie::App> and
C<Selkie::App::pick-frame-budget> from application code.
=end pod
unit module Selkie::App::Internal::IdleBudget;
# Idle-tier constants are implementation detail for Selkie::App's run loop.
my constant IDLE-HALF = 1e0 / 30e0; # 30 Hz = ~33 ms
my constant IDLE-QUARTER = 1e0 / 12e0; # 12 Hz = ~83 ms
my constant IDLE-DEEP = 1e0 / 4e0; # 4 Hz = 250 ms
my constant STORE-ACTIVITY-MIN-BUDGET = IDLE-HALF;
our constant APP-SLEEP-CHUNK-MAX is export = 0.1e0;
sub app-ladder-tier(Num:D $idle-for, Num:D $hot-budget --> Num:D) {
given $idle-for {
when * < 30e0 { $hot-budget }
when * < 60e0 { IDLE-HALF }
when * < 120e0 { IDLE-QUARTER }
default { IDLE-DEEP }
}
}
sub pick-app-frame-budget(
Num:D $hot-budget,
Num:D $user-idle-for,
Num:D $store-idle-for,
Bool:D :$animating = False,
--> Num:D
) is export {
# An animation is sampled, not triggered: it needs frames whether or
# not anything has happened recently. Bypassing the ladder here (as
# opposed to poking the user-activity clock) keeps the tween from
# leaving a 30-second hot tail behind it once it finishes.
return $hot-budget if $animating;
my Num $user-budget = app-ladder-tier($user-idle-for, $hot-budget);
my Num $store-budget = max(
app-ladder-tier($store-idle-for, $hot-budget),
STORE-ACTIVITY-MIN-BUDGET,
);
max(min($user-budget, $store-budget), $hot-budget);
}