Skip to content

feat(video): support 48:9 triple-monitor picture geometry - #2052

Merged
hckrman101 merged 2 commits into
NotRexed:mainfrom
Arkex-ai:feat/triple-monitor-48-9
Nov 11, 2026
Merged

hckrman101 merged 2 commits into
NotRexed:mainfrom
Arkex-ai:feat/triple-monitor-48-9

Conversation

@Arkex-ai

@Arkex-ai Arkex-ai commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

On a 48:9 desktop the camera stopped widening at 32:9, and the game rejected custom outputs such as 5760×1080 and 7680×1440. Both settings now give a wider view and keep the HUD in the center 16:9 area.

Addresses the 48:9 request in #1007, originally reported in #2039.

Technical changes

  • Use the same output limits in the host and menu. A custom output above 32:9 selects the camera shape when the OS reports a single 16:9 primary display.
  • Keep the internal pixel budget. 5760×1080 renders at full size, and 7680×1440 uses an aligned 6528×1224 picture at the exact 48:9 ratio.
  • Present with the existing aspect-preserving path. To fill three displays, use a 48:9 logical display or a spanning window.

Validation

  • At 0d5e2981, geometry and output fixtures pass on Windows LLVM-MinGW and Linux GCC. The new four-decimal case fails before the fix (6608x1240) and passes after it (6528x1224). Full local suite: Windows 325 passed / 3 failed / 25 skipped; Linux 330 / 1 / 22. All three Windows failures reproduce on main f915af93; Linux lacks the bake fixture dependency covered by fix(build): run offline bake with portable zstd and Clang 18 #1954.

  • Current-head upstream source checks fail in finish-output fixtures after main added FSR runtime provisioning; existing test: the finish checks give the build its arguments, read since #1866 #2102 owns the fixture correction. These differ from the local failures. Windows build/package and AppImage passed.

  • At 557542cd on d47206ed, the geometry and output fixtures passed on Windows and Ubuntu. All 11 Windows startup cases also passed. The previous revision also passed the geometry, parser and presentation rectangle checks on Windows and Ubuntu.

  • Native Windows smoke at 9ed2da57 on RTX 5070 Ti used both output settings in a 1920×360 window. Vulkan reported source sizes of 5760×1080 and 6528×1224, with a full 1920×360 destination in both cases. Captures decoded at the two configured output sizes. The HUD stayed in the middle third and the house-to-Kokiri Forest transition completed in both runs.

  • With 7680×1440 configured, maximizing to a 3440×1369 swapchain kept a 3440×645 centered destination. Both runs exited normally and preserved the original checkpoint hashes.

  • The brief black center with visible sides during the opening transition was also reproduced at 32:9 on the pre-change build 600960cd. Linux gameplay, campaign-wide cutscenes and a physical three-monitor span remain untested.

Dev-work claim.

Current-head check (0d5e2981) Result
Linux AppImage Passed
Windows build Passed
Source suite Failed: inherited finish fixtures (#2102); remaining checks pending

@Arkex-ai
Arkex-ai force-pushed the feat/triple-monitor-48-9 branch from 9ed2da5 to 557542c Compare November 11, 2026 01:19
@Arkex-ai
Arkex-ai marked this pull request as ready for review November 11, 2026 01:33

@ghost ghost left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. The 32:9 and 48:9 limits now live in one place (hos_output_size_valid / hos_output_is_surround in hos_wide_size.h), so the host parser and the menu can't drift apart any more. The host and the menu both force the surround shape for a >32:9 custom output, so the menu's Render resolution rows match what boot picks. The 24-row alignment checks out: 7680x1440 goes over the 3840x2160 budget and comes out at exactly 6528x1224 (48:9), and 5760x1080 fits in the budget at full size. Handheld is unaffected because hos_output_size reports 2560x1440 there. The pool goes to 515 MB and 900 MB as the test expects. Nothing on main since the base touches these files, and CI is green.

A few nits, none blocking:

  • hos_main.c: a surround output now overrides an explicit HOS_ASPECT (see inline).
  • hos_wide_clamp: the 1e-6 snap doesn't catch the 4-decimal form (see inline).
  • vk_menu.cpp picture_for: the doc comment above it still says "with Ultrawide on". A surround output now takes this path with Ultrawide off too, so it's worth a few words there.

The opening-transition black centre is also on the pre-change 32:9 build, so I agree it's not from this PR. A real three-monitor span and Linux are still untested, as the description says.

Comment thread host/hos_main.c
uint32_t hos_output_size(int height);
const uint32_t output_w = hos_output_size(0), output_h = hos_output_size(1);
/* A custom surround output explicitly requests that shape, even if the OS reports one monitor. */
if (hos_output_is_surround(output_w, output_h)) want = (float)output_w / (float)output_h;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this also runs when HOS_ASPECT is set, so HOS_ASPECT=1.7778 (or 0) can't opt out of the surround camera with a 5760x1080/7680x1440 output. The block comment above still says HOS_ASPECT wins. If the override is intended, a word in that comment would do. If not, if (!e && hos_output_is_surround(...)) keeps the env var as the escape hatch. (The menu ignores HOS_ASPECT anyway, so either choice is consistent with it.)

Comment thread host/hos_wide_size.h Outdated
return want > 32.0 / 9.0 ? 32.0 / 9.0 : want < 5.0 / 4.0 ? 5.0 / 4.0 : want;
const double surround = 48.0 / 9.0;
/* Accept the rounded value commonly used for HOS_ASPECT. */
return want >= surround - 0.000001 ? surround : want < 5.0 / 4.0 ? 5.0 / 4.0 : want;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the 1e-6 tolerance catches 5.333333 but not 5.3333, which is the 4-decimal form the docs use for HOS_ASPECT (2.3889). With HOS_ASPECT=5.3333 at the 1440 output, r isn't exactly 48/9, so hos_wide_size takes the 8-row path and gives 6608x1240 (5.329) instead of 6528x1224. A tolerance like 1e-4 would snap both. Only matters for the env var: the output-derived ratio is exact.

Document custom surround output precedence and match the menu description.

Assisted-by: GPT-6 (Codex)
@Arkex-ai

Copy link
Copy Markdown
Contributor Author

Addressed the three nits at 0d5e2981. A custom output above 32:9 intentionally takes precedence, keeping startup and menu geometry consistent; both comments now say so. The clamp accepts four-decimal 48:9 input. The added regression fails before the fix (6608x1240) and passes after it (6528x1224). Geometry and output fixtures pass on Windows LLVM-MinGW and Linux GCC. Fresh full-suite/build checks are pending; the description separates them from earlier evidence.

@hckrman101
hckrman101 merged commit b46b60f into NotRexed:main Nov 11, 2026
10 of 13 checks passed
pmwork-personal added a commit to pmwork-personal/Hookshot-pr that referenced this pull request Nov 11, 2026
Brings in NotRexed#2052 (48:9), NotRexed#2078 (the off value's label) and NotRexed#2041 (the
V-Sync row). Conflicts resolved with upstream's text kept and the row's
new name on top:
- vk_menu.cpp picture_for and hos_main.c's widescreen comment: NotRexed#2052's
  wording, "Ultrawide" read as the Aspect ratio.
- tx_ultrawide: 16:9 again instead of NotRexed#2078's "Off (16:9)". NotRexed#2078 added
  "Off" because "Ultrawide: 16:9" read as already on; under the name
  Aspect ratio the value is a shape, and "Aspect ratio: Off (16:9)"
  would not read well.
- readme: the settings table and NotRexed#2052's Output resolution notes, with
  the row's new name.
- test_audio_output_menu.py, test_stick_dead_zone.py: the option stubs
  take both NotRexed#2041's vsync and the ultrawide key.
Also follows the rename where the first commit missed it:
recomplauncher.json (label, help, and its default now 1, so the
launcher does not write 16:9 over the new default) and
tests/test_menu_restart.cpp's sample row names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pmwork-personal added a commit to pmwork-personal/Hookshot-pr that referenced this pull request Nov 11, 2026
Brings in NotRexed#2052 (48:9 surround), NotRexed#2041 and the rest of main. NotRexed#2052's
code is kept as merged (output limits, hos_wide_clamp up to 48:9, the
24-row alignment at 48:9); the cap and HOS_WIDE_MAX_PX sit on top.

With the 5120x2160-pixel cap, 48:9 comes out as:
- the 7680x1440 output: full size (it has exactly 5120x2160's pixels)
  instead of 6528x1224. Its pool stays 900 MB, set by the output's own
  size as before; the 5120x2880 output already plays in that pool with
  more pixels.
- 48:9 at the 4K output (11520x2160 wanted): kept to 7680x1440, exactly
  48:9, pool 915 MB, the same pixels and pool as 21:9's 5120x2160.

Tests follow: test_widescreen_shapes.py takes the full-size 7680x1440
and a 48:9-at-2160 case, and keeps NotRexed#2052's 6528x1224 cases (the 24-row
alignment and the four-decimal 5.3333) under HOS_WIDE_MAX_PX=8294400,
the old cap; test_output_resolution.py's 7680x1440 output is full size
(its scene special case is no longer needed); test_rt_pool_minimum.py
has 48:9 at the 4K output (915 MB). The readme's 7680x1440 sentence
and the cap follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant