fix(lvgl): stand the displays down while the app is suspended - #53
Merged
Merged
Conversation
An overlay claim on a dual-role surface left its own last frame on the glass after it released, under a live app. The board suppresses its blit door for the duration of a claim (every board in the fleet with a dual-role surface does this) — but suppression drops the PIXELS while LVGL goes on rendering and goes on getting its lv_display_flush_ready. The library believed those areas had reached the panel, so when the claim lifted nothing was dirty: the overlay's frame sat there with only the widgets that happened to change painting over it. A device whose app mutates on change — which is the idiom the authoring sheets teach — never repaints the rest at all. So LvglModule now stands its displays down while the app is suspended (the app cannot draw anything new while suspended, so nothing is lost) and stands them up on resume, which invalidates each active screen and repaints every pixel the overlay owned. Only for targets this module still owns: before an app's first bind there is nothing to repaint, and a target lgfx claimed is not ours. To hear about the suspension at all, onAppRunning moves from Driver up to Extension, and Sandbox::notifyAppRunning calls it on every declared extension rather than only the Drivers among them. That is the right home for it: the extension that most needs to know the app stopped is a graphics module, which owns no hardware and so was never a Driver. Existing Driver overrides are untouched — same signature, same slot. Found on an oracle (360x360 round face, dual-role) and reproduced in that board's wasm sim, where a still app left 129600 of 129600 pixels unrepainted after an agent_status claim released. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An overlay claim on a dual-role surface left its own last frame on the glass after it released, under a live app.
What happens
A board suppresses its blit door for the duration of a claim — every board in the fleet with a dual-role surface does this, so the overlay cannot be painted over a frame later. But suppression drops the pixels while LVGL goes on rendering and goes on getting its
lv_display_flush_ready. The library believed those areas had reached the panel, so when the claim lifted nothing was dirty: the overlay's frame sat there with only the widgets that happened to change painting over it.A body that mutates on change rather than rebuilding — the idiom the authoring sheets teach — never repaints the rest at all.
The fix
LvglModulestands its displays down while the app is suspended (a suspended app cannot draw anything new, so nothing is lost) and stands them up on resume, which invalidates each active screen and repaints every pixel the overlay owned. Only for targets this module still owns: before an app's first bind there is nothing to repaint, and a targetlgfxclaimed is not ours to touch.To hear about the suspension at all,
onAppRunningmoves fromDriverup toExtension, andSandbox::notifyAppRunningcalls it on every declared extension rather than only theDrivers among them. That is the right home for it: the extension that most needs to know the app stopped is a graphics module, which owns no hardware and so was never aDriver. ExistingDriveroverrides are untouched — same signature, same slot, so this is source-compatible.Evidence
Found on an oracle (360×360 round face, dual-role:
cfg.systemDisplayand an app surface) and reproduced in that board's wasm sim, where a still app left129600 of 129600pixels unrepainted after anagent_statusclaim released, and0with this change. The consumer repo now smokes that on every board with a status surface.test_overlaygains one case: a module-lessExtensionhears the overlay suspension.Version
0.8.6-dev, with
docs/changelog.mdanddocs/api.mdupdated (theExtensioninterface table, theDriver"added interface" section, and thesuspendAppparagraph, which said drivers receive the hook).🤖 Generated with Claude Code