Improve framebuffer transitions and screen initialization - #1940
Open
robcodedev wants to merge 3 commits into
Open
Improve framebuffer transitions and screen initialization#1940robcodedev wants to merge 3 commits into
robcodedev wants to merge 3 commits into
Conversation
fbset requests a geometry and returns without verifying that the driver has latched it. Runtime also always asked for two virtual pages, even though MainUI uses three, and stale framebuffer contents were left in memory when page boundaries moved. That last part causes the sheared frames seen around 752x560 handoffs. A 640 page can start inside a 752 page, so pixels written at a 3008-byte stride can briefly be scanned out at 2560 bytes per row. Add fbmode, which verifies both visible and virtual geometry, clears using the driver's real post-switch line_length, can preclear before a pitch change, and leaves scanout parked on page 0. Make launch_switcher the single owner of GameSwitcher's 752x560 requirement. A game exiting toward GameSwitcher leaves the framebuffer alone, and launch_switcher probes first so an already-correct 752x560 two-page layout is left untouched. Leave the framebuffer alone when a shutdown is pending too. keymon draws the End_Save screen from deepsleep() and backgrounds it, so it is usually still rendering when the game exits and runtime reaches the post-game resolution change. bootScreen reads the geometry once at startup and writes rows at that pitch, so changing the mode underneath it shears the shutdown screen. Nothing after that point needs 640x480. On 752x560-capable devices, establish MainUI's 640x480 three-page layout in init_system before the boot screen is drawn. launch_main_ui probes that layout and preserves it when already correct; if a real change is needed it preclears before committing the new geometry. Existing resolution-change paths retain fbset fallback. The new preparation paths only run when fbmode is available, and failed mode changes fall back to fbset where a transition is required.
Not everyone wants 560p on a 752x560 panel. Drop a .force640Res file in $sysdir/config and runtime keeps the framebuffer at 640x480. The override is applied after resolution detection. When set, it pins screen_resolution to 640x480, removes /tmp/new_res_available, and establishes the 640x480 three-page layout through fbmode. Removing /tmp/new_res_available means the rest of runtime takes the same paths it would on a device that never exposed 560p, rather than every call site needing to know about the override. The actual mode used by Onion is written to /tmp/screen_resolution. No flag, no behaviour change.
get_screen_resolution polled /proc/mi_modules/fb/mi_fb0 every 500ms until the driver came up. On some boots that costs 3 seconds or more, and the 500ms interval can add almost another half-second after the driver is actually ready. Try three sources in order instead: 1. Read mi_fb0 once. If the driver is already up, use its timing. 2. If it is not, read FB_TIMING_WIDTH/HEIGHT from dmesg. 3. If neither answers, poll mi_fb0 at 100ms instead of 500ms, keeping the same 5 second ceiling. FB_TIMING_* is the configured boot framebuffer and is not guaranteed to equal the panel, so dmesg is only consulted when mi_fb0 cannot answer. It can never override a real driver reading. The parser accepts both FB_TIMING_* and FB_TIMMING_* spellings. The dmesg path can answer before mi_fb0 exists, which removes the implicit driver-readiness barrier the old polling loop provided. Add wait_for_fb_driver and call it before both boot-time fbmode changes so an early dmesg result cannot let runtime race the display driver's late initialization. This fixes intermittent sheared output seen with .force640Res on 752x560 hardware.
Copilot AI
added a commit
to Amiga500/Onion
that referenced
this pull request
Sep 9, 2026
…and previews, GameSwitcher favorites + crash fixes, fbmode framebuffer transitions Co-authored-by: Amiga500 <16525337+Amiga500@users.noreply.github.com>
Author
|
Thanks @Amiga500 for testing and coming with feedback. I will dropping the detection commit rather than patching it. Force-pushing later so this is just the first 2 safe commits. |
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.
This PR improves framebuffer handling on 752x560-capable devices, adds an optional 640x480 mode, and shortens screen detection without reintroducing the display-initialization race that can produce sheared frames.
The changes are split into three commits so each part can still be reviewed independently:
fbmodefor verified framebuffer transitions.force640Resoverride1. Verified framebuffer transitions
Runtime currently uses
fbsetfor resolution changes. It requests a geometry but does not verify when the driver has actually latched it, always requests two virtual pages, and does not clear framebuffer memory whose page boundaries have just moved.That last point is what produces the sheared frames seen around 752x560 handoffs. The 640x480 and 752x560 layouts do not divide framebuffer memory at the same offsets, so bytes written using the 752x560 stride can briefly be scanned out using the 640x480 stride.
This adds
fbmode, a small framebuffer helper that:line_length--probeso redundant mode changes can be skippedfbsetfallbacks can be usedGameSwitcher handoff
launch_switcherbecomes the single owner of GameSwitcher's 752x560 requirement.A game exiting toward GameSwitcher leaves the framebuffer alone instead of dropping to 640x480 only for the next stage to switch it straight back.
Before launching GameSwitcher, runtime probes the current framebuffer and leaves an already-correct 752x560 two-page layout untouched, avoiding a forced same-mode relatch when arriving from a 752x560 game.
Shutdown
keymondraws theEnd_Savescreen fromdeepsleep()and backgrounds it, so it is usually still rendering when the game exits and runtime reaches the post-game resolution change.bootScreenreads the framebuffer geometry once at startup and writes rows at that pitch, so changing the mode underneath it shears the shutdown screen.Runtime now preserves the framebuffer when
/tmp/.offOrderis set. Nothing after that point renders except the shutdown screen itself, which reads the live geometry, so the transition was only ever cost..offOrderis already used this way inlaunch_game- the "SAVING" panel is skipped on the same condition.MainUI handoff
On 752x560-capable devices, runtime establishes MainUI's 640x480 three-page layout in
init_system, before the boot screen is drawn.launch_main_uithen probes the framebuffer. If it is still 640x480/3, the layout is preserved and the boot screen remains visible until MainUI paints over it.If the layout differs, runtime preclears before changing it so a pitch change cannot expose stale pixels written using the previous stride.
640-only devices do not use these extra preparation paths.
2. Optional forced 640x480 mode
Adds an opt-in flag:
When present, runtime pins
screen_resolutionto 640x480, removes/tmp/new_res_available, and establishes the 640x480 three-page framebuffer layout.Removing
/tmp/new_res_availableis intentional: downstream code then takes the same paths it would on hardware that never exposed 560p, rather than every resolution-related call site needing a separate override case./tmp/screen_resolutionrecords 640x480, so components that read it use the same geometry runtime is using - DraStic's launch.sh uses this file to decide whether to select its 752x560 mode, and display_getResolution() feeds DISPLAY_WIDTH/DISPLAY_HEIGHT for screenshot capture and GameSwitcher thumbnail scaling.No flag file means no behavior change.
3. Faster screen detection with explicit driver readiness
get_screen_resolutionpreviously polled:every 500ms until the display driver published its timing.
On some boots that takes several seconds, and the coarse interval can add up to another 500ms after the driver is actually ready.
Resolution is now resolved from three sources, in order:
mi_fb0onceFB_TIMING_WIDTH/FB_TIMING_HEIGHTfromdmesgmi_fb0every 100ms with the same 5 second ceilingmi_fb0remains authoritative. Thedmesgtiming describes the configured boot framebuffer and is not guaranteed to equal the panel, so it is only used whenmi_fb0has no answer and can never override a real driver reading.The parser also accepts the
FB_TIMMING_*spelling seen in some logs.Preserve driver readiness
The old polling loop did two jobs implicitly:
The
dmesgpath can answer the first question beforemi_fb0exists, so that implicit readiness barrier disappears.That matters because both the normal 752-capable boot path and
.force640Resperform a boot-time framebuffer mode change. Callingfbmodebefore the display driver has finished its own initialization can let the driver's later setup overwrite runtime's mode, leaving scanout and framebuffer contents using different layouts.This was observed as intermittent sheared output when booting a 752x560 device with
.force640Res.wait_for_fb_driver()makes the old guarantee explicit. It waits formi_fb0to publishCurrent TimingWidthbefore either boot-timefbmodeoperation.A fast
dmesghit can therefore resolve the screen type immediately without allowing the framebuffer transition itself to race late driver initialization.If the readiness wait times out, runtime logs it and still attempts the mode change as a best effort.
Fallback
Existing resolution-change paths retain their
fbsetfallback.The new framebuffer paths are gated on the presence of
fbmode, and failedfbmodetransitions fall back tofbsetwhere a mode change is required.Testing
Tested on Miyoo Mini V4 / Miyoo Flip 752x560 hardware:
.force640Res