Repository navigation
Conversation
This was referenced Nov 9, 2026
…ystem leaves a game, not the operation mode. Star Fox rendered 768x432 docked, smaller than handheld
oe::GetCurrentGraphicsScale (am's graphics scaling parameters, 10 / 20 / 30 -> tier 0 / 1 / 2) answered 1 docked. Games size their picture and their GPU budget by it, as a console does while it needs the GPU itself (GameChat's video): Star Fox keeps only "tier 0" (byte +0xa of its mode event, main+0xba69970) and below it renders 0.8 times smaller, so docked its DLSS network was resized to 768x432 at boot (960x540 handheld, and with tier 0 docked). Donkey Kong Bananza's code scales its frame buffer by {1.0, 0.8, 2/3}[tier] and adds 0 / 9 / 13 to the GPU time its dynamic resolution counts (from the disassembly, main+0x30f840; its docked size with tier 0 was not measured on main). A docked picture smaller than the handheld one on a GPU twice as fast is not the console's, and Star Fox's console footage matches tier 0: Peppy's close-up 65 s into it has a mean luminance gradient of 5.8 (x1000 at 1080p), tier 0 here 5.3, tier 1 4.6. GPU time in that cutscene is the same, about 7 ms p50 at its 30 fps.
The host answers 0 in both modes; DM_GFX_SCALE=1 or 2 answers a reduced tier (t_oe). Docs: services.md entry, both games' notes, env_switches.
Checked: make -C dm/host/tests GAME=040074A01BF12000 run (t_oe: 57 checks). The sizes and gradients above were measured on a build of our fork, not on main; no regress run, and the change reaches every Switch 2 game that reads the tier.
…esolution are basic settings The Mac launcher had no way to pick a picture size for Ocarina of Time, the GPU share the game sees, or the console mode with a default that follows the build. Now: - Render scale: "Game's own" (1.0, the game's full size, its own dynamic resolution as the sub-setting) or one of the game's own dynamic-resolution levels fixed (0.75 .. 0.5 in the profile's render_levels, shown in pixels from render_base). patches.py has a render-scale stub (the graphics update's scale apply block, found by function fingerprint beside the frame step and the dynamic-resolution stubs) that takes the loader's scale every frame while it is not 1.0; loader.c divides it by the graphics tier's picture so a level names the same size at every GPU share. - GPU share (DM_GFX_SCALE: Whole GPU, 80 %, 67 %) and Console mode (DM_OPMODE) take Auto, the profile's tested value (hle_oe.c dm_gfx_scale and dm_opmode_value). The profile names tier 0 (gfx_scale 0), so the picture is unchanged by default and the launcher offers the game's own lighter modes. - Dynamic resolution (the game's own climb under load) is the sub-setting of Render scale at "Game's own". - Frame rate offers 30 and 60. 120 is not offered: the game steps its time in whole vsyncs, and fps_max 120 needs the game measured at that rate first. The new settings.tsv rows carry level=basic and needs=; a choice row may have auto=<label>, its default, which the host reads as the profile's value. Needs PR seedds#1304 (the graphics scale is tier 0 in both modes), whose commit this one is built on. Front-ends: interface: a launcher.json choice row can carry "auto" (the value its Auto option stands for, the game's tested default); Ocarina of Time's render scale is a choice of 1.0 first (Dynamic) then the game's own levels, with "base" for their pixels, where it was a range. A front end that draws choices needs nothing else; Auto is its default. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The launcher's render scale (934b51a3) divides by the graphics tier's picture through hle_oe.c's dm_gfx_scale; the two host tests that link loader.c without hle_oe.c define it (tier 0, the whole GPU). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
FeReuss
force-pushed
the
pr/oot-launcher-render-scale
branch
from
November 9, 2026 16:44
4e722ba to
24cbc61
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.
What and why
The Mac launcher had no way to choose Ocarina of Time's (0400486024DEC000, v131072) picture size, the GPU share the game sees, or a console mode whose default follows the build. This adds them as basic settings:
render_levels, shown in pixels fromrender_base).patches.pyhas a render-scale stub (the graphics update's scale apply block, found by function fingerprint beside the frame step and the dynamic-resolution stubs) that takes the loader's scale every frame while it is not 1.0;loader.cdivides it by the graphics tier's picture so a level names the same size at every GPU share.DM_GFX_SCALE: Whole GPU, 80 %, 67 %) and Console mode (DM_OPMODE) take Auto, the profile's tested value (hle_oe.cdm_gfx_scale,dm_opmode_value). The profile names tier 0 (gfx_scale 0), so the picture is unchanged by default; the lighter tiers are the game's own modes, which The graphics scale is tier 0 in both modes: Star Fox's docked 3D was 768x432, smaller than handheld #1304 makes reachable.fps_max 120needs the game measured at that rate first (the host says[RED]and runs at 60 if it is forced).Nothing changes unless a player picks a value: the defaults are the profile's.
What these settings do on a MacBook Air M4 (Hyrule Field view, docked, 1920x1080 as the game's full size, one 120 s run each, window):
DM_RENDER_SCALE=0.5(1280x720) 45.4 fps against 44.9 at full size: the game's cost on Apple GPUs hardly depends on the picture size (mesh, compute and the upscaler's fixed output dominate), so lowering it does not buy frames.DM_GFX_SCALE=1(the game's 80 % mode, a 2048x1152 UI and a 683x384 dynamic-resolution floor) 56.8-57.0 fps over 20 minutes, at the cost of a smaller picture: it is offered, not the default.Checked
dm/tools/teststest_launcher_settings,test_docs,test_game_profile,test_architecture,test_oot_frame_step: see the numbers below;make -C dm/host/tests GAME=0400486024DEC000 run(includest_oe, which now checks the tier and the mode defaults, andt_nro/t_symbols, which stubdm_gfx_scaleforloader.c's new call);dm/ios/tests/launcher_storage_check.swiftfor the iOS front end's row. The wholemake -C dm/gfx/tests GAME=0400486024DEC000 runon the tree with every PR of the series: 150 suites, 72,812 checks, 0 failed.DM_RENDER_SCALE,DM_GFX_SCALE,DM_OPMODE,DM_DYNAMIC_RESOLUTION) on the tree of 2026-11-08/09 this was written on (main7f502220); this branch is rebased on7a7acfeeand built and unit-tested, not run in the game.scripts/regress.py check: not run; a profile and launcher change that reaches one game, and only Ocarina of Time is built on this Mac.Front ends
Front-ends: interface: a launcher.json choice row can carry "auto" (the value its Auto option stands for, the game's tested default); Ocarina of Time's render scale is a choice of 1.0 first (Dynamic) then the game's own levels, with "base" for their pixels, where it was a range. A front end that draws choices needs nothing else; Auto is its default.
Docs
docs/settings.md,docs/frontends.mdanddocs/launcher.schema.jsondescribeautoand the choice form;docs_patches.pyandenv_switches.pywere run (game patches table, switch table).Series: what these PRs add up to
This PR is one of a set from one effort to make Ocarina of Time (0400486024DEC000 v131072) hold its frame rate on a MacBook Air M4. The set, and how its parts combine into the last measured result:
The result (the Hyrule Field view, the heaviest of the game: 1920x1080 docked, 60 fps cap, window, 120 s runs, M4 with 10 GPU cores, 16 GB, macOS 27.2):
7f502220+ #1304,fps_holdat its defaultfps_hold off(#1927)cut_draws 128below, and the PRs listed as "also in the tree"enc_thread on(#1928)(The step from 33.7 to 40.2 changes the shader chain, so it has no in-process A/B; #1833 is most of it. Kokiri Forest, walking, is at 60 fps on build 4; the Hyrule view is the worst case.)
Each part switched in one process on build 4 (
DM_AB, 210 s, 600-frame phases, frame p50 with the part active against without; the noise between phases is about 0.3 ms): border-FC (#1929) 22.61 vs 23.98 ms; the barrier set (FRAG_ORDER,PASS_OVERLAPandHEAP_RELAXalternating together) 22.41 vs 22.58 ms;CUT_IDLE22.74 vs 22.85 ms;DISPATCH_CHAIN22.32 vs 22.48 ms.Which PRs make that tree:
fps_hold offenc_thread onshader_raw_direct(without it every raw store is dropped on an M4 and the foliage is not drawn: the 48-50 fps of a build without it are false)FeReuss:pr1833-m4-window, one commit on #1833's head (not yet offered on #1833 itself)gpu_ts_hz), #1833 (shader_raw_direct), #1720, #1377, #1840-fwrapv, nowe4e5ff64), #1368 / #1708 (native mesh prewarm and mesh without task: main's own versions), #1707 (withdrawn)FRAG_ORDER+PASS_OVERLAP+HEAP_RELAX),CUT_IDLEpr/pass-overlapandpr/cut-idleinFeReuss/nxnative-ootcut_draws 128(64 and 128 tie on this tree)All of it was measured on main
7f502220plus the above; these PRs are rebased on main8d5d4f1b; the tool and docs tests that touch them were run again there (test_env_switches,test_docs,test_nsp_chain, and each PR's own), while the host build and the graphics suite are those of7a7acfee, and none of it has been run in the game on the newer main (a shader rebuild of the new chain takes about an hour and 10 GB of disk). This PR is #1931.🤖 Generated with Claude Code