Improve framebuffer transitions and 640x480 handling - #1940
Open
robcodedev wants to merge 3 commits into
Open
robcodedev 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.
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. |
install.sh initializes the LCD but never establishes a framebuffer geometry, so installUI starts on whatever mode the firmware left active. On a Miyoo Mini Flip that is 752x560 with three virtual pages, while installUI's layout is a fixed 640x480, so the installer UI is drawn wrong. Clear the framebuffer and set 640x480 with two pages right after init_lcd, before anything can draw. The clear comes first: fbset does not touch framebuffer memory, so the firmware's boot contents would be scanned out at the new stride until installUI paints over them, which is not until after SDL and asset loading. Clearing /dev/fb0 to end of device covers the framebuffer allocation exposed by the driver, a superset of both layouts, and zeroed bytes are safe to scan at either pitch. Use fbset rather than fbmode because the installer runs before onion.pak is extracted on a first install, and the stub clears .tmp_update before install.sh runs on an update, so bin/fbmode is not available on either path. Apply the same preclear-before-pitch-change principle directly here with the tools available during bootstrap. fbset is supplied by the firmware at /usr/sbin/fbset and is on PATH on both paths.
robcodedev
force-pushed
the
framebuffer-transitions
branch
from
September 10, 2026 19:12
b3d9186 to
5b95c76
Compare
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 transitions on 752x560-capable devices, adds an optional 640x480 mode, and fixes the installer starting before a suitable framebuffer geometry has been established.
The changes are split into three commits so each part can still be reviewed independently:
fbmodefor verified runtime 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.
MainUI handoff
On 752x560-capable devices, runtime establishes MainUI's 640x480 three-page layout in
init_system, before the boot screen is drawn.On a Miyoo Mini Flip the firmware leaves the framebuffer at 752x560 with three virtual pages before runtime starts:
This was captured immediately after
init_lcd, before any runtime mode change.The boot-time transition is therefore a real pitch change, from 3008 bytes per row to 2560. The new 640x480 pages overlap memory previously used by the 752x560 layout, so this path preclears before changing geometry rather than allowing framebuffer contents written at the old stride to be scanned at the new one.
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.
Shutdown
keymoncan draw theEnd_Savescreen while the game is still exiting. The screen is rendered using the framebuffer geometry it observed when it started, so changing the mode underneath it can shear the shutdown screen.Runtime now preserves the framebuffer when
/tmp/.offOrderis set. A normal return-to-MainUI transition is unnecessary once shutdown is already pending, so the current layout is left untouched.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'slaunch.shuses this file to decide whether to select its 752x560 mode, anddisplay_getResolution()feedsDISPLAY_WIDTH/DISPLAY_HEIGHTfor screenshot capture and GameSwitcher thumbnail scaling.No flag file means no behavior change.
3. Installer framebuffer geometry
The installer starts outside Onion's normal runtime framebuffer setup.
install.shrunsinit_lcdbut does not establish a framebuffer geometry before its UI is used.installUIitself has a fixed 640x480 layout.On a Flip, the framebuffer immediately after
init_lcdwas observed as:The installer now clears
/dev/fb0and establishes a 640x480 two-page layout immediately afterinit_lcd, before any installer UI is drawn.The clear deliberately happens first.
fbsetchanges the framebuffer geometry but does not clear its contents, so pixels written using the firmware's 752x560 stride could otherwise be scanned using the new 640x480 stride untilinstallUIproduces its first frame.Clearing the framebuffer allocation first means the geometry change operates on zeroed memory, applying the same preclear-before-pitch-change principle used by
fbmodeduring runtime transitions.This path uses
fbsetrather thanfbmode. On a first install,fbmodeis still insideonion.pak; on an update, the installer stub replaces the old.tmp_updatecontents beforeinstall.shruns. The firmware-providedfbsetis available during bootstrap, so the installer can establish its known 640x480 layout without depending on the Onion runtime helper.This installer preparation runs on every device. On hardware already using 640x480 it clears the framebuffer and reapplies the geometry that is already active.
Fallback
Runtime resolution-change paths retain their existing
fbsetfallback.The runtime framebuffer preparation is gated on the presence of
fbmode, and failedfbmodetransitions fall back tofbsetwhere a mode change is required. The installer uses firmware-providedfbsetdirectly becausefbmodeis not available during bootstrap.Testing
Thanks @Amiga500 and "another.alvin" for testing and coming with feedback.
Tested on Miyoo Mini V4 / Miyoo Flip 752x560 hardware:
.force640Resinit_lcd