fix(vk): on weak Intel laptops the shaders are prepared and the scene's passes draw within seconds, the pipeline cache is saved, and a Debug button sets the lightest rows #404
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 milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!404
Loading…
Reference in a new issue
No description provided.
Delete branch "Yeetbot90/Longshot:fix/igpu-weak-laptop"
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
On a weak Intel laptop (i3-1115G4, UHD Graphics, 2 cores / 4 threads, 16 GB) the build's shader preparation is stopped by its watchdog, so every start builds every shader in play, the scene's light and exposure passes are left out for minutes (the Deku Tree's dialogue drawn blown out), and the GPU device was lost in the Deku Tree's last cutscene with video memory over the driver's allowance. This lets the preparation finish, draws those passes within seconds, keeps integrated GPUs under their memory allowance, and adds a Debug button that sets the lightest rows at once.
What changed
The cause, from Unity's logs (build
nightly-130-0caf0618, which is main @0caf0618): Intel's Windows compiler builds compute pipelines one at a time (serial_builds_on), and with the optimizer on it took 0.3 s to 389.5 s for each of 37 dispatches, about 22 minutes on that one thread. The preparation's 300 s watchdog then stops it and leaveslongshot_prepare_skipped. In the cutscene the textures' pool held 9 blocks (1152 MB) made at the start that VMA keeps for the whole run, while the textures' budget had fallen to 720 MB, so the 97% rule could not give memory back.jobs_push_serial(fn, on_failure, first)ingpu/vk/vk_jobs.cpp/.hadds a front lane. The game's dispatches go there, ahead of the mesh fallback's model builds, in order among themselves. After each build the thread callspipeline_cache_between_builds().pipeline_cache_saveingpu/vk/vk_draw.cpp. A save put off on Intel's serial builds (thePcacheFetchlock against igvk64's crash invkGetPipelineCacheData) is now owed (pcache_save_owed).pipeline_cache_between_buildsruns it on the serial thread between two builds, the one moment no compute build is under way. The function's signature is unchanged (checks cut it out by its text).gpu/vk/vk_draw.cpp,gpu/vk/vk_shader.h. On Intel's serial path a dispatch's first build is without the optimizer (VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT, as the mesh fallback's builds already are).compute_optimizethen builds the optimized one on the back lane, and the dispatch binds it once made (Program::compute_optimized). The first pipeline stays for the session, because a recording may hold it.precompile_runandprecompile_warmingpu/vk/vk_draw.cpp, throughprecompile_compute_quick. On Intel's serial builds they take the optimized pipeline when the caches have it, and otherwise build the unoptimized one, so the preparation finishes within its 300 s. A program made this way owes its optimized build (Program::optimize_owed), which its first dispatch queues on the back lane. Programs that are never dispatched are never optimized.blocks_at_startingpu/vk/vram_compact.h, called fromgpu/vk/vk_vma.cpp. An integrated GPU now makes no texture blocks at the start, because its heap is the PC's RAM. Blocks are made as needed and given back, and the 97% rule applies. Dedicated cards keep the 15% of the heap made at the start (the ~170 msvkAllocateMemorymeasured on AMD's Windows driver).RX_VK_IMAGE_PREALLOCstill sets a number.low_vram_texture_mipsingpu/vk/vk_texture.cpp. It also counts an integrated GPU on a PC with 16 GB of RAM or less (system_ram_bytes()) as small, and it goes by Minimum's budgets (opts.budget == 1), not only the preset, because the button below leaves the preset on Custom with those budgets. On Minimum, decoded ASTC textures then keep at most 1024 texels: Unity's 1365x1365x90 arrays go from 53 MB to 13 MB. Render targets and depth images are untouched.gpu/vk/auto_settings.h. Auto on an integrated GPU with 4 threads or fewer sets Render resolution to 33% (RES_ULTRA_PERFORMANCE) instead of Minimum's 50%.gpu/vk/vk_menu.cpp,gpu/vk/vk_menu.h, Debug tab:intel_quick_computeasksintel_compiler_row, since Mesa's ANV on Linux ignores the flag). Off: one optimized build, as before.README.md(the smaller mips on integrated GPUs;longshot_prepare_skippedunder If something goes wrong),docs/development.md(RX_VK_COMPUTE_QUICK_FIRST).serial_builds_onexcept the memory blocks, the mips rule, the Auto rule and the button, which all need an integrated GPU. Rows a player set on Custom stay as they are; only Auto and the button change rows.Flags and settings
intel_quick_compute_builds)e072164e; every other GPURX_VK_COMPUTE_QUICK_FIRSTRX_VK_LOW_VRAM_MIPS=0turns it off, as before)RX_VK_IMAGE_PREALLOC=<n>still sets a number)Measurements
main:
0caf0618(2026-11-14)this PR: fix/igpu-weak-laptop @
922301bdSince measured:
e072164elimits the quick compute builds to Intel's Windows driver (review below); it changes nothing on the GPUs measured here, and the checks that readvk_menu.cppwere run again on it (64 passed,test_pad_layoutfailed as on main)Hardware: main's in-game column is Unity's laptop (i3-1115G4, Intel UHD Graphics, 16 GB, Windows,
nightly-130-0caf0618); the checks ran on this PC (Windows 11, llvm-mingw clang 20261104, Python 3)Scene: his play to the Deku Tree's last cutscene (two sets of five logs from 2026-11-14); the checks need no game
Method: lines counted by script from his ten
nightly-130-0caf0618logs; the PR's eight changed checks run against main's source and this PR's;tests/run_all.pyon both, run at the same timeHow to reproduce:
python -I -B tests/run_all.pyon each side; for main's source, copy this PR'stests/changes into a worktree at0caf0618and run the checks named below0caf0618922301bdSLOW compiletests/run_all.pyThe pipeline cache: in Unity's first set of logs, five starts each loaded 182 KB and one save was logged in all. In his newest set it grew from 0.6 MB to 77 MB over five starts, so saves did happen there. The owed save makes them happen between builds, not only when no build is under way.
Testing
Tested: On this PC (Windows 11, llvm-mingw clang 20261104, no Intel or integrated GPU), as in Measurements: the eight changed checks fail on main's source and pass here, and
tests/run_all.pyfails the same 10 on both sides (test_release,test_lift_cache,test_tested_configurations,test_oot_state_tap,test_spawn_emit,test_framegen_resources,test_pad_layout,test_bake_portability,test_module_ids,test_fpx_sticky: this PC's setup, none reads these files).vk_draw.cpp,vk_jobs.cpp,vk_menu.cpp,vk_programs.cpp,vk_texture.cppandvk_vma.cppsyntax-checked with llvm-mingw clang (-fms-extensions, the build's include paths): clean. The cause was read from Unity's tennightly-130-0caf0618logs, counted by script.Not tested: This PR in the game, on any GPU: this PC has no Intel or integrated GPU, so neither the preparation finishing, the cutscene staying within the allowance, nor the menu rows' look were seen. Whether Intel's Windows driver honours
DISABLE_OPTIMIZATIONfor these shaders and how much faster that build is. The GPU cost of the unoptimized passes until their optimized builds arrive. A Linux build (host code is portable C++; only the Windows toolchain was run). The C++ fixtures under the release toolchain.Needs other testers:
cache/longshot_prepare_skipped, rebuild, press Set up for a weak laptop, play to the Deku Tree's last cutscene; expecting the preparation to finish, noSLOW compilein play, no device loss (request to open)Screenshots
Nothing captured: the two new rows show only on Intel or integrated graphics, and this PC has neither. Unity's screenshots of main are described under Why.
Risk and rollback
RX_VK_COMPUTE_QUICK_FIRST=0) goes back to one optimized build.vkAllocateMemoryof 128 MB when textures grow, not measured on Intel's or AMD's integrated drivers.RX_VK_IMAGE_PREALLOC=9restores the old count.RX_VK_LOW_VRAM_MIPS=0turns it off.longshot_prepare_skippedkeeps skipping until it is rebuilt or the file deleted (README).Reviewer notes
Start with
precompile_compute_quickandcompute_optimizeingpu/vk/vk_draw.cpp, thenblocks_at_startingpu/vk/vram_compact.h. Overlaps: #288 changes the line that callslow_vram_texture_mips(not its body); #50 and #284 rework howtests/test_blocks_at_start.pyfinds its source, so whichever lands second merges that test; #27 movestest_low_vram_texture_mips.pyandtest_precompile_compute_guard.pyto a shared source cutter. Open questions: should the quick compute builds go to every GPU on serial builds (RX_VK_COMPUTE_SERIAL=1)? Should Auto keep 50% and leave 33% to the button?Issues
See the Deku Tree crash and shader-stutter reports from Unity's laptop (logs above; no issue on the tracker yet).
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.mainand passing here.tests/that reads changed source updated in this PR, not weakened.WIP: fix(vk): on weak Intel laptops the scene's passes draw within seconds, the pipeline cache is saved, and a Debug button sets the lightest rowsto fix(vk): on weak Intel laptops the shaders are prepared and the scene's passes draw within seconds, the pipeline cache is saved, and a Debug button sets the lightest rowsI checked this PR against Mesa's Intel driver on Linux (Iris Xe, i9-13900H, Mesa 26.2.4). serial_builds_on() goes by vendorID == 0x8086, and intel_quick defaults to 1 even where the row is hidden, so the quick compute builds also run on Linux Intel, not only on Windows as the description says. On Mesa they don't do anything: ANV ignores VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT. Building compute shader 0a9b6e3892907675 alone (held to 32 lanes, shader cache off) gave the same instruction count, cycles, spills and compile time with and without the flag (18.4–18.9 s, two runs each), and the optimized rebuild through the same pipeline cache took 0.0 s. So on Linux it just adds a second pipeline handle per dispatch, which is harmless but doesn't help. It might be worth limiting it to Intel's Windows driver (dev.driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, or #ifdef _WIN32 as the row does), so the row and the code agree. On Linux the slow part is ANV's register allocation spilling at SIMD32, not its optimizer. I have fixes for that on a branch: compute-pipeline pinning on Mesa Intel, a compile gate weighted by memory, a smaller preparation plan, a lower spilling rate and a lighter mesh fallback epilogue. I'll open a PR for them once I've finished testing on this laptop. Your branch merges cleanly with mine, and the checks we both touch pass on the merge.
ok
Thanks, that's right: the row was Windows-only but the code wasn't.
e072164emakesintel_quick_compute()also askintel_compiler_row()(Intel graphics on Windows, the row's own rule), so on Linux with ANV the dispatches get the one optimized build, as before.test_intel_quick_compute.pychecks it, anddocs/development.mdnow says Windows only. Good to hear the branches merge cleanly; I'll look out for your ANV spilling PR.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.