fix(vk): Auto (this PC) reads the primary monitor when there's no window, so an update no longer lowers the resolution #176

Merged
HumanBean merged 1 commit from d4nkn3ss/Longshot:fix/auto-screen-without-window into main 2026-11-13 11:09:23 +00:00
Contributor

Why

Updating a game folder with the Builder could lower the player's resolution on Windows: the update's shader preparation has no window, so "Auto (this PC)" saw a 0x0 screen, decided the hardware had changed, chose again and wrote that over the player's settings (#165: 2560x1440 became 2048x1152). A headless start did the same.

What changed

  • vk: auto_profile() in gpu/vk/vk_main.cpp (Windows) asks MonitorFromWindow(main_window, MONITOR_DEFAULTTOPRIMARY) without first requiring a window: with main_window NULL that is the primary monitor. With no window it also takes that monitor's refresh rate, which display_refresh_mhz() reports as 0 then. With a window, nothing changes: the window's monitor and display_refresh_mhz() as before.
  • display_refresh_mhz() itself is unchanged: frame pacing and frame generation keep their own no-window behaviour.

Flags and settings

None

Measurements

main: fabcd2c0 (2026-11-13)
this PR: fix/auto-screen-without-window @ a25867e5
Hardware: RTX 3080 10 GB, NVIDIA 621.14, i9-12900K, 64 GB RAM, Windows 11; primary screen 2560x1440 at 165 Hz
Scene: n/a: the start's Auto line and longshot_options.ini, from the same standalone build with main's and this PR's longshot_vk.dll swapped in
Method: an options file written by a windowed first start (auto_for=744c6a1e8b5735b7, output_res=2048x1152), copied back before each run; then a headless start (HOS_HEADLESS=1) and a preparation-only start (--prepare-shaders) with each DLL, comparing the options file before and after and the log's vk: Auto (this PC) line
How to reproduce: start a game folder once normally, then start it with HOS_HEADLESS=1 (or let the Builder update it) and compare auto_for= in longshot_options.ini

main @ fabcd2c0 this PR @ a25867e5
headless start: options file rewritten, auto_for=65cf663444a98857 unchanged
preparation-only start: options file rewritten, auto_for=65cf663444a98857 unchanged
a fresh folder whose first start is the preparation: auto_for= not measured on main (0x0 screen, so a fingerprint the first windowed start doesn't have) 744c6a1e8b5735b7, the same as a windowed first start
main, headless:   vk: Auto (this PC): the hardware changed: 10051 MB of video memory: tier 3; ... screen 0x0 at 0 Hz, 65312 MB of RAM, 24 threads)
PR, headless:     vk: Auto (this PC): the settings chosen for this PC before (NVIDIA GeForce RTX 3080, ... screen 2560x1440 at 165 Hz, ...)
PR, prepare:      vk: Auto (this PC): the settings chosen for this PC before (... screen 2560x1440 at 165 Hz, ...)
PR, fresh folder: vk: Auto (this PC): first start: 10051 MB of video memory: tier 3; ... screen 2560x1440 at 165 Hz, ...)

Testing

Tested: the runs above on Windows 11 (main's and this PR's DLL in the same build). tests/test_auto_settings.py passes.

Full suite: python -I -B tests/run_all.py on main @ fabcd2c0 with this change, Windows 11: 499 passed, 3 failed, 34 skipped; all three fail on main too: tests/test_check_third_party.py (#80), tests/test_release.py (#119, #144, #145) and tests/test_builder_dlss_update.py (its C# fixture doesn't build here: a dotnet without the SDK).

Not tested: Linux: auto_profile() there still takes the size from the window (desktop_size), so a window-less run fingerprints 0x0 as before; this PR leaves that path alone. Several monitors with the game on a non-primary one: a window-less run takes the primary, so a player whose game window sits on another monitor of a different size would still see Auto choose again.

Needs other testers: None

Screenshots

Nothing on screen

Risk and rollback

Only window-less runs change, and only on Windows: they now see the primary monitor where they saw nothing. Reverting the commit is enough.

Issues

Fixes #165

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • 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. (Each start's result is the same every run: a fingerprint and a file, not a timing.)
  • 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.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (The change is in the _WIN32 branch; the Linux branch is untouched.)

🤖 Generated with Claude Code

## Why Updating a game folder with the Builder could lower the player's resolution on Windows: the update's shader preparation has no window, so "Auto (this PC)" saw a 0x0 screen, decided the hardware had changed, chose again and wrote that over the player's settings (#165: 2560x1440 became 2048x1152). A headless start did the same. ## What changed - vk: `auto_profile()` in `gpu/vk/vk_main.cpp` (Windows) asks `MonitorFromWindow(main_window, MONITOR_DEFAULTTOPRIMARY)` without first requiring a window: with `main_window` NULL that is the primary monitor. With no window it also takes that monitor's refresh rate, which `display_refresh_mhz()` reports as 0 then. With a window, nothing changes: the window's monitor and `display_refresh_mhz()` as before. - `display_refresh_mhz()` itself is unchanged: frame pacing and frame generation keep their own no-window behaviour. ## Flags and settings None ## Measurements main: fabcd2c0 (2026-11-13) this PR: fix/auto-screen-without-window @ a25867e5 Hardware: RTX 3080 10 GB, NVIDIA 621.14, i9-12900K, 64 GB RAM, Windows 11; primary screen 2560x1440 at 165 Hz Scene: n/a: the start's Auto line and `longshot_options.ini`, from the same standalone build with main's and this PR's `longshot_vk.dll` swapped in Method: an options file written by a windowed first start (`auto_for=744c6a1e8b5735b7`, `output_res=2048x1152`), copied back before each run; then a headless start (`HOS_HEADLESS=1`) and a preparation-only start (`--prepare-shaders`) with each DLL, comparing the options file before and after and the log's `vk: Auto (this PC)` line How to reproduce: start a game folder once normally, then start it with `HOS_HEADLESS=1` (or let the Builder update it) and compare `auto_for=` in `longshot_options.ini` | | main @ fabcd2c0 | this PR @ a25867e5 | |---|---|---| | headless start: options file | rewritten, `auto_for=65cf663444a98857` | unchanged | | preparation-only start: options file | rewritten, `auto_for=65cf663444a98857` | unchanged | | a fresh folder whose first start is the preparation: `auto_for=` | not measured on main (0x0 screen, so a fingerprint the first windowed start doesn't have) | `744c6a1e8b5735b7`, the same as a windowed first start | ``` main, headless: vk: Auto (this PC): the hardware changed: 10051 MB of video memory: tier 3; ... screen 0x0 at 0 Hz, 65312 MB of RAM, 24 threads) PR, headless: vk: Auto (this PC): the settings chosen for this PC before (NVIDIA GeForce RTX 3080, ... screen 2560x1440 at 165 Hz, ...) PR, prepare: vk: Auto (this PC): the settings chosen for this PC before (... screen 2560x1440 at 165 Hz, ...) PR, fresh folder: vk: Auto (this PC): first start: 10051 MB of video memory: tier 3; ... screen 2560x1440 at 165 Hz, ...) ``` ## Testing **Tested:** the runs above on Windows 11 (main's and this PR's DLL in the same build). `tests/test_auto_settings.py` passes. **Full suite:** `python -I -B tests/run_all.py` on main @ fabcd2c0 with this change, Windows 11: 499 passed, 3 failed, 34 skipped; all three fail on main too: `tests/test_check_third_party.py` (#80), `tests/test_release.py` (#119, #144, #145) and `tests/test_builder_dlss_update.py` (its C# fixture doesn't build here: a `dotnet` without the SDK). **Not tested:** Linux: `auto_profile()` there still takes the size from the window (`desktop_size`), so a window-less run fingerprints 0x0 as before; this PR leaves that path alone. Several monitors with the game on a non-primary one: a window-less run takes the primary, so a player whose game window sits on another monitor of a different size would still see Auto choose again. **Needs other testers:** None ## Screenshots Nothing on screen ## Risk and rollback Only window-less runs change, and only on Windows: they now see the primary monitor where they saw nothing. Reverting the commit is enough. ## Issues Fixes #165 ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (Each start's result is the same every run: a fingerprint and a file, not a timing.) - [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. - [x] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (The change is in the `_WIN32` branch; the Linux branch is untouched.) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(vk): Auto (this PC) reads the primary monitor when there's no window, so an update no longer lowers the resolution
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 10s
a25867e5a5
auto_profile() read the screen only through the game's window, so the Builder's shader preparation and a headless start
fingerprinted a 0x0 screen at 0 Hz: no options file had that fingerprint, Auto chose again "for this PC" and wrote it
over the player's settings (a player's 2560x1440 became 2048x1152 after a Builder update). With no window it now
takes the primary monitor (MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY)) and its refresh rate. Fixes #165.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
HumanBean deleted branch fix/auto-screen-without-window 2026-11-13 11:09:23 +00:00
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 10s
Some workflows are waiting to be reviewed.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
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/Longshot!176
No description provided.