fix(menu): run the upscalers' one-time probes during the start-up screen, not at the menu's first open (#1886) #1916
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1916
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/menu-probes-at-startup"
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?
For #1886, the menu open freezing the game and the audio going out of sync.
Measured: on a v2.0.14-line build with DLSS (G:\hk-v2015), I opened and closed the menu ten times by script during play with
RX_VK_FRAME_LOG.NVIDIA DLSS: NGX startedandfsr3: AMD FSR 3.1 can run on this GPUat that moment, then13.6 fps over the last 7.4 s.Cause: at the menu's first open,
vk_menu.cppasks on the frame's thread:dlss_probe()(NVIDIA's NGX start, about 3 s);fsr4_probe();fsr3::supported().While NGX starts the game stands still but its sound keeps going, so a cutscene's audio ends up out of step.
Fix:
startup_screen()starts the three probes once (std::call_once) on a thread of their own when the start-up screen first shows, during shader preparation, where nobody waits on them. Each is already locked and runs once (ngx_init'ss.muandngx_tried, FSR 4'sload()lock,fsr3::supported's static), so:A log line gives the background probe's time.
Not yet checked: a local in-game test of this change. My PC is kept free for the owner's v2.0.15 testing right now. CI compiles it on Windows (with and without DLSS) and Linux. I'll re-run the 10-open menu test on a build of this branch before merging.
🤖 Generated with Claude Code
The approach is right and the fix reads clean. On the thread-safety question you asked me to look at, here is what I checked in the code:
ngx_init(s.mu+ngx_tried) and FSR 4'sload()(l.mu+tried) are locked and run once, so the menu's later calls just wait or return.fsr3::supported()is a function-local static, so its first call is serialised by the magic-static guard.g.wave, which it writes, is read only aftersupported()returns (e.g.vk_fsr3.cpp:418before:423), so that is ordered too.g_whyis atomic.startup_screenis called from the prep loop invk_main.cpp, aftervkCreateDevice. So thedev.deviceguard passes in practice.What I could not verify, and what I'd test on your PC:
NVSDK_NGX_VULKAN_Init_with_ProjectIDnow runs on a worker thread while the start-up painter presents and the shader-prep worker builds pipelines on the sameVkDevice. Before, it ran on the frame's thread between frames. If NGX touches a queue or waits idle inside Init, that would now race the painter's present. I don't seevk_main.cpptaking a lock around it. The 10-open test you plan will not exercise this, so please also run a cold start with DLSS and the validation layers on, and watch for a queue sync error during the start-up screen.Smaller points are inline. CI: the two failures are
test_bake_*(andlibzstd.so.1missing on the Windows runner), nothing in this diff touches them; the Windows/Linux builds pass. No test covers the change, which is fair for a timing fix, but the log line gives a way to check it.@ -2416,0 +2427,4 @@std::thread([] {const auto t0 = std::chrono::steady_clock::now();dlss_probe();fsr4_probe();Since the
call_onceis consumed here, a call before the device exists would drop the probes for the rest of the run, and you'd silently be back to the old 3 s hitch at the menu's first open. It holds today (the device is made before the start-up screen), but it would be sturdier to set the flag only after the device check, e.g. a plain atomic exchange after the!dev.devicereturn.@ -2416,1 +2435,4 @@});}void startup_screen(const StartupView* view) {Nit: the thread is detached, and Hookshot leaves through
ExitProcess/exit()with the device alive (per the comment invk_fsr4.cpp), so a quit while NGX is still starting is the only window. Probably fine, but worth a thought if a user quits during the first seconds of the start-up screen.