WIP: fix(vk): keep ultrawide loading fades full width #57

Draft
mooki wants to merge 4 commits from mooki/Longshot:fix/wide-loading-fade into main
First-time contributor

Why

Draft: this waits for ozwaldorf's Extended ultrawide work, then the pane-level replacement requested in the original review. No open or merged Longshot pull request for that dependency was found in the complete public title/body inventory checked during this move.

Centred ultrawide loading fades leave the scene visible in the side strips. This preserved mask-only proposal covers those strips, but also blurs or hides the loading indicator. It must not be merged as a complete visual fix. EjianYT identified and tested the bit-3 correction.

What changed

  • Renderer policy, wide_sides() in gpu/vk/vk_framegen.cpp: keep only pause/system-background bit 1 out of the full-width mask: centred modes use 0xd instead of 0x5; Full width remains 0xf.
  • Canvas descriptions in nx2/oot_wide.py and tests/test_wide_loading_fade.py: correct the canvas descriptions and add a game-free fixture compiling the actual renderer policy and HUD projection patch around authored state.
  • README.md and docs/tested-configurations.md: preserve the historical evidence rows and documented icon trade-off. No shader, host API, pane hook, option ID or generated game code is added.
  • A separate migration-time test commit puts _CRT_SECURE_NO_WARNINGS before the fixture's headers, matching the other portable fixtures. The strict Windows-target check otherwise rejected its existing memcpy calls. Warning flags and all behavioral assertions remain unchanged.
  • This revision only rebases the preserved proposal and converts the live description to the current template. It does not implement the pane-level replacement, alter the source patch, or clear the draft blocker.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Insert menu → Graphics → Ultrawide menus Changed behavior; no new row or option ID: Centred modes keep the loading canvas full width (0xd instead of 0x5); Full width stays 0xf Centred, blurred sides (1), unchanged Off by default: do not ship this mask-only policy with the icon regression; the pane-level replacement comes first Historical Linux/RTX 4090 ultrawide fade coverage Loading-icon sharpness/visibility; 16:9 already worked Current Longshot game, Windows game, physical ultrawide display, AMD/Intel/Deck, HDR, frame-generated output (should help on: No additional hardware claim)
longshot_options.ini: ultrawide_menus Changed behavior through the same menu policy; key and values unchanged: 0 Full width, 1 Centred, blurred sides, 2 Centred, black bars; the latter two receive the mask change 1, unchanged Off by default: separate default change; same pane-level blocker Same fade coverage as the menu row Not an independent fade/icon control or a fix for the icon Same runtime gaps as the menu row (should help on: No additional hardware claim)
tests/test_wide_loading_fade.py --cxx New test-only CLI flag: Selects the compiler used for the authored fixture g++; the suite supplies its selected compiler Off by default: game default; compiler selection is test-only Repeating the compiled Linux behavior comparison Game rendering or performance Native Windows fixture execution (should help on: No additional runtime claim)
tests/test_wide_loading_fade.py --source New test-only CLI flag: Selects the checkout whose real renderer policy and HUD patch the fixture compiles The checkout containing the test Off by default: game default; another checkout is selected explicitly for the baseline Failing-on-main/passing-on-branch comparisons with one fixture Game rendering or performance Native Windows fixture execution (should help on: No additional runtime claim)
_CRT_SECURE_NO_WARNINGS in the generated fixture New fixture-only compile definition in the migration-time repair: Declares the CRT policy before headers so the existing memcpy calls compile with the unchanged strict warning flags Defined for this fixture; no product setting On by default: for this fixture's portability policy, not a game option The retained Windows-target syntax check Native Windows execution proof or the loading-icon defect Native Windows fixture execution (should help on: No additional runtime claim)

No environment switch is added or changed. The new fixture's fixed compiler arguments are -std=c++20, -O2, -Wall, -Wextra and -Werror; they are not new configurable game/build settings, and the CRT repair does not weaken them. The existing README option-table choices/default remain unchanged, and the added README warning documents the mask-only trade-off. Consolidating its duplicated Ultrawide menus bullets remains owed with the pane replacement; this rebase does not pretend that review point is finished.

Measurements

Branch state: on main d725b3631982ed0035ea3ac9cbe1677e9fad260c; head 58143b9df475a69dbfa80647ae687257d2edca4e; whole game-free suite on this head: 511 passed, 1 failed, 20 skipped (main d725b3631982ed0035ea3ac9cbe1677e9fad260c: 510 passed, 1 failed, 20 skipped); the commits are unchanged by rebases apart from the results table.

The branch-state suite was run with the repository default compiler and six workers; only the local updater NU1100 reference-pack failure remains, as on its shared base. The full source suite includes the changed fixture, not a game or Windows execution.

The rules-only rebase preserved all four original author/date/message records, including the maintainer merge, all three patch entries and the byte-identical net source diff. Main subsequently gained the DLSS model settle fix and Testing-template changes; this branch merges cleanly and does not touch the DLSS implementation/check header. It remains on its tested base under the central-refresh policy. Older evidence below keeps the commits actually measured.

Retained migration-time measurements

main: d4a69456c9 (2026-11-12)
this PR: fix/wide-loading-fade @ 49a7c60bbe
Posted migration head: this branch @ 71e34ec3d746e40642650a115c3d43c746543c81; the whole suite and interleaved behavior proof used 49a7c60bbef0ee87276e6767dbbc5ad83d74864d, before the fixture-header-only commit.
Hardware: Core i9-13900K, 96 GB RAM, Arch Linux 7.2.15-1-omarchy, Clang 23.1.3; no GPU used for the new checks.
Scene: authored 16:9/21:9 canvases in the compiled fixture, not a newly run game.
Method: two interleaved main/branch pairs with the same fixture and compiler; count its behavioral failures and report their median. Whole branch suite with the repository's default compiler; shared pinned-main suite. After the one-line CRT guard, only the changed fixture and failed Windows-target step were rerun, both passing; the earlier full suite is not relabelled as a new run.

main @ d4a69456 this PR @ 49a7c60b
Behavioral failure lines, run 1 / run 2 12 / 12 0 / 0
Median failure count 12 0
Whole suite 507 passed, 2 failed, 20 skipped 509 passed, 1 failed, 20 skipped
Current Longshot game build/run Not run Not run: retained draft, no game build requested
FAIL: 16:9 mode 1 keep mask 0x5, expected 0xd
FAIL: 16:9 mode 2 keep mask 0x5, expected 0xd
FAIL: 21:9 mode 1 keep mask 0x5, expected 0xd
FAIL: 21:9 mode 1 loading fade projection component 0
PASS: loading/event fades and wheel stay full width; pause/HUD centring, sides and 16:9 unchanged
507 passed, 2 failed, 20 skipped in 504 s (linux, 6 at once)
509 passed, 1 failed, 20 skipped in 166 s (linux, 6 at once)

The base suite was run once for all moved pull requests of this day, on that commit. Both sides fail tests/test_updater_asset_digest.py with NU1100, unable to resolve local Microsoft.AspNetCore.App.Ref (= 10.0.13). The shared base also fails two bounded-time cases in tests/test_appimage_package_retry.py; that test passes here. No package was installed and no failed run was discarded. Forgejo has no CI runner.

The first Windows-target fixture capture failed five deprecated-memcpy diagnostics. After the early CRT guard, its one captured translation unit passes with the same warnings-as-errors settings. That is syntax only, not native Windows execution. The historical GitHub Windows run at the pre-rename head is not a check of this Longshot head.

Historical game evidence, not repeated: Hookshot base 51da0464, mask change 7dc0773b, 2026-11-12, RTX 4090/NVIDIA 615.78.08 on this Linux PC. Six windowless runs at 4432x1856 or 3840x2160 showed full-width fade coverage and unchanged pause/Map centring. The 21:9 loading icon becomes a dim blur with blurred sides, disappears behind black bars, and is sharp but stretched in Full width. The first 16:9 route did not reach the actual Map; a later corrected route did. One startup virtual-core escape occurred in the first 16:9 run; all six had zero fatal/crash/device-loss/driver-fault counts. These were ordinary shared runs, not performance measurements.

How to reproduce

How to reproduce: use the exact fixture/source matrix below; the historical visual route is separate.

For the recorded compiled comparison, use separate checkouts named baseline at d4a69456c9de5131589af1fcf9a09adba4c403d1 and candidate at 49a7c60bbef0ee87276e6767dbbc5ad83d74864d. From their parent directory, use the same Clang installation for all four commands, in this order; each invocation compiles and runs authored 16:9/21:9 canvas state, without a game or Vulkan device:

python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source baseline
python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source candidate
python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source baseline
python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source candidate

Count the FAIL: behavior lines per invocation and report the median for each source: the retained counts are 12/0/12/0. The baseline exits nonzero deliberately. The whole-suite command was python -I -B tests/run_all.py --jobs 6 --strict in each named checkout, with a fresh HOME; the whole suites were single runs, not two interleaved suites. For the later CRT-only repair, use the fixture at 71e34ec3d746e40642650a115c3d43c746543c81; only that fixture and the failed Windows-target step were repeated then.

For visual reproduction, compare the historical Hookshot main @ 51da0464 and mask-only this PR @ 7dc0773b at the same Hyrule Field save-load and Hyrule Field/Kokiri transition, then pause and open the actual Map. Use the game's upscaler, frame generation off, no UI mod, 4432x1856 game picture for the wide case and 3840x2160 for the 16:9 control; compare Centred, blurred sides, Centred, black bars, and Full width. Inspect both fade coverage and the loading icon, not equal opacity or matching frame numbers. These are reproduction conditions for the retained captures, not a claim that this Longshot head or the pane prototype was run.

Testing

Tested: Linux game-free checks on the branch-state head and shared base, with the default compiler, fresh isolated test environment and the full suite. Historical compiled main/branch pairs, Windows-target syntax, and the six inspected Hookshot visual/log runs retain their identities below; the visual runs were correctness checks, not speed measurements.

Not tested: No Longshot game build/run, fresh visual proof or performance measurement. The pane-level replacement is not in this branch. No Windows game, native Windows execution of the new fixture, physical ultrawide display, AMD/Intel/Deck, HDR or frame-generated output. No test request was posted during this move.

No new game build/run was requested for this dependency-held draft. This work was limited to windowless Linux checks; native Windows, physical ultrawide input/presentation and the other GPU systems above were not available for these runs.

The branch-state head has run the complete source suite, including the changed fixture. Windows-target syntax remains the earlier labelled capture, not a new Windows execution.

Tested but not measured: the six historical Hookshot windowless game runs on this Linux/RTX 4090 PC were ordinary shared runs. They provide the retained visual/log evidence, not FPS, frame-time, stutter or performance measurements. No current Longshot game has been run for this proposal.

Needs other testers:

  • Windows with a physical ultrawide display: compare loading, pause and Map against main, expecting full-width fade coverage and the documented blurred/hidden icon trade-off, not a complete icon fix (request to open).
  • Linux AMD/Intel and Steam Deck: check the same centred/full-width modes and transitions, expecting unchanged pause/Map centring and no additional rendering/stability regression beyond the known icon defect (request to open).

Screenshots

Historical game labels: main @ 51da0464 is the baseline and this PR @ 7dc0773b is the mask-only renderer change. They are not the current rebased Longshot commits or the migration-time fixture heads.

Hookshot 51da0464 versus mask-only 7dc0773b, 2026-11-12: full-width fade coverage; pause and Map stay centred. Loading frames compare coverage, not equal opacity or frame numbers.

Same historical mask-only stage: sharp centred icon before, dim blur with blurred sides, hidden by black bars, sharp but stretched in Full width. This is why the draft remains blocked.

Both retained original panels were inspected. They are not photographs of a Longshot build or of the separate pane prototype.

Risk and rollback

The original review's blocker is real: covering the fade by widening the whole canvas moves and stretches the icon too. A dark-pixel heuristic or an unproved pane patch is not included as a workaround.

The known risk is already visible: the default blurred-sides mode smudges the loading indicator at the edge, black bars hide it, and Full width leaves it sharp but stretched. Fade coverage alone is not a complete visual fix or permission to merge. Other hardware and output modes listed under Not tested have no runtime proof here.

This proposal adds no dedicated runtime opt-out. Revert the wide_sides() mask-policy change (kMenus back to 0xa, centred keep-mask back to 0x5) to restore the prior behavior; that also restores the original exposed side strips during loading fades. Selecting Full width is not a centred-icon fix. No shader or host API rollback is needed.

Reviewer notes

Start with wide_sides() in gpu/vk/vk_framegen.cpp, the canvas descriptions/HUD patch in nx2/oot_wide.py, then tests/test_wide_loading_fade.py. The early CRT definition changes fixture portability only; it leaves all behavioral assertions and warning flags intact.

Still owed from hckrman101's review: keep the loading canvas centred and widen only its spanning fade pane on the dependency's per-pane path; follow its renumbered modes; fold the duplicated Ultrawide menus README bullets together; derive fixture addresses from wide.KEEP_VTABLES; print failures for the grace-period/wheel checks; repeat 21:9 fade/icon pictures. Both sets of historical result rows are retained. The separate Hookshot pane prototype and its pictures are not silently substituted for this posted mask-only branch.

The requested fix keeps the loading canvas squeezed and the icon sharp inside the middle 16:9, widening only the spanning fade pane through the dependency's existing per-pane path. That allows kMenus to stay 0xa with its comment corrected. The dependency renumbers Extended to 1 and centred modes to 2/3 (side = mode - 1), so the current fixture's side == mode and mode ? 0xd : 0xf assumptions must change with that replacement. Both historical result-row sets remain; neither the README consolidation nor the fixture nits were silently done in a rules-only rebase. A reporter check on the real 3440x1440 display remains welcome, not claimed.

This remains WIP waiting on the dependency and the reviewed pane-level direction, not a readiness request. The separate prototype and its different build identities remain in the carried discussion, not in this branch's proof.

Issues

Original report: https://github.com/NotRexed/Hookshot/issues/2220
Original draft/review: https://github.com/NotRexed/Hookshot/issues/2851
Dependency: https://github.com/NotRexed/Hookshot/issues/2843
On this forge: See #82 (this report) and See #64 (the broader HUD and menu layout proposal, which this does not close). Old GitHub numbers are not Forgejo issue numbers.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. Kept on the tested base under the central-refresh policy; Main handles a later refresh before ready.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). Exact rebased head checked; inherited NU1100 only.
  • Tested in the game, or what wasn't is named under Testing. Draft; no new Longshot game run.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Historical compiled behavior proof has two interleaved pairs and a median; the new-head comparison and complete visual fix remain open.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README). Table complete; choices/default and the existing README warning retained, but the requested README consolidation still waits with the pane replacement. No environment switch was added.
  • Screenshots for a change that shows on screen. Historical, with their actual build identities above.
  • A game-free test added for the fix, failing on main and passing here. Historical negative controls retained; the test also passes in the exact-head full suite.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. No current game builds; fixture checks only.
  • Docs updated. Historical notes retained; the requested README consolidation still waits with the pane replacement.

Moved from NotRexed/Hookshot#2851.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]

## Why **Draft: this waits for ozwaldorf's [Extended ultrawide work](https://github.com/NotRexed/Hookshot/issues/2843), then the pane-level replacement requested in [the original review](https://github.com/NotRexed/Hookshot/issues/2851).** No open or merged Longshot pull request for that dependency was found in the complete public title/body inventory checked during this move. Centred ultrawide loading fades leave the scene visible in the side strips. This preserved mask-only proposal covers those strips, but also blurs or hides the loading indicator. It must not be merged as a complete visual fix. EjianYT identified and tested the bit-3 correction. ## What changed - Renderer policy, `wide_sides()` in `gpu/vk/vk_framegen.cpp`: keep only pause/system-background bit 1 out of the full-width mask: centred modes use `0xd` instead of `0x5`; Full width remains `0xf`. - Canvas descriptions in `nx2/oot_wide.py` and `tests/test_wide_loading_fade.py`: correct the canvas descriptions and add a game-free fixture compiling the actual renderer policy and HUD projection patch around authored state. - `README.md` and `docs/tested-configurations.md`: preserve the historical evidence rows and documented icon trade-off. No shader, host API, pane hook, option ID or generated game code is added. - A separate migration-time test commit puts `_CRT_SECURE_NO_WARNINGS` before the fixture's headers, matching the other portable fixtures. The strict Windows-target check otherwise rejected its existing `memcpy` calls. Warning flags and all behavioral assertions remain unchanged. - This revision only rebases the preserved proposal and converts the live description to the current template. It does not implement the pane-level replacement, alter the source patch, or clear the draft blocker. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Insert menu → Graphics → Ultrawide menus | Changed behavior; no new row or option ID: Centred modes keep the loading canvas full width (`0xd` instead of `0x5`); Full width stays `0xf` | Centred, blurred sides (`1`), unchanged | Off by default: do not ship this mask-only policy with the icon regression; the pane-level replacement comes first | Historical Linux/RTX 4090 ultrawide fade coverage | Loading-icon sharpness/visibility; 16:9 already worked | Current Longshot game, Windows game, physical ultrawide display, AMD/Intel/Deck, HDR, frame-generated output (should help on: No additional hardware claim) | | `longshot_options.ini`: `ultrawide_menus` | Changed behavior through the same menu policy; key and values unchanged: `0` Full width, `1` Centred, blurred sides, `2` Centred, black bars; the latter two receive the mask change | `1`, unchanged | Off by default: separate default change; same pane-level blocker | Same fade coverage as the menu row | Not an independent fade/icon control or a fix for the icon | Same runtime gaps as the menu row (should help on: No additional hardware claim) | | `tests/test_wide_loading_fade.py --cxx` | New test-only CLI flag: Selects the compiler used for the authored fixture | `g++`; the suite supplies its selected compiler | Off by default: game default; compiler selection is test-only | Repeating the compiled Linux behavior comparison | Game rendering or performance | Native Windows fixture execution (should help on: No additional runtime claim) | | `tests/test_wide_loading_fade.py --source` | New test-only CLI flag: Selects the checkout whose real renderer policy and HUD patch the fixture compiles | The checkout containing the test | Off by default: game default; another checkout is selected explicitly for the baseline | Failing-on-main/passing-on-branch comparisons with one fixture | Game rendering or performance | Native Windows fixture execution (should help on: No additional runtime claim) | | `_CRT_SECURE_NO_WARNINGS` in the generated fixture | New fixture-only compile definition in the migration-time repair: Declares the CRT policy before headers so the existing `memcpy` calls compile with the unchanged strict warning flags | Defined for this fixture; no product setting | On by default: for this fixture's portability policy, not a game option | The retained Windows-target syntax check | Native Windows execution proof or the loading-icon defect | Native Windows fixture execution (should help on: No additional runtime claim) | No environment switch is added or changed. The new fixture's fixed compiler arguments are `-std=c++20`, `-O2`, `-Wall`, `-Wextra` and `-Werror`; they are not new configurable game/build settings, and the CRT repair does not weaken them. The existing README option-table choices/default remain unchanged, and the added README warning documents the mask-only trade-off. Consolidating its duplicated Ultrawide menus bullets remains owed with the pane replacement; this rebase does not pretend that review point is finished. ## Measurements <!-- branch-state --> Branch state: on main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`; head `58143b9df475a69dbfa80647ae687257d2edca4e`; whole game-free suite on this head: `511 passed, 1 failed, 20 skipped` (main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`: `510 passed, 1 failed, 20 skipped`); the commits are unchanged by rebases apart from the results table. <!-- /branch-state --> The branch-state suite was run with the repository default compiler and six workers; only the local updater NU1100 reference-pack failure remains, as on its shared base. The full source suite includes the changed fixture, not a game or Windows execution. The rules-only rebase preserved all four original author/date/message records, including the maintainer merge, all three patch entries and the byte-identical net source diff. Main subsequently gained the DLSS model settle fix and Testing-template changes; this branch merges cleanly and does not touch the DLSS implementation/check header. It remains on its tested base under the central-refresh policy. Older evidence below keeps the commits actually measured. ### Retained migration-time measurements main: d4a69456c9de5131589af1fcf9a09adba4c403d1 (2026-11-12) this PR: fix/wide-loading-fade @ 49a7c60bbef0ee87276e6767dbbc5ad83d74864d Posted migration head: this branch @ `71e34ec3d746e40642650a115c3d43c746543c81`; the whole suite and interleaved behavior proof used `49a7c60bbef0ee87276e6767dbbc5ad83d74864d`, before the fixture-header-only commit. Hardware: Core i9-13900K, 96 GB RAM, Arch Linux 7.2.15-1-omarchy, Clang 23.1.3; no GPU used for the new checks. Scene: authored 16:9/21:9 canvases in the compiled fixture, not a newly run game. Method: two interleaved main/branch pairs with the same fixture and compiler; count its behavioral failures and report their median. Whole branch suite with the repository's default compiler; shared pinned-main suite. After the one-line CRT guard, only the changed fixture and failed Windows-target step were rerun, both passing; the earlier full suite is not relabelled as a new run. | | main @ d4a69456 | this PR @ 49a7c60b | |---|---|---| | Behavioral failure lines, run 1 / run 2 | 12 / 12 | 0 / 0 | | Median failure count | 12 | 0 | | Whole suite | 507 passed, 2 failed, 20 skipped | 509 passed, 1 failed, 20 skipped | | Current Longshot game build/run | Not run | Not run: retained draft, no game build requested | ```text FAIL: 16:9 mode 1 keep mask 0x5, expected 0xd FAIL: 16:9 mode 2 keep mask 0x5, expected 0xd FAIL: 21:9 mode 1 keep mask 0x5, expected 0xd FAIL: 21:9 mode 1 loading fade projection component 0 PASS: loading/event fades and wheel stay full width; pause/HUD centring, sides and 16:9 unchanged 507 passed, 2 failed, 20 skipped in 504 s (linux, 6 at once) 509 passed, 1 failed, 20 skipped in 166 s (linux, 6 at once) ``` The base suite was run once for all moved pull requests of this day, on that commit. Both sides fail `tests/test_updater_asset_digest.py` with `NU1100`, unable to resolve local `Microsoft.AspNetCore.App.Ref (= 10.0.13)`. The shared base also fails two bounded-time cases in `tests/test_appimage_package_retry.py`; that test passes here. No package was installed and no failed run was discarded. Forgejo has no CI runner. The first Windows-target fixture capture failed five deprecated-`memcpy` diagnostics. After the early CRT guard, its one captured translation unit passes with the same warnings-as-errors settings. That is syntax only, not native Windows execution. The historical GitHub Windows run at the pre-rename head is not a check of this Longshot head. **Historical game evidence, not repeated:** Hookshot base `51da0464`, mask change `7dc0773b`, 2026-11-12, RTX 4090/NVIDIA 615.78.08 on this Linux PC. Six windowless runs at 4432x1856 or 3840x2160 showed full-width fade coverage and unchanged pause/Map centring. The 21:9 loading icon becomes a dim blur with blurred sides, disappears behind black bars, and is sharp but stretched in Full width. The first 16:9 route did not reach the actual Map; a later corrected route did. One startup virtual-core escape occurred in the first 16:9 run; all six had zero fatal/crash/device-loss/driver-fault counts. These were ordinary shared runs, not performance measurements. ### How to reproduce How to reproduce: use the exact fixture/source matrix below; the historical visual route is separate. For the recorded compiled comparison, use separate checkouts named `baseline` at `d4a69456c9de5131589af1fcf9a09adba4c403d1` and `candidate` at `49a7c60bbef0ee87276e6767dbbc5ad83d74864d`. From their parent directory, use the same Clang installation for all four commands, in this order; each invocation compiles and runs authored 16:9/21:9 canvas state, without a game or Vulkan device: ```sh python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source baseline python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source candidate python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source baseline python -I -B candidate/tests/test_wide_loading_fade.py --cxx clang++ --source candidate ``` Count the `FAIL:` behavior lines per invocation and report the median for each source: the retained counts are 12/0/12/0. The baseline exits nonzero deliberately. The whole-suite command was `python -I -B tests/run_all.py --jobs 6 --strict` in each named checkout, with a fresh HOME; the whole suites were single runs, not two interleaved suites. For the later CRT-only repair, use the fixture at `71e34ec3d746e40642650a115c3d43c746543c81`; only that fixture and the failed Windows-target step were repeated then. For visual reproduction, compare the historical Hookshot `main @ 51da0464` and mask-only `this PR @ 7dc0773b` at the same Hyrule Field save-load and Hyrule Field/Kokiri transition, then pause and open the actual Map. Use the game's upscaler, frame generation off, no UI mod, 4432x1856 game picture for the wide case and 3840x2160 for the 16:9 control; compare Centred, blurred sides, Centred, black bars, and Full width. Inspect both fade coverage and the loading icon, not equal opacity or matching frame numbers. These are reproduction conditions for the retained captures, not a claim that this Longshot head or the pane prototype was run. ## Testing **Tested:** Linux game-free checks on the branch-state head and shared base, with the default compiler, fresh isolated test environment and the full suite. Historical compiled main/branch pairs, Windows-target syntax, and the six inspected Hookshot visual/log runs retain their identities below; the visual runs were correctness checks, not speed measurements. **Not tested:** No Longshot game build/run, fresh visual proof or performance measurement. The pane-level replacement is not in this branch. No Windows game, native Windows execution of the new fixture, physical ultrawide display, AMD/Intel/Deck, HDR or frame-generated output. No test request was posted during this move. No new game build/run was requested for this dependency-held draft. This work was limited to windowless Linux checks; native Windows, physical ultrawide input/presentation and the other GPU systems above were not available for these runs. The branch-state head has run the complete source suite, including the changed fixture. Windows-target syntax remains the earlier labelled capture, not a new Windows execution. Tested but not measured: the six historical Hookshot windowless game runs on this Linux/RTX 4090 PC were ordinary shared runs. They provide the retained visual/log evidence, not FPS, frame-time, stutter or performance measurements. No current Longshot game has been run for this proposal. **Needs other testers:** - Windows with a physical ultrawide display: compare loading, pause and Map against main, expecting full-width fade coverage and the documented blurred/hidden icon trade-off, not a complete icon fix (request to open). - Linux AMD/Intel and Steam Deck: check the same centred/full-width modes and transitions, expecting unchanged pause/Map centring and no additional rendering/stability regression beyond the known icon defect (request to open). ## Screenshots Historical game labels: `main @ 51da0464` is the baseline and `this PR @ 7dc0773b` is the mask-only renderer change. They are not the current rebased Longshot commits or the migration-time fixture heads. ![Hookshot `51da0464` versus mask-only `7dc0773b`, 2026-11-12: full-width fade coverage; pause and Map stay centred. Loading frames compare coverage, not equal opacity or frame numbers.](https://git.magicbean.dev/attachments/253c477e-e99b-4359-8ad1-643a2b5e4ce5) ![Same historical mask-only stage: sharp centred icon before, dim blur with blurred sides, hidden by black bars, sharp but stretched in Full width. This is why the draft remains blocked.](https://git.magicbean.dev/attachments/b6a064bc-03e9-4953-bfad-455b1be7e9a6) Both retained original panels were inspected. They are not photographs of a Longshot build or of the separate pane prototype. ## Risk and rollback The original review's blocker is real: covering the fade by widening the whole canvas moves and stretches the icon too. A dark-pixel heuristic or an unproved pane patch is not included as a workaround. The known risk is already visible: the default blurred-sides mode smudges the loading indicator at the edge, black bars hide it, and Full width leaves it sharp but stretched. Fade coverage alone is not a complete visual fix or permission to merge. Other hardware and output modes listed under Not tested have no runtime proof here. This proposal adds no dedicated runtime opt-out. Revert the `wide_sides()` mask-policy change (`kMenus` back to `0xa`, centred keep-mask back to `0x5`) to restore the prior behavior; that also restores the original exposed side strips during loading fades. Selecting Full width is not a centred-icon fix. No shader or host API rollback is needed. ## Reviewer notes Start with `wide_sides()` in `gpu/vk/vk_framegen.cpp`, the canvas descriptions/HUD patch in `nx2/oot_wide.py`, then `tests/test_wide_loading_fade.py`. The early CRT definition changes fixture portability only; it leaves all behavioral assertions and warning flags intact. **Still owed from hckrman101's review:** keep the loading canvas centred and widen only its spanning fade pane on the dependency's per-pane path; follow its renumbered modes; fold the duplicated Ultrawide menus README bullets together; derive fixture addresses from `wide.KEEP_VTABLES`; print failures for the grace-period/wheel checks; repeat 21:9 fade/icon pictures. Both sets of historical result rows are retained. The separate Hookshot pane prototype and its pictures are not silently substituted for this posted mask-only branch. The requested fix keeps the loading canvas squeezed and the icon sharp inside the middle 16:9, widening only the spanning fade pane through the dependency's existing per-pane path. That allows `kMenus` to stay `0xa` with its comment corrected. The dependency renumbers Extended to 1 and centred modes to 2/3 (`side = mode - 1`), so the current fixture's `side == mode` and `mode ? 0xd : 0xf` assumptions must change with that replacement. Both historical result-row sets remain; neither the README consolidation nor the fixture nits were silently done in a rules-only rebase. A reporter check on the real 3440x1440 display remains welcome, not claimed. This remains WIP waiting on the dependency and the reviewed pane-level direction, not a readiness request. The separate prototype and its different build identities remain in the carried discussion, not in this branch's proof. ## Issues Original report: https://github.com/NotRexed/Hookshot/issues/2220 Original draft/review: https://github.com/NotRexed/Hookshot/issues/2851 Dependency: https://github.com/NotRexed/Hookshot/issues/2843 On this forge: See #82 (this report) and See #64 (the broader HUD and menu layout proposal, which this does not close). Old GitHub numbers are not Forgejo issue numbers. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [ ] Rebased on current `main`. Kept on the tested base under the central-refresh policy; Main handles a later refresh before ready. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). Exact rebased head checked; inherited NU1100 only. - [x] Tested in the game, or what wasn't is named under Testing. Draft; no new Longshot game run. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [ ] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Historical compiled behavior proof has two interleaved pairs and a median; the new-head comparison and complete visual fix remain open. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [ ] Flags noted, and the switch reference updated (docs/development.md, the README). Table complete; choices/default and the existing README warning retained, but the requested README consolidation still waits with the pane replacement. No environment switch was added. - [x] Screenshots for a change that shows on screen. Historical, with their actual build identities above. - [x] A game-free test added for the fix, failing on `main` and passing here. Historical negative controls retained; the test also passes in the exact-head full suite. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. No current game builds; fixture checks only. - [ ] Docs updated. Historical notes retained; the requested README consolidation still waits with the pane replacement. --- Moved from NotRexed/Hookshot#2851. Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <[email protected]>
Keep the loading-fade canvas in the full-width mask in both centred menu modes. The pause background still centres, and Full width and 16:9 projections stay unchanged. Credit EjianYT for identifying the loading-fade bit in issue #2220.

Compile the real mask policy and HUD patch in a game-free regression fixture. Document the shared loading-icon layout trade-off.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Keep the mask-only proposal a draft: real scale-pass captures show that centred blurred sides blur the loading icon and black bars hide it. Record the six runs, including unsuccessful input helpers and the unchanged 16:9 controls.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Keep the existing warning flags and behavioral assertions; match the other Windows-capable fixtures.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Author
First-time contributor

Discussion carried over from NotRexed/Hookshot#2851

Every comment that was readable on the original thread when it was copied on 2026-11-12, in order, unchanged except that issue and pull request numbers are written as links to the old repository and names carry no @. Comments by an account that has since been closed there could no longer be read and are missing; where a reply quotes them, the quote remains.


mooki000, 2026-11-12 17:21 UTC (comment, original):

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:

  • Pane level, on NotRexed/Hookshot#2843. Keep the loading screen squeezed in the centred modes and widen only its spanning fade pane through NotRexed/Hookshot#2843's per-pane path, so the mask stays 0xa and only its comment is corrected. I am reading NotRexed/Hookshot#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.
  • Order. NotRexed/Hookshot#2843 first, then this rebased onto it, with the test's side == mode and mode ? 0xd : 0xf expectations moved to the renumbered modes.
  • The two test nits: the addresses from wide.KEEP_VTABLES, and a FAIL: line for the grace-period and wheel checks.
  • The readme note folded into main's Ultrawide menus bullet; if the icon stays sharp the "known cost" paragraph goes.
  • The table rows: both sets kept.
  • Pictures again at 21:9, icon and fade crops before and after, for the new version.

It stays a draft until then.


ozwaldorf, 2026-11-12 17:40 UTC (comment, original):

hckrman101 NotRexed/Hookshot#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


mooki000, 2026-11-12 20:06 UTC (comment, original):

The reporter's bit-3 diagnosis was right, but the fade needs to reach the sides without moving its icon into the blur or black bars.
Thanks hckrman101 and ozwaldorf. This is the centred-layout bridge ozwaldorf described as “fairly easy to bridge over support for”; NotRexed/Hookshot#2843 already handles Extended.
The small rule keeps mask 0xa and widens only a centred, canvas-spanning picture in LoadingFade_00, using the existing size hook. It matches the layout name and geometry, not a pane index; the four archive records are copies of the shared loading layout. A renamed layout or changed geometry in another game version would need updating.

Before/after came from one binary, 9c8b4708 on NotRexed/Hookshot#2843's 9a4c0177, with a local opt-out that is not committed.
Tested windowless on Arch Linux 7.2.15-1-omarchy, i9-13900K, RTX 4090/NVIDIA 615.78.08: actual 4432x1856 game picture, captured at 2216x928, no UI mod, game's upscaler, FG off; save load and Hyrule Field/Kokiri transitions.
The side strips during the loading fade at 21:9. 1. Before, blurred sides: the fade stops at the middle and the scene shows at the edge. 2. After: the fade fills the picture. 3. Before, black bars: a dark scene leaks at the sides. 4. After: the sides are covered too

The loading icon enlarged three times, before and after in both centred modes: the same sharp icon at the same place

Both centred modes now cover the strips while the icon stays sharp at the same position inside the middle 16:9; nothing else visible on the loading screen moved.
Two more panels, not attached, show the pause menu and the Map unchanged in both centred modes, and Extended checked once with its existing sharp edge icon unchanged.
The new regression fails 24 centred-width cases with both GCC and Clang before the rule and passes with both after it. Final suite: 502 passed, two known inherited failures (missing Skip opening README row and zstd fixture symbols), 20 skipped. Both Windows-target units compile; Windows execution still needs the fork run.
The isolated branch is now fix/wide-loading-fade-on-2843 at 511abae4, rebased onto NotRexed/Hookshot#2843's b1d47d31: its host/pane-hook source did not change; the fixture follows the option ID change 52→53. These are not pictures of a rebuilt b1d47d31 binary.
NotRexed/Hookshot#2843 is still open and unreviewed and may change again; it must land first. So this pull request stays a draft with its old mask-only commit until NotRexed/Hookshot#2843 is in; then I replace it with this pane-level rule, rebased, after a Windows run of the project's checks in my fork.
16:9 and Full width are checked game-free for this prototype; the earlier 16:9 pictures belong to the mask-only stage, not a new runtime check of this rule. No performance claim.

## Discussion carried over from NotRexed/Hookshot#2851 Every comment that was readable on [the original thread](https://github.com/NotRexed/Hookshot/pull/2851) when it was copied on 2026-11-12, in order, unchanged except that issue and pull request numbers are written as links to the old repository and names carry no @. Comments by an account that has since been closed there could no longer be read and are missing; where a reply quotes them, the quote remains. --- **mooki000**, 2026-11-12 17:21 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2851#issuecomment-6830774047)): 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: - **Pane level, on [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843).** Keep the loading screen squeezed in the centred modes and widen only its spanning fade pane through [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843)'s per-pane path, so the mask stays `0xa` and only its comment is corrected. I am reading [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/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. - **Order.** [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843) first, then this rebased onto it, with the test's `side == mode` and `mode ? 0xd : 0xf` expectations moved to the renumbered modes. - **The two test nits**: the addresses from `wide.KEEP_VTABLES`, and a `FAIL:` line for the grace-period and wheel checks. - **The readme note** folded into main's **Ultrawide menus** bullet; if the icon stays sharp the "known cost" paragraph goes. - **The table rows**: both sets kept. - **Pictures again** at 21:9, icon and fade crops before and after, for the new version. It stays a draft until then. --- **ozwaldorf**, 2026-11-12 17:40 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2851#issuecomment-6831234951)): hckrman101 [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/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 --- **mooki000**, 2026-11-12 20:06 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2851#issuecomment-6834605634)): The reporter's bit-3 diagnosis was right, but the fade needs to reach the sides without moving its icon into the blur or black bars. Thanks hckrman101 and ozwaldorf. This is the centred-layout bridge ozwaldorf described as “fairly easy to bridge over support for”; [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843) already handles Extended. The small rule keeps mask `0xa` and widens only a centred, canvas-spanning picture in `LoadingFade_00`, using the existing size hook. It matches the layout name and geometry, not a pane index; the four archive records are copies of the shared loading layout. A renamed layout or changed geometry in another game version would need updating. Before/after came from **one binary**, `9c8b4708` on [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843)'s `9a4c0177`, with a local opt-out that is **not committed**. Tested windowless on Arch Linux 7.2.15-1-omarchy, i9-13900K, RTX 4090/NVIDIA 615.78.08: actual 4432x1856 game picture, captured at 2216x928, no UI mod, game's upscaler, FG off; save load and Hyrule Field/Kokiri transitions. ![The side strips during the loading fade at 21:9. 1. Before, blurred sides: the fade stops at the middle and the scene shows at the edge. 2. After: the fade fills the picture. 3. Before, black bars: a dark scene leaks at the sides. 4. After: the sides are covered too](https://gist.githubusercontent.com/mooki000/b86bd3f35969803fb032f71f035844f8/raw/69db39c2c777a82beb3975ee4f079dace5d207e2/137-loading-fade-pane-coverage.jpg) ![The loading icon enlarged three times, before and after in both centred modes: the same sharp icon at the same place](https://gist.githubusercontent.com/mooki000/b86bd3f35969803fb032f71f035844f8/raw/69db39c2c777a82beb3975ee4f079dace5d207e2/138-loading-fade-pane-icons.jpg) Both centred modes now cover the strips while the icon stays sharp at the same position inside the middle 16:9; nothing else visible on the loading screen moved. Two more panels, not attached, show the pause menu and the Map unchanged in both centred modes, and Extended checked once with its existing sharp edge icon unchanged. The new regression fails 24 centred-width cases with both GCC and Clang before the rule and passes with both after it. Final suite: 502 passed, two known inherited failures (missing Skip opening README row and zstd fixture symbols), 20 skipped. Both Windows-target units compile; Windows execution still needs the fork run. The isolated branch is now `fix/wide-loading-fade-on-2843` at `511abae4`, rebased onto [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843)'s `b1d47d31`: its host/pane-hook source did not change; the fixture follows the option ID change 52→53. These are not pictures of a rebuilt b1d47d31 binary. [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843) is still open and unreviewed and may change again; it must land first. So this pull request stays a draft with its old mask-only commit until [NotRexed/Hookshot#2843](https://github.com/NotRexed/Hookshot/issues/2843) is in; then I replace it with this pane-level rule, rebased, after a Windows run of the project's checks in my fork. 16:9 and Full width are checked game-free for this prototype; the earlier 16:9 pictures belong to the mask-only stage, not a new runtime check of this rule. No performance claim.
mooki force-pushed fix/wide-loading-fade from 71e34ec3d7 to 58143b9df4
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 2s
2026-11-13 02:00:56 +00:00
Compare
Author
First-time contributor

Updated the description to the current template: Testing with what was tested, what was not and which testers are needed, the whole checklist, and one block for the branch's base and suite. Rebased onto main d725b363 with the patches unchanged; whole suite on 58143b9d: 511 passed, 1 failed, 20 skipped, the one failure being the local .NET reference pack that also fails on main. It merges cleanly with the newer main and stays work in progress for the pane-level dependency and the loading-icon regression.

Updated the description to the current template: Testing with what was tested, what was not and which testers are needed, the whole checklist, and one block for the branch's base and suite. Rebased onto main d725b363 with the patches unchanged; whole suite on 58143b9d: 511 passed, 1 failed, 20 skipped, the one failure being the local .NET reference pack that also fails on main. It merges cleanly with the newer main and stays work in progress for the pane-level dependency and the loading-icon regression.
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 2s
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'fix/wide-loading-fade:mooki-fix/wide-loading-fade'
git switch 'mooki-fix/wide-loading-fade'
Sign in to join this conversation.
No description provided.