fix(vk): keep ultrawide loading fades full width #2851
Open
github-sync
wants to merge 3 commits from
github/pr/2851 into main
pull from: github/pr/2851
merge into: MagicBeanDev:main
MagicBeanDev:main
MagicBeanDev:github/pr/2893
MagicBeanDev:github/pr/2890
MagicBeanDev:github/pr/2887
MagicBeanDev:github/pr/2878
MagicBeanDev:github/pr/2875
MagicBeanDev:github/pr/2874
MagicBeanDev:github/pr/2873
MagicBeanDev:github/pr/2871
MagicBeanDev:github/pr/2756
MagicBeanDev:github/pr/2897
MagicBeanDev:github/pr/2896
MagicBeanDev:github/pr/2718
MagicBeanDev:github/pr/2842
MagicBeanDev:github/pr/2691
MagicBeanDev:github/pr/2895
MagicBeanDev:github/pr/2743
MagicBeanDev:github/pr/2765
MagicBeanDev:github/pr/2708
MagicBeanDev:github/pr/2732
MagicBeanDev:github/pr/2755
MagicBeanDev:github/pr/2817
MagicBeanDev:github/pr/2876
MagicBeanDev:release-please--branches--main
MagicBeanDev:release-please--branches--main--release-notes
MagicBeanDev:github/pr/2778
MagicBeanDev:github/pr/2888
MagicBeanDev:github/pr/2866
MagicBeanDev:github/pr/2877
MagicBeanDev:github/pr/2800
MagicBeanDev:github/pr/2829
MagicBeanDev:github/pr/2850
MagicBeanDev:github/pr/2889
MagicBeanDev:github/pr/2882
MagicBeanDev:github/pr/2860
MagicBeanDev:github/pr/2849
MagicBeanDev:github/pr/2886
MagicBeanDev:github/pr/2794
MagicBeanDev:github/pr/2840
MagicBeanDev:github/pr/2830
MagicBeanDev:github/pr/2834
MagicBeanDev:github/pr/2719
MagicBeanDev:github/pr/2742
MagicBeanDev:github/pr/2741
MagicBeanDev:github/pr/2820
MagicBeanDev:github/pr/2771
MagicBeanDev:github/pr/2859
MagicBeanDev:github/pr/2858
MagicBeanDev:github/pr/2823
MagicBeanDev:github/pr/2757
MagicBeanDev:github/pr/2769
MagicBeanDev:github/pr/2844
MagicBeanDev:github/pr/2843
MagicBeanDev:github/pr/2673
MagicBeanDev:github/pr/2855
MagicBeanDev:github/pr/2739
MagicBeanDev:github/pr/2807
MagicBeanDev:github/pr/2789
MagicBeanDev:github/pr/2814
MagicBeanDev:github/pr/2818
MagicBeanDev:github/pr/2774
MagicBeanDev:github/pr/2772
MagicBeanDev:github/pr/2750
MagicBeanDev:github/pr/2786
MagicBeanDev:github/pr/2785
MagicBeanDev:github/pr/2782
MagicBeanDev:github/pr/2779
MagicBeanDev:github/pr/2775
MagicBeanDev:github/pr/2706
MagicBeanDev:github/pr/2766
MagicBeanDev:github/pr/2747
MagicBeanDev:github/pr/2759
MagicBeanDev:github/pr/2745
MagicBeanDev:github/pr/2740
MagicBeanDev:github/pr/2733
MagicBeanDev:github/pr/2725
MagicBeanDev:github/pr/2727
MagicBeanDev:github/pr/2728
MagicBeanDev:github/pr/2729
MagicBeanDev:github/pr/2721
MagicBeanDev:github/pr/2722
MagicBeanDev:github/pr/2715
MagicBeanDev:github/pr/2714
MagicBeanDev:github/pr/2707
MagicBeanDev:github/pr/2703
MagicBeanDev:github/pr/2705
MagicBeanDev:github/pr/2697
MagicBeanDev:github/pr/2679
MagicBeanDev:github/pr/2676
MagicBeanDev:github/pr/2669
MagicBeanDev:docs/what-hookshot-connects-to
MagicBeanDev:fix/hdr-encode-test
MagicBeanDev:fix/main-tests
MagicBeanDev:fix/play-cache-files
MagicBeanDev:perf/game-barrier-order
MagicBeanDev:feat/heap-lazy
MagicBeanDev:feat/texture-detail
MagicBeanDev:perf/astc-opaque-bc1
MagicBeanDev:fix/fs-dir-lock
MagicBeanDev:fix/framegen-native-kept
MagicBeanDev:fix/update-no-downgrade
MagicBeanDev:port/k10-gcn-f16-mirrors
MagicBeanDev:fix/framegen-mult-cap
MagicBeanDev:chore/release-as-2.1.1
MagicBeanDev:perf/pcache-load-switch
MagicBeanDev:fix/prepare-progress-log
MagicBeanDev:fix/update-closes-stale-game
MagicBeanDev:fix/hdr-scaled-sampled
MagicBeanDev:perf/first-start-preset
MagicBeanDev:perf/zero-upload
MagicBeanDev:fix/vcore-escape-2s
MagicBeanDev:test/fake-gh-atomic
MagicBeanDev:perf/batch-idle-flush
MagicBeanDev:test/finish-stub-a
MagicBeanDev:chore/record-2.1.0
MagicBeanDev:fix/main-red-tests
MagicBeanDev:fix/test-display-startup-driver-cache
MagicBeanDev:feat/mesh-shader-mode
MagicBeanDev:fix/menu-probes-at-startup
MagicBeanDev:fix/fps-counter-classic
MagicBeanDev:fix/test-log-batch-flake
MagicBeanDev:fix/narrow-screen-hud
MagicBeanDev:ci/prereleases
MagicBeanDev:release/v2.0.15
MagicBeanDev:hotfix/v2.0.15
MagicBeanDev:fix/present-ahead-replay
MagicBeanDev:release/v2.0.13
MagicBeanDev:fix/bracket-paths-2013
MagicBeanDev:fix/hdr-overlays-2013
MagicBeanDev:fix/fps-counter-scale-2013
MagicBeanDev:fix/stick-seen-at-rest
MagicBeanDev:hotfix/menu-fits-screen
MagicBeanDev:fix/f1-always-opens-menu
MagicBeanDev:fix/ini-keep-lines
MagicBeanDev:claude/cranky-pike-7cf247
MagicBeanDev:perf/texture-answer-flat
MagicBeanDev:fix/stamp-test-modules
MagicBeanDev:fix/appimage-fonts
MagicBeanDev:fix/display-awake
MagicBeanDev:release/v2.0.12
MagicBeanDev:fix/discord-windows
MagicBeanDev:rc/v2.0.12-tests
MagicBeanDev:fix/dlss-keep-feature
MagicBeanDev:rc/v2.0.12
MagicBeanDev:button-icons
No reviewers
Labels
Clear labels
accessibility
Barrier affecting people with disabilities
autorelease: pending
autorelease: tagged
bug
Something isn't working
dependencies
Pull requests that update a dependency file
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
github_actions
Pull requests that update GitHub Actions code
good first issue
Good for newcomers
help wanted
Extra attention is needed
invalid
This doesn't seem right
question
Further information is requested
testing wanted
wontfix
This will not be worked on
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
Milestone
Clear milestone
No items
No milestone
Assignees
Clear assignees
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2851
Loading…
Reference in a new issue
No description provided.
Delete branch "github/pr/2851"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this is for: centred ultrawide menus currently leave the scene visible in the side strips during a loading fade. This keeps the fade full-width, but it also moves the loading icon into the side treatment, so this is a draft proposal, not a complete visual fix. What is measured: real windowless game captures on Linux/RTX 4090 at the reporter's 4432×1856 game-picture size, plus compiled regression checks. Not measured: a physical ultrawide display, Windows gameplay, other GPU vendors or performance.
Refs #2220. Credit to @EjianYT for identifying bit 3 and testing the
0xa→0x2correction.Problem
nx2/oot_wide.pyhas one keep bit per UI canvas. Bit 3 belongs to the loading fade, not the map.wide_sides()ingpu/vk/vk_framegen.cppremoved bits 1 and 3 in either centred mode. The HUD patch therefore squeezed the entire loading canvas into the middle 16:9.What changed
0xf; centred modes now use0xdinstead of0x5.vk_framegen.cppandoot_wide.py.test_wide_loading_fade.py, compiling the real renderer policy and generated HUD patch with authored state, in the existing wide-shape fixture style.docs/tested-configurations.md, including the unsuccessful input routes. No new shader, runtime switch, host interface, pane hook or generated game code is included.The pause/map centring, wheel background, event fades and inactive 16:9 projection are deliberately unchanged.
How it was tested
Environment: Arch Linux, kernel 7.2.15-1-omarchy; Intel Core i9-13900K; NVIDIA RTX 4090, driver 615.78.08. Base
51da0464, mask-only change7dc0773b, 2026-11-12. The same host executable was used before and after. Its base build includes dormant readback diagnostics (c372e16e, not enabled); the changed renderer was built from this branch. No Xbox UI mod or overlay was used.Rebase: final head
d2e37d47is one2057b2b. The one end-of-task rebase was conflict-free. The fade regression was rerun with GCC and Clang and passes; its generated unit is byte-identical to the Windows-syntax-checked unit. Upstream added AMD Anti-Lag frame-generation tagging, not a change to the fade policy. The game build/captures and full-suite result below are from before that rebase; the rebased game was not rebuilt or run.The reporter's log distinguishes 3840×2160 output setting, 4432×1856 game picture, 3328×1392 scene, and a 3440×1440 swapchain. The reproduction uses the first three, with
HOS_ASPECT=2.3889andHOS_WIDE_MAX_PX=8294400; it does not pretend that a windowless run has the reporter's swapchain. Both 21:9 captures are 2216×928, preserving the game picture's shape.Game-free checks
-std=c++20 -O2 -Wall -Wextra -Werrorflags. The local preflight had an incorrect C/libc++ include order; its captured source was compiled with that order corrected. This is not Windows execution.-Wall -Wextracheck reports 11 missing-initializer warnings at unchanged Vulkan structure initializers, none at the mask change. No fixture core dumps were produced.Game captures
All captures used the real scale pass (
RX_VK_SHOT_FX=1). The bridge's named raw screenshots bypass that pass and were not used to judge the blur. These were ordinary runs on a busy PC, not exclusive timing runs; no fps, latency or performance claim is made.Retained input failures: one initial capture helper used a relative count with an absolute-frame wait; the first 16:9 route dismissed the tapestry but did not leave its menu; the extended mode check used an unrecognized setting key. Each stopped on its error, and no unreached step is counted as evidence. None was a game crash or device loss.
six inspected panels: before/mask-only loading fade, pause and Map. Same save, picture size and settings; the loading frames compare coverage, not identical fade opacity or frame numbers.
identical bottom-right crops, enlarged 2×: the original sharp icon inside the central 16:9 versus the mask-only icon blurred near the outer edge. This is why the proposal remains a draft.
six inspected panels at the same 3840×2160 picture size: before/after loading fade and sharp icon, pause and actual Map. Captures are 1920×1080.
equal 2× crops showing the original centred icon, the mask-only blurred icon, the hidden black-bars icon and the sharp-but-stretched Full-width reference. A separate raw image immediately before the black-bars capture still shows the icon: the side pass, not a missing draw, removes it.
All six runs reported zero fatal/crash/device-loss/kernel-driver-fault lines. The first 16:9 run recorded one virtual-core escape at startup; the other five recorded none. The last three capture routes passed their checks and quit normally. Full width's unchanged mask is covered by the compiled before/after checks; its runtime image is a reference from the changed binary, not a separate pre-fix Full-width run.
Not tested / not shown
windows-2022source-check parts passed on a run on my fork at this head before the pull request was opened.)Why not simply keep the icon centred too?
The existing HUD hook changes one projection for the whole canvas, not an individual pane. Clearing bit 3 centres both the icon and fade; keeping it widens both. The side pass receives only margins and its mode, not a pane identity or loading opacity.
A complete solution needs a new game-side hook that widens only the fade pane, or a new loading-state/opacity hand-off to the side-fill path and its shader. Exempting the outer pixels alone would still leave a stretched, displaced icon. This proposal does not add an unproved pane patch or a dark-pixel heuristic.
Risks
The loading icon regression is real in both centred modes: it is a dim blur with blurred sides and completely hidden by black bars. Full width shows it sharply but stretched; 16:9 keeps its original position and proportions. The mask-only change should not be merged as if it preserves the loading indicator.
Overlaps
The pre-rebase open-PR comparison found 57 PRs touching one of the initial four changed files. The shared-code PRs #1488, #1979, #2015, #2017, #2172, #2261, #2262, #2531, #2658 and #2665 merged cleanly in that comparison; no conflict hunk was reported. No competing loading-fade repair was found. The final branch gate passes against
e2057b2b.Questions for the maintainers and reporter
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]
The corrected meaning of bit 3 looks right. #2843 reads it the same way. The problem is that this change widens everything on that screen, not just the fade (see the review body). If the fade pane is widened on its own, this mask can stay at
0xa. Then it's only the comment that needs fixing.Main now has an Ultrawide menus bullet in the option list, and a clean merge would put this one beside it. Please merge the two. If the icon gets fixed, this paragraph mostly goes away: a known regression reads oddly in user docs.
Nit: take these from
wide.KEEP_VTABLES(you already load the module) rather than copying the addresses. That way the fixture can't drift fromoot_wide.py. A second nit: the grace-period and wheel checks near the end bumpfailureswithout printing anything, so a failure there exits 1 silently. AFAIL:line like the others would help.Thanks for this, and for the careful write-up. The before/after pictures at the reporter's 4432x1856 picture are exactly what I wanted to see: the bug is shown, and shown gone. The icon crops make the cost just as clear.
Root cause and layer. I agree with the diagnosis, and #2843 independently names keep bit 3 the same way. The centred modes cleared bits 1 and 3, so the HUD site squeezed the whole loading screen into the middle 16:9. While the fade runs, the world is still drawn, so
no_worldis false and the side pass is off. That leaves the scene bright in the strips.wide_sides()only lives invk_framegen.cppbecause the scale pass does. It runs on every present with frame generation Off too (that path goes throughwide_sides_possible()invk_replay.cpp), so your FG-off captures cover the normal case. The mask is the right switch for the fade. The trouble is that it is whole-canvas.Side effects. I don't see any beyond the icon. 16:9 is untouched because the squeeze is 0 there, and your 16:9 pair confirms it. The HUD, text boxes, the cursor and the map are ordinary canvases and stay squeezed. The wheel background (bit 0), event fades (bit 2) and movies keep their current behaviour. The only thing that stops being pillarboxed is the loading screen itself, which takes its icon with it.
The icon trade-off. This is the reason I wouldn't take the mask-only change as it stands. In the default mode (blurred sides) the loading indicator turns into a smudge at the far edge, and with black bars it vanishes completely. I'd rather fix it per pane than ship that. #2843 (Extended) adds per-pane hooks, and one of its rules already draws a pane that spans the canvas at the screen's width. Here's the version I'd like: keep the loading screen squeezed in the centred modes, and widen only its spanning fade pane through that path. The icon then stays sharp in the middle 16:9, and the fade covers the strips. Please check how Extended already treats this screen once #2843 is in, because it may need very little. If that turns out heavy, say so here and we can talk about the mask change as a stopgap.
Test. It's a good check. It compiles the real
wide_sides()and the real HUD patch around authored state, so it tests behaviour rather than matching text. It fails on the old mask (four keep-mask checks plus the loading-canvas projection), and it runs and passes in all four source-check parts at this head. Two nits are inline.Conflicts and ordering.
docs/tested-configurations.mdconflicts with main: rows landed at the top of the table today. Keep both sets.readme.mdmerges cleanly but would end up with two Ultrawide menus bullets. Main now has one in the option list, which already says loading screens get the same sides. Please fold your note into that one.vk_framegen.cppmerges cleanly with today's #2262/#2658.kMenusline and its comment, and the keep-bit comment inoot_wide.py). It also renumbers the modes: Extended becomes 1 and the centred modes 2/3 withside = mode - 1. This test'sside == modeandmode ? 0xd : 0xfexpectations would break once it lands. Since the pane-level route would build on #2843 anyway, I'd land #2843 first and rebase this onto it.To take it out of draft: a fix that keeps the icon (or an agreed stopgap), rebased on main and on #2843, the readme note folded in, and before/after crops of the icon and fade at 21:9 again. A run from @EjianYT on their real 3440x1440 window would be a welcome extra.
Thanks for the thorough review, and for the merge of main. Agreed on all of it: the mask is the wrong grain, and a loading indicator that smudges or vanishes is not something to ship.
What I will do:
0xaand only its comment is corrected. I am reading #2843's head now to see how Extended already treats this screen and will say here whether it needs little or turns out heavy, before writing more than a prototype.side == modeandmode ? 0xd : 0xfexpectations moved to the renumbered modes.wide.KEEP_VTABLES, and aFAIL:line for the grace-period and wheel checks.It stays a draft until then.
@hckrman101 #2843 should correctly handle these transitions already in extended mode! It doesn't fix them on the centered layouts though, but that should be fairly easy to bridge over support for