Switch focused render mode to reactive (render on demand) to save battery #78

Closed
opened 2026-05-29 20:11:42 +00:00 by funman300 · 1 comment
Owner

Background

"More battery life gains can be made by rendering on demand" — Quaternions

The VSync fix (PresentMode::AutoVsync on Android) capped the GPU at the display refresh rate and eliminated the ~1000 fps runaway. The next step is to stop rendering entirely when the game is idle — no animations playing, no drag in progress, no input received.

Current state

// solitaire_app/src/lib.rs
app.insert_resource(WinitSettings {
    focused_mode: UpdateMode::Continuous,   // renders every vsync tick regardless
    unfocused_mode: UpdateMode::reactive_low_power(Duration::from_secs(1)),
});

UpdateMode::Continuous renders on every vsync even when the board is static — wasting CPU, GPU, and battery between player actions.

Goal

Switch to render-on-demand while focused:

focused_mode: UpdateMode::reactive_low_power(Duration::from_millis(100)),

Bevy will then only re-render when:

  • A window or input event arrives (touch, tap, keyboard)
  • A Bevy system explicitly calls window.request_redraw() (needed for animations)

Work required

  1. Change focused_mode to UpdateMode::reactive_low_power(...) on Android (and optionally desktop).
  2. Audit all animation systems (card_animation_plugin, feedback_anim, auto_complete_plugin) — they must call window.request_redraw() each frame they are actively animating, otherwise animations will stall.
  3. Audit the elapsed-time ticker (tick_elapsed_time in game_plugin) — it fires every frame; under reactive mode it should only tick while the game is unpaused and the HUD timer is visible.
  4. Verify on device: animations must remain smooth; the board must not freeze between taps.

Expected outcome

  • Zero GPU frames rendered during idle (board fully settled, no input).
  • Full animation framerate maintained during card moves and auto-complete.
  • Measurable battery improvement on a sustained play session.

Labels

  • enhancement
  • android
  • performance
## Background > "More battery life gains can be made by rendering on demand" — Quaternions The VSync fix (`PresentMode::AutoVsync` on Android) capped the GPU at the display refresh rate and eliminated the ~1000 fps runaway. The next step is to stop rendering entirely when the game is idle — no animations playing, no drag in progress, no input received. ## Current state ```rust // solitaire_app/src/lib.rs app.insert_resource(WinitSettings { focused_mode: UpdateMode::Continuous, // renders every vsync tick regardless unfocused_mode: UpdateMode::reactive_low_power(Duration::from_secs(1)), }); ``` `UpdateMode::Continuous` renders on every vsync even when the board is static — wasting CPU, GPU, and battery between player actions. ## Goal Switch to **render-on-demand** while focused: ```rust focused_mode: UpdateMode::reactive_low_power(Duration::from_millis(100)), ``` Bevy will then only re-render when: - A window or input event arrives (touch, tap, keyboard) - A Bevy system explicitly calls `window.request_redraw()` (needed for animations) ## Work required 1. Change `focused_mode` to `UpdateMode::reactive_low_power(...)` on Android (and optionally desktop). 2. Audit all animation systems (`card_animation_plugin`, `feedback_anim`, `auto_complete_plugin`) — they must call `window.request_redraw()` each frame they are actively animating, otherwise animations will stall. 3. Audit the elapsed-time ticker (`tick_elapsed_time` in `game_plugin`) — it fires every frame; under reactive mode it should only tick while the game is unpaused and the HUD timer is visible. 4. Verify on device: animations must remain smooth; the board must not freeze between taps. ## Expected outcome - Zero GPU frames rendered during idle (board fully settled, no input). - Full animation framerate maintained during card moves and auto-complete. - Measurable battery improvement on a sustained play session. ## Labels - enhancement - android - performance
Author
Owner

Fixed in 38e4c03.

Changed focused_mode from UpdateMode::Continuous to UpdateMode::reactive_low_power(Duration::from_millis(100)) on Android. The 100 ms ceiling ensures the game timer updates ~10×/s even with no input; animations self-sustain at full frame rate via the RequestRedraw chain added in #79. The GPU is now completely idle between frames when the board is static, which should meaningfully extend battery life.

Fixed in 38e4c03. Changed `focused_mode` from `UpdateMode::Continuous` to `UpdateMode::reactive_low_power(Duration::from_millis(100))` on Android. The 100 ms ceiling ensures the game timer updates ~10×/s even with no input; animations self-sustain at full frame rate via the `RequestRedraw` chain added in #79. The GPU is now completely idle between frames when the board is static, which should meaningfully extend battery life.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/Ferrous-Solitaire#78