feat(video): a Window choice that fills the actual window, Hor+ and Vert+ #142
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!142
Loading…
Reference in a new issue
No description provided.
Delete branch "simonwjackson/Longshot:feat/window-aspect"
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?
Why
Monitor's shape follows the monitor, not a resized window. Window fills the actual window, showing more at the sides on wide shapes and preserving the 16:9 horizontal view on narrower shapes.
What changed
ultrawide=2), opt-in and selected after restart. No new option ID; existing monitor/output modes keep their defaults.hos_wide_ratioremain fixed at startup for upscaling/DLSS jitter.hos_wide_resizeupdates squeeze/margin; THUMB uses its own live getter. Startup and live shapes use main's 5:4..48:9 clamp, including renderer draw-time UI correction. Cached canvases refit without recreating guest targets.aspect_starteddistinctly from Window.f3fe1763through072c38a, keeping both Window's README paragraph and #55's saved-render-scale paragraph. Later commits add tests and measured-run rows.Flags and settings
ultrawide=2HOS_ASPECT(existing)The picture size is set by the window's shape at start. A windowed start is normally 1280×720. Widening it later can look softer than Monitor's shape because the targets do not grow. Start full screen or use
HOS_WINDOW_SIZEto choose another initial shape. These limits are in the hint, README and options-file reference.Measurements
main:
f3fe1763dd(2026-11-13)this PR: feat/window-aspect @
6f39e8dc82Those are the built and measured sources. Current head
f8d5b964f427cb0290923ef9d2d4ffb4d24e8fc7adds only tests/documentation after that runtime build. Mainf3fe1763was current when this revision started and was merged in072c38a. Main advanced during the serialized builds to514591a3; a final three-way merge check is clean. That newer snapshot is not included or claimed tested here.Hardware: RX 7900 XT, RADV Mesa 26.2.3; Ryzen 5 7600X, 32 GB; NixOS 26.11, Linux 7.2.7, private Sway/Xwayland.
Scene: Castle Town wooden door (
Market_Child), identical copied save, stationary. 1280×720 drawable, 1920×1080 output, render 100%, game's upscaler, compute mesh fallback, FG/HDR off, uncapped, V-Sync Auto. Audio disabled.Method: fresh Linux builds and native shader preparation; two interleaved pairs, main/PR/main/PR, Monitor's shape on both. Warm-up before each 30 s sample; median of its last five presents-log readings. No other heavy build during these paired samples.
How to reproduce: load the same Castle Town save without moving, use the settings above and
ultrawide=1, warm up, then retain five steadyvk: ... presents, ... fpsreadings. For the live check use Window, restart, open Items, widen to 2520×1080, switch blurred/black sides, and return to 1280×720.f3fe1763, Monitor6f39e8dc, MonitorThe 0.05 FPS difference is inside the run-to-run spread; these two pairs show no observed default-path regression in this scene, not a general speed claim. The bridge reported
16:9 (monitor's)in all four runs.Exact presents-log samples, in run order
Functional proof at this PR @
6f39e8dc82:The two functional runs overlapped another CPU build. Their diagnostic medians (43.2 and 44.8 FPS) are recorded in the ledger but are not a performance comparison. The earlier four runs at main
316f9319/ PR1c66d19bare also recorded there as historical evidence, not measurements of this revision.Testing
Tested: fresh Linux NUP builds, source audits (2183 PR / 2177 main archived files, no mismatches), native shader preparation, paired default-path runs and the live resize/menu checks above. Inspected screenshots; both private test units stopped after each session. Only private copies, copied saves and a private compositor were used; the shared GPU lock covered every preparation and run.
On zao,
flock /tmp/upstream-prs/suite.lock python -I -B tests/run_all.py --jobs 8 --timeout 1200: 516 passed, 4 failed, 16 skipped. Two new source-reading fixture failures were fixed inaa44d39by including the actual helper/header; the subsequent focused run passed 13/13. The remainingtest_linux_tools.py(Nix PATH fixture) andtest_menu_i18n.py(stale existing translation key) fail on untouchedf3fe1763too. Main's semaphore/upscaler fixtures pass. No stale translation key is unique to this PR. The full suite was not repeated after the fixture/documentation-only commits.The regression test executes actual
host_wide_menus→wide_sidescode for blurred/black/off modes; it fails on pre-fix PR072c38aand passes now. Other tests execute the injected MOVIE/THUMB sites, verify fixed DLSS ratio, checked aspect bounds, recycled-view retirement, FOV interaction, zero-size resize handling, real option saving and headless camera fallback. There is no standalone formatter/typechecker; native fixtures compile, the suite byte-compiles Python, andgit diff --checkpasses.Not tested: Windows build/gameplay and non-ASCII Windows paths; other GPUs and physical handhelds; HDR and DLSS/FSR/FG; full playthrough; visual movie playback and newly saved thumbnail contents after resizing (those sites have game-free coverage); native Wayland's asynchronous fullscreen transition; headless gameplay. The tested Xwayland starts reported the requested drawable before picture sizing, but that does not establish native Wayland timing.
Needs other testers:
Screenshots
These are attachments to this public PR, not raw links into the private fork. Anonymous browser GETs returned 200 and matched the uploaded bytes. All shots are from the same Castle Town spot; menu captures are from that session.
Risk and rollback
Narrow startup shapes cost more pixels. Widening a small startup picture can look softer; extreme shapes are clamped, not unlimited portrait/surround support. Projection/UI cases outside the tested scene, temporal upscalers and asynchronous fullscreen backends still need coverage. Choose Monitor's shape or an explicit aspect and restart to disable Window. No public host/renderer interface or generated shader changes.
Reviewer notes
Review 1152's margin fix is in
6f39e8dc82ae.hos_wide_ratiois deliberately not live: DLSS jitter needs the allocated target shape. #95 should own its base layout usinghos_wide_aspect(), withoot_ui_squeeze.hretained as the live correction for cached canvases. This is a coordination proposal, not a claim that the branches have been combined. #57's keep-mask handling remains intact; #199's FOV interaction checks pass.Checklist
For everyone
type(scope): description).f3fe1763(current when this revision started) into the branch in072c38a; no rebase or force-push.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above). The two new fixture failures were corrected and their focused reruns pass; the exact full-run result is above.third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested-configurations.mdfor each measured run.mainand passing here. The live-side regression was reproduced on pre-fix PR072c38a, not untouched main, which has no Window mode; the new regression passes here.tests/that reads changed source updated in this PR, not weakened.d4nkn3ss referenced this pull request2026-11-13 06:34:02 +00:00
Added a fresh interleaved main/PR Linux measurement session at the named commits, the last-five-sample FPS medians, feature proof and inspected screenshots. Windows testing requests are open; the description names the remaining gaps. The branch also rebases cleanly onto main
1be180bbwith an identical stable patch ID and passing focused tests; the force-with-lease push is still gated, so the measured remote head stays pinned. No new baseline FPS is claimed for the local rebase. The four drawable shapes and live resize were checked; #95 loading-fade integration has its own open request.WIP: feat(video): a Window choice that fills the actual window, Hor+ and Vert+to feat(video): a Window choice that fills the actual window, Hor+ and Vert+Merged main snapshot
dd02c6cca9with a merge commit and normal push; resolved README using main’s current rows plus Window, and retained both main’s new default-output cases and our Window/save cases in test_output_resolution.py. Eleven focused checks pass; full suite: 506 passed, 3 failures reproduced on untouched main, 16 skipped; Linux build and isolated Castle Town smoke pass, and newer mainfdc2840bstill merges cleanly (details in Testing).Thanks. This is careful work. The Hor+/Vert+ projection is correct: the tangent is multiplied by 16:9 over the window's shape only when the window is narrower, so the horizontal view stays the 16:9 one. Keeping each projection's original tangent stops the FOV growing on repeated updates, and that also holds with the FOV slider's hook (the new block in
tests/test_oot_fov.py). A minimised window (0x0) is ignored, both inrx_resizeand inhos_wide_resize. A live resize changes no render target, so no upscaler history or guest heap has to be rebuilt. The swapchain is still remade the way main does it (swap_resizefolds a burst of resizes into one remake at the next present). The default doesn't change:ultrawide=0/1and a missing line read and save as before, andhos_wide_windowis set only byultrawide=2.HOS_ASPECTstill overrides. NoMkwVkHost/MkwVkRendererchange,third_party/untouched, no generated files.I read the code only. I didn't build it or run any checks.
Must change
It doesn't merge with current main. Main is now at
fbd42024.README.mdconflicts with the bullet that #55 added in the same place (f647a072, "Changing the Upscaler keeps your chosen render scale..."). Keep both bullets. Every other file merges cleanly (I checked with a three-way merge). The "Rebased on currentmain" box is false until then.After a live resize, movies, the menus' sides and the save picture still use the startup shape.
hos_wide_resizeupdates only the camera/HUD aspect.hos_wide_marginis set only inhos_wide_start, and two things still read it:host_wide_menus→vk_framegen.cpp wide_sides(), which places the blurred or black sides of the pause and map menus.The THUMB site likewise reads the startup
hos_wide_ratio. Two examples:Recompute
hos_wide_squeeze/hos_wide_marginfrom the live aspect inhos_wide_resize. Give THUMB a live ratio of its own.hos_wide_ratiohas to stay at the startup value, because the DLSS jitter (rx_backend.c dlss_jitter_clip) needs the shape the render targets actually have. These are the paths the description lists as untested; "Follows window resizes" isn't true for them yet.The checklist doesn't match the template.
docs/tested-configurations.md" was changed to "the folded table below". Add the rows to the file, as AGENTS.md asks.The screenshots return 404.
git.magicbean.dev/simonwjackson/Longshot/raw/commit/02f8cb12.../*.pngdoesn't resolve: the fork or that commit isn't reachable. Attach them to the PR so a reviewer can see Hor+/Vert+ and the centred HUD. If you can, add a main @ hash shot of the same spot at one of the resized sizes.Should change
hos_wide_picture_sizetakes any aspect: main'shos_wide_clamp(5:4 to 48:9) isn't applied. Its pixel cap can also break the "do not shrink below 1920x1080" comment. Below about 1:3, the width drops under 1920 (540x2160 → 1656x6648). Above about 10:1, the height drops under 1080, and from about 28:1 the width goes past 16384. You can only get there at startup withHOS_WINDOW_SIZEor full screen.HOS_WINDOW_SIZEis set. So a player who picks Window and maximises on a 21:9 screen gets a 2560x1440 picture stretched across 3440, which is softer than Monitor's shape. Say so in the hint and the README ("the picture's size is set by the window's shape at start"), or open the window at the size it last had.hos_sdl_pixel_sizeright afterset_fullscreenalready the full-screen size? On X11/Wayland, going full screen can be asynchronous. I haven't checked this.window_fit_active()callsgetenv("HOS_ASPECT")on every draw and every 0x90 uniform block in Window mode. Read it once.hos_wide_projectiontable.memmove.valid. In a window whose aspect equals the storedpatched_aspect(for example a square window), a new square shadow view at that address is then taken for a patched camera.HOS_HEADLESS: the picture keeps the monitor's shape fromhos_main.c, buthos_wide_aspect()is 0, so the cameras stay at 16:9 and the picture is stretched. The live_ratiodoesn't fall back to_ratio_fixed. This is a minor dev-only case.The other layout work
#95 rewrites the same
HUDstring innx2/oot_wide.py, so they will conflict as text, and whichever lands second has to port. As written, Window mode replaces #95's HUD outright:hos_ui_qx/qyand edge-anchored panes don't apply in Window mode;hos_wide_ui_tickreads the startuphos_wide_squeeze/hos_wide_ratio, which a live resize doesn't change.Please agree with #95's author which one owns the HUD projection. I'd suggest #95's layout taking
hos_wide_aspect()as its shape, with the draw-time refit (oot_ui_squeeze.h) staying as the live correction.#57 only changes which keep-mask bits the menus clear. Window's HUD branch still honours
hos_wide_keep_mask, so the two are compatible. Its fades still depend on the side margin from point 2 above.#199 and this PR edit different parts of
tests/test_oot_fov.py.The Output resolution row: in Window mode only the chosen size's height is used, and its shape is ignored. That matches
picture_for; the hint could say so.Nits
hos_display_startnow waits for the window for everyone, one interleaved pair on the default would settle it.aspect_startedstarts at -1, which is now Window's value untiloutputs_syncruns.@ -497,6 +497,12 @@ HDR, Detail, and GPU and memory (last: the rows to change when something is wronand **Sharpness** sharpens it, by the picture's pixels: when the window is much larger than the picture (the HandheldProfile's 1536x864 on a 4K screen), a Sharpness kept from an older version is stronger than it was, so a lower one maysuit.- **Window aspect ratio** (opt-in): fills the actual window. Wider than 16:9 shows more at the sides (Hor+);This conflicts with current main (
fbd42024): #55 added the 'Changing the Upscaler keeps your chosen render scale' bullet in the same place. Keep both.@ -3989,6 +4006,8 @@ void draw_startup(ui::Ctx& c) {} // namespacebool window_fit_active() { return ultrawide_read == 2 && !getenv("HOS_ASPECT"); }This is called per draw (
draw()) and per 0x90 uniform block (uniform_range) in Window mode, so it callsgetenvon the hot path. CacheHOS_ASPECTonce.@ -0,0 +16,4 @@float hos_wide_aspect(void) { return hos_wide_window ? atomic_load_explicit(&window_aspect, memory_order_relaxed) : hos_aspect_ratio; }void hos_wide_resize(unsigned width, unsigned height) {Only the camera/HUD aspect follows a resize here.
hos_wide_margin/hos_wide_squeeze, set once inhos_wide_start, still drive the MOVIE site and the menus' blurred/black sides (host_wide_menus->vk_framegen.cpp wide_sides), and THUMB reads the startuphos_wide_ratio. After a resize, movies and menu sides keep the startup shape. Recompute squeeze/margin here from the live aspect, and give THUMB its own live ratio. Keephos_wide_ratioas it is for the DLSS jitter, since the targets keep their startup size. The live aspect is also unclamped: a 1600x40 or 40x1600 window gives a view of about 175 degrees.@ -0,0 +21,4 @@if (aspect < 16.0 / 9.0) oh = (unsigned)(ow / aspect / 8 + 0.5) * 8;else ow = (unsigned)(oh * aspect / 8 + 0.5) * 8;/* Upstream's render-target pool guard (issue 1031): cap pixels, not shape. */if ((double)ow * oh > hos_wide_max_px()) {There's no
hos_wide_clamphere, unlike main's path, and this cap can break the comment above. Below about 1:3 the width drops under 1920 (540x2160 -> 1656x6648). Above about 10:1 the height drops under 1080, and from about 28:1 the width passes 16384. Clamp the aspect first (main's 5:4 to 48:9, or a portrait floor you've checked).@ -300,1 +312,4 @@if (getenv("HOS_FULLSCREEN") && atoi(getenv("HOS_FULLSCREEN"))) set_fullscreen(1);int pixel_w = 0, pixel_h = 0;hos_sdl_pixel_size(window, &pixel_w, &pixel_h);hos_wide_start(pixel_w, pixel_h);Is the pixel size already the full-screen size right after
set_fullscreen(1)? On X11/Wayland the switch can be asynchronous, and the picture is sized only from this value. Otherwise, a windowed start opens at 1280x720 in Window mode, so the picture is nearly always 16:9 and a maximised ultrawide window stretches 2560 pixels across 3440. Worth saying in the hint/README.@ -51,1 +87,4 @@HUD = "{ extern int hos_wide_window; if (hos_wide_window) " + HUD + " else " + HUD_FIXED + " }"MOVIE = ("{ extern volatile float hos_wide_margin; const float _m = hos_wide_margin; if (_m > 0.0f) { "MOVIE still reads
hos_wide_margin, which is only set at startup in Window mode, so movies leave the middle 16:9 after a live resize (see host/hos_wide.c).@ -48,6 +72,21 @@ HUD = ("{ extern volatile float hos_wide_squeeze; const float _q = hos_wide_sque"memcpy(c->vreg[1], _row, 16); } } } } /* (nx2/oot_wide.py: HUD in the middle 16:9) */"% (UI_M00, UI_M11, " : ".join("_vt == 0x%xULL ? %du" % (v, 1 << k) for k, v in enumerate(KEEP_VTABLES)) + " : 0u"))HUD = ("{ extern float hos_wide_aspect(void); const float _w = hos_wide_aspect(); if (_w > 0.0f) { float _m00, _m11; "#95 rewrites this same HUD string (
hos_ui_qx/qy, edge-anchored panes). In Window mode this branch replaces it outright, and #95'shos_wide_ui_tickreads the startup squeeze/ratio. Please agree with #95 which one owns the HUD projection before either lands.Addressed review 1152 in head
f8d5b964f427. The runtime fix is6f39e8dc82ae; later commits add regression coverage and the measured-run ledger.072c38abrings inf3fe1763. Both #55's saved-render-scale paragraph and Window's paragraph remain. No rebase or force-push. Main advanced during the serialized builds to514591a3; a final three-way merge check is clean, but that newer snapshot is not included or claimed tested. The checklist now says what was actually merged.hos_wide_resizeupdates squeeze/margin. MOVIE andhost_wide_menus→wide_sidesnow receive the live margin. THUMB callshos_wide_thumb_ratio;hos_wide_ratioremains the startup value for DLSS jitter. Actual injected MOVIE/THUMB code and the host-to-renderer blur/black-side path have executable regression tests. The new menu-side test fails before the fix and passes after it.docs/tested-configurations.md, below the day's existing rows. No folded-table substitute.window_fit_activecaches the HOS_ASPECT presence check once.hos_wide_aspectfalls back to the boot picture's aspect. The actual projection path is covered by a game-free test. No headless gameplay claim.hos_wide_aspect(), keepingoot_ui_squeeze.has draw-time live correction. The proposal is drafted, not an agreement yet. Combined-build coverage remains T-6SJP.aspect_startednow starts at -3, distinct from Window (-1), monitor (-2), and shape indices.Linux acceptance: start 1280×720, open Items, widen to 2520×1080; both blurred and black sides appear. Return to 1280×720: neither leaves bars. Repeat from a 2448×1848 startup. Inspected screenshots show Hor+/Vert+ and centred HUD. Movies and resized thumbnail contents have game-free coverage only; those visual checks, Windows, native Wayland fullscreen, HDR and temporal upscalers remain stated gaps.
Checks: full suite once, 516 passed / 4 failed / 16 skipped. Two new source-reading fixture failures were fixed without weakening assertions (
aa44d39), then the focused 13-check run passed. The remainingtest_linux_toolsandtest_menu_i18nfailures reproduce on untouchedf3fe1763; no stale translation key is unique to this PR. Both fresh Linux builds and their native shader preparations passed. No separate formatter/typechecker is configured; native fixtures compile, Python is byte-compiled by the suite, andgit diff --checkpasses.Please re-review the code and Linux evidence. Windows and #95 integration remain explicit test requests, not claimed passes.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.