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

Open
Yeetbot90 wants to merge 9 commits from Yeetbot90/Longshot:fix/igpu-weak-laptop into main
Contributor

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 leaves longshot_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: jobs_push_serial(fn, on_failure, first) in gpu/vk/vk_jobs.cpp / .h adds 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 calls pipeline_cache_between_builds().
  • pipeline cache: pipeline_cache_save in gpu/vk/vk_draw.cpp. A save put off on Intel's serial builds (the PcacheFetch lock against igvk64's crash in vkGetPipelineCacheData) is now owed (pcache_save_owed). pipeline_cache_between_builds runs 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).
  • dispatch builds: 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_optimize then 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.
  • preparation and precompile: precompile_run and precompile_warm in gpu/vk/vk_draw.cpp, through precompile_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.
  • memory: blocks_at_start in gpu/vk/vram_compact.h, called from gpu/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 ms vkAllocateMemory measured on AMD's Windows driver). RX_VK_IMAGE_PREALLOC still sets a number.
  • textures: low_vram_texture_mips in gpu/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.
  • Auto: 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%.
  • menu: gpu/vk/vk_menu.cpp, gpu/vk/vk_menu.h, Debug tab:
    • Intel quick compute builds (On by default; shown, and run, only for Intel graphics on Windows, like the Intel shader compiles row: intel_quick_compute asks intel_compiler_row, since Mesa's ANV on Linux ignores the flag). Off: one optimized build, as before.
    • Set up for a weak laptop, a button shown only on integrated graphics. It sets Minimum's rows and memory budgets, Render resolution 33% with the game's own upscaler, plain window scale, no sharpening, no frame generation, Intel's shaders one at a time, and quick compute builds. The preset then reads Custom. The rows that need a restart ask for one at close, as when set by hand.
  • docs: README.md (the smaller mips on integrated GPUs; longshot_prepare_skipped under If something goes wrong), docs/development.md (RX_VK_COMPUTE_QUICK_FIRST).
  • Deliberately unchanged: other GPUs. Nothing here runs without serial_builds_on except 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

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Debug row "Intel quick compute builds" (ini intel_quick_compute_builds) Intel's serial compute builds on Windows: an unoptimized pipeline first, the optimized one on the back lane On (row shown, and the code run, on Intel Windows only) On: the alternative is a pass missing for minutes Intel iGPUs on Windows (UHD, Iris Xe) Linux with Mesa's ANV, which ignores the flag (thomas-montano's Iris Xe run): off there since e072164e; every other GPU Intel Arc; any Intel device in play
RX_VK_COMPUTE_QUICK_FIRST Overrides that row (0 off, 1 on) Unset (the row decides) Leave unset; for A/B tests as the row as the row as the row
Debug button "Set up for a weak laptop" Sets the lightest rows at once (listed under What changed) Not pressed (button) Offer it to iGPU players with stutter Integrated GPUs with 4 threads or fewer Dedicated cards: the button is hidden Every integrated GPU in play
Auto on an integrated GPU with 4 threads or fewer Render resolution 33% instead of 50% On with Auto On: 50% measured at 121-197 ms per frame on Unity's laptop i3-class iGPU laptops 8+ thread iGPUs: unchanged (50%) In play
Integrated GPU, 16 GB RAM or less, Minimum's budgets Smaller ASTC mips (RX_VK_LOW_VRAM_MIPS=0 turns it off, as before) On On iGPUs sharing 16 GB or less 32 GB PCs, dedicated cards: unchanged In play
Integrated GPU: no texture blocks at the start (RX_VK_IMAGE_PREALLOC=<n> still sets a number) Blocks made as needed and given back On On iGPUs: 1152 MB less held on Unity's laptop Dedicated cards: unchanged In play

Measurements

main: 0caf0618 (2026-11-14)
this PR: fix/igpu-weak-laptop @ 922301bd
Since measured: e072164e limits the quick compute builds to Intel's Windows driver (review below); it changes nothing on the GPUs measured here, and the checks that read vk_menu.cpp were run again on it (64 passed, test_pad_layout failed 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-0caf0618 logs; the PR's eight changed checks run against main's source and this PR's; tests/run_all.py on both, run at the same time
How to reproduce: python -I -B tests/run_all.py on each side; for main's source, copy this PR's tests/ changes into a worktree at 0caf0618 and run the checks named below

main @ 0caf0618 this PR @ 922301bd
Shader preparation at the build (Unity's logs) skipped in 10 of 10 logs not run on his laptop yet (Testing)
Slowest compute build, optimizer on (Unity's logs) 389.5 s; 37 SLOW compile first build unoptimized (test_pipeline_state_computes)
Texture blocks made at the start, his integrated GPU (8061 MB heap) 9 (1152 MB), kept all run 0 (test_blocks_at_start)
1365x1365x90 ASTC array after the weak laptop button (Custom, Minimum's budgets) 53 MB, full size 13 MB, 682x682 (test_low_vram_texture_mips)
Auto's render resolution, integrated GPU, 4 threads 50% 33% (test_auto_settings)
The PR's 8 changed checks 8 fail 8 pass
tests/run_all.py 509 passed, 10 failed, 42 skipped 510 passed, 10 failed, 42 skipped (the same 10)
[hos host] longshot nightly-130-0caf0618 (source 65722f5b)
[hos host] vk: the shaders' preparation was skipped at the build: left to when each is first drawn
[hos host] vk: compute pipeline of 383a566958350efe: SLOW compile, 389499 ms (on a worker)
[hos Presentation Thread] vk: over the driver's video-memory allowance (6.6 of 6.5 GB)
[hos Presentation Thread] vk: image 1119x1119x1 x1 levels 1 format 126 (NVN 0x34) not made
[hos Presentation Thread] vk: submit 257558 failed (-4)
[hos Presentation Thread] vk: FATAL: the GPU device was lost (VK_ERROR_DEVICE_LOST): ...

main @ 0caf0618, with this PR's checks:
test_intel_quick_compute       exit 1: FAIL: the quick build is not limited to the serial builds and the row
test_pipeline_cache_save       exit 1: Ran 15 tests / FAILED (failures=1, skipped=1)
test_pcache_fetch_lock         exit 1: AssertionError: a save put off is not owed to the serial builds' thread
test_auto_settings             exit 1: test_auto_settings.cpp:23:28: error: use of undeclared identifier 'RES_ULTRA_PERFORMANCE'
test_low_vram_texture_mips     exit 1: PASS custom-preset / FAIL:107 x.skip == (uint32_t)skip   (the next case: custom-with-minimums-budgets)
test_blocks_at_start           exit 1: vk_vma.cpp: blocks_at_start() no longer has: vram_compact::blocks_at_start(heap, kImageBlock, holds_textures, dev.props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
test_pipeline_state_computes   exit 1: ValueError: substring not found (no precompile_compute_quick)
test_precompile_compute_guard  exit 1: ValueError: substring not found (no precompile_compute_quick)

this PR @ 922301bd:
test_intel_quick_compute       exit 0: PASS: Intel's serial compute builds draw without the optimizer first, and the weak laptop button sets the lightest rows
test_pipeline_cache_save       exit 0: Ran 15 tests / OK (skipped=1)
test_pcache_fetch_lock         exit 0: PASS: on Intel a pipeline cache's data is fetched with no build under way, and the background save does not stall builds
test_auto_settings             exit 0: auto settings: all checks passed
test_low_vram_texture_mips     exit 0: PASS 41 mip-policy configurations
test_blocks_at_start           exit 0: PASS
test_pipeline_state_computes   exit 0: PASS: the precompile's compute arm asks the caches first ...; on Intel's one-at-a-time builds it compiles without the optimizer and owes the optimized build
test_precompile_compute_guard  exit 0: PASS: extracted wrapper/compute arm; modeled thread join only

run_all.py: main 509 passed, 10 failed, 42 skipped; this PR 510 passed, 10 failed, 42 skipped

The 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.py fails 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.cpp and vk_vma.cpp syntax-checked with llvm-mingw clang (-fms-extensions, the build's include paths): clean. The cause was read from Unity's ten nightly-130-0caf0618 logs, 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_OPTIMIZATION for 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:

  • Intel UHD laptop on Windows (Unity's i3-1115G4): delete 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, no SLOW compile in play, no device loss (request to open)
  • AMD integrated GPU (a Radeon 780M laptop): Auto and the button; expecting no new stutter from blocks made in play (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

  • Unoptimized scene passes cost more GPU time until their optimized builds are bound; on a GPU at 120-200 ms a frame that may show. The row (or RX_VK_COMPUTE_QUICK_FIRST=0) goes back to one optimized build.
  • Each dispatch built twice adds a pipeline per dispatch to the cache and keeps the unoptimized one for the session.
  • Integrated GPUs make texture blocks in play again: a vkAllocateMemory of 128 MB when textures grow, not measured on Intel's or AMD's integrated drivers. RX_VK_IMAGE_PREALLOC=9 restores the old count.
  • Smaller mips on integrated GPUs with 16 GB or less on Minimum: textures over 1024 texels are blurrier up close. RX_VK_LOW_VRAM_MIPS=0 turns it off.
  • The owed save makes the next build wait for one cache fetch and write (about 100 ms at 100 MB).
  • A folder that already has longshot_prepare_skipped keeps skipping until it is rebuilt or the file deleted (README).
  • Reverting the PR restores main's behaviour; nothing it writes is read by main differently.

Reviewer notes

Start with precompile_compute_quick and compute_optimize in gpu/vk/vk_draw.cpp, then blocks_at_start in gpu/vk/vram_compact.h. Overlaps: #288 changes the line that calls low_vram_texture_mips (not its body); #50 and #284 rework how tests/test_blocks_at_start.py finds its source, so whichever lands second merges that test; #27 moves test_low_vram_texture_mips.py and test_precompile_compute_guard.py to 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

  • 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. (Game-free checks, deterministic, both sides on this PC; main's in-game numbers are from Unity's logs, this PR's in-game run is owed: Testing.)
  • 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.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.
## 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 leaves `longshot_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: `jobs_push_serial(fn, on_failure, first)` in `gpu/vk/vk_jobs.cpp` / `.h` adds 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 calls `pipeline_cache_between_builds()`. - pipeline cache: `pipeline_cache_save` in `gpu/vk/vk_draw.cpp`. A save put off on Intel's serial builds (the `PcacheFetch` lock against igvk64's crash in `vkGetPipelineCacheData`) is now **owed** (`pcache_save_owed`). `pipeline_cache_between_builds` runs 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). - dispatch builds: `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_optimize` then 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. - preparation and precompile: `precompile_run` and `precompile_warm` in `gpu/vk/vk_draw.cpp`, through `precompile_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. - memory: `blocks_at_start` in `gpu/vk/vram_compact.h`, called from `gpu/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 ms `vkAllocateMemory` measured on AMD's Windows driver). `RX_VK_IMAGE_PREALLOC` still sets a number. - textures: `low_vram_texture_mips` in `gpu/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. - Auto: `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%. - menu: `gpu/vk/vk_menu.cpp`, `gpu/vk/vk_menu.h`, Debug tab: - **Intel quick compute builds** (On by default; shown, and run, only for Intel graphics on Windows, like the Intel shader compiles row: `intel_quick_compute` asks `intel_compiler_row`, since Mesa's ANV on Linux ignores the flag). Off: one optimized build, as before. - **Set up for a weak laptop**, a button shown only on integrated graphics. It sets Minimum's rows and memory budgets, Render resolution 33% with the game's own upscaler, plain window scale, no sharpening, no frame generation, Intel's shaders one at a time, and quick compute builds. The preset then reads Custom. The rows that need a restart ask for one at close, as when set by hand. - docs: `README.md` (the smaller mips on integrated GPUs; `longshot_prepare_skipped` under *If something goes wrong*), `docs/development.md` (`RX_VK_COMPUTE_QUICK_FIRST`). - Deliberately unchanged: other GPUs. Nothing here runs without `serial_builds_on` except 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 | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Debug row "Intel quick compute builds" (ini `intel_quick_compute_builds`) | Intel's serial compute builds on Windows: an unoptimized pipeline first, the optimized one on the back lane | On (row shown, and the code run, on Intel Windows only) | On: the alternative is a pass missing for minutes | Intel iGPUs on Windows (UHD, Iris Xe) | Linux with Mesa's ANV, which ignores the flag (thomas-montano's Iris Xe run): off there since e072164e; every other GPU | Intel Arc; any Intel device in play | | `RX_VK_COMPUTE_QUICK_FIRST` | Overrides that row (0 off, 1 on) | Unset (the row decides) | Leave unset; for A/B tests | as the row | as the row | as the row | | Debug button "Set up for a weak laptop" | Sets the lightest rows at once (listed under What changed) | Not pressed (button) | Offer it to iGPU players with stutter | Integrated GPUs with 4 threads or fewer | Dedicated cards: the button is hidden | Every integrated GPU in play | | Auto on an integrated GPU with 4 threads or fewer | Render resolution 33% instead of 50% | On with Auto | On: 50% measured at 121-197 ms per frame on Unity's laptop | i3-class iGPU laptops | 8+ thread iGPUs: unchanged (50%) | In play | | Integrated GPU, 16 GB RAM or less, Minimum's budgets | Smaller ASTC mips (`RX_VK_LOW_VRAM_MIPS=0` turns it off, as before) | On | On | iGPUs sharing 16 GB or less | 32 GB PCs, dedicated cards: unchanged | In play | | Integrated GPU: no texture blocks at the start (`RX_VK_IMAGE_PREALLOC=<n>` still sets a number) | Blocks made as needed and given back | On | On | iGPUs: 1152 MB less held on Unity's laptop | Dedicated cards: unchanged | In play | ## Measurements main: 0caf0618 (2026-11-14) this PR: fix/igpu-weak-laptop @ 922301bd Since measured: e072164e limits the quick compute builds to Intel's Windows driver (review below); it changes nothing on the GPUs measured here, and the checks that read `vk_menu.cpp` were run again on it (64 passed, `test_pad_layout` failed 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-0caf0618` logs; the PR's eight changed checks run against main's source and this PR's; `tests/run_all.py` on both, run at the same time How to reproduce: `python -I -B tests/run_all.py` on each side; for main's source, copy this PR's `tests/` changes into a worktree at 0caf0618 and run the checks named below | | main @ 0caf0618 | this PR @ 922301bd | |---|---|---| | Shader preparation at the build (Unity's logs) | skipped in 10 of 10 logs | not run on his laptop yet (Testing) | | Slowest compute build, optimizer on (Unity's logs) | 389.5 s; 37 `SLOW compile` | first build unoptimized (test_pipeline_state_computes) | | Texture blocks made at the start, his integrated GPU (8061 MB heap) | 9 (1152 MB), kept all run | 0 (test_blocks_at_start) | | 1365x1365x90 ASTC array after the weak laptop button (Custom, Minimum's budgets) | 53 MB, full size | 13 MB, 682x682 (test_low_vram_texture_mips) | | Auto's render resolution, integrated GPU, 4 threads | 50% | 33% (test_auto_settings) | | The PR's 8 changed checks | 8 fail | 8 pass | | `tests/run_all.py` | 509 passed, 10 failed, 42 skipped | 510 passed, 10 failed, 42 skipped (the same 10) | ``` [hos host] longshot nightly-130-0caf0618 (source 65722f5b) [hos host] vk: the shaders' preparation was skipped at the build: left to when each is first drawn [hos host] vk: compute pipeline of 383a566958350efe: SLOW compile, 389499 ms (on a worker) [hos Presentation Thread] vk: over the driver's video-memory allowance (6.6 of 6.5 GB) [hos Presentation Thread] vk: image 1119x1119x1 x1 levels 1 format 126 (NVN 0x34) not made [hos Presentation Thread] vk: submit 257558 failed (-4) [hos Presentation Thread] vk: FATAL: the GPU device was lost (VK_ERROR_DEVICE_LOST): ... main @ 0caf0618, with this PR's checks: test_intel_quick_compute exit 1: FAIL: the quick build is not limited to the serial builds and the row test_pipeline_cache_save exit 1: Ran 15 tests / FAILED (failures=1, skipped=1) test_pcache_fetch_lock exit 1: AssertionError: a save put off is not owed to the serial builds' thread test_auto_settings exit 1: test_auto_settings.cpp:23:28: error: use of undeclared identifier 'RES_ULTRA_PERFORMANCE' test_low_vram_texture_mips exit 1: PASS custom-preset / FAIL:107 x.skip == (uint32_t)skip (the next case: custom-with-minimums-budgets) test_blocks_at_start exit 1: vk_vma.cpp: blocks_at_start() no longer has: vram_compact::blocks_at_start(heap, kImageBlock, holds_textures, dev.props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) test_pipeline_state_computes exit 1: ValueError: substring not found (no precompile_compute_quick) test_precompile_compute_guard exit 1: ValueError: substring not found (no precompile_compute_quick) this PR @ 922301bd: test_intel_quick_compute exit 0: PASS: Intel's serial compute builds draw without the optimizer first, and the weak laptop button sets the lightest rows test_pipeline_cache_save exit 0: Ran 15 tests / OK (skipped=1) test_pcache_fetch_lock exit 0: PASS: on Intel a pipeline cache's data is fetched with no build under way, and the background save does not stall builds test_auto_settings exit 0: auto settings: all checks passed test_low_vram_texture_mips exit 0: PASS 41 mip-policy configurations test_blocks_at_start exit 0: PASS test_pipeline_state_computes exit 0: PASS: the precompile's compute arm asks the caches first ...; on Intel's one-at-a-time builds it compiles without the optimizer and owes the optimized build test_precompile_compute_guard exit 0: PASS: extracted wrapper/compute arm; modeled thread join only run_all.py: main 509 passed, 10 failed, 42 skipped; this PR 510 passed, 10 failed, 42 skipped ``` The 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.py` fails 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.cpp` and `vk_vma.cpp` syntax-checked with llvm-mingw clang (`-fms-extensions`, the build's include paths): clean. The cause was read from Unity's ten `nightly-130-0caf0618` logs, 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_OPTIMIZATION` for 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:** - Intel UHD laptop on Windows (Unity's i3-1115G4): delete `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, no `SLOW compile` in play, no device loss (request to open) - AMD integrated GPU (a Radeon 780M laptop): Auto and the button; expecting no new stutter from blocks made in play (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 - Unoptimized scene passes cost more GPU time until their optimized builds are bound; on a GPU at 120-200 ms a frame that may show. The row (or `RX_VK_COMPUTE_QUICK_FIRST=0`) goes back to one optimized build. - Each dispatch built twice adds a pipeline per dispatch to the cache and keeps the unoptimized one for the session. - Integrated GPUs make texture blocks in play again: a `vkAllocateMemory` of 128 MB when textures grow, not measured on Intel's or AMD's integrated drivers. `RX_VK_IMAGE_PREALLOC=9` restores the old count. - Smaller mips on integrated GPUs with 16 GB or less on Minimum: textures over 1024 texels are blurrier up close. `RX_VK_LOW_VRAM_MIPS=0` turns it off. - The owed save makes the next build wait for one cache fetch and write (about 100 ms at 100 MB). - A folder that already has `longshot_prepare_skipped` keeps skipping until it is rebuilt or the file deleted (README). - Reverting the PR restores main's behaviour; nothing it writes is read by main differently. ## Reviewer notes Start with `precompile_compute_quick` and `compute_optimize` in `gpu/vk/vk_draw.cpp`, then `blocks_at_start` in `gpu/vk/vram_compact.h`. Overlaps: #288 changes the line that calls `low_vram_texture_mips` (not its body); #50 and #284 rework how `tests/test_blocks_at_start.py` finds its source, so whichever lands second merges that test; #27 moves `test_low_vram_texture_mips.py` and `test_precompile_compute_guard.py` to 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 - [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. (Game-free checks, deterministic, both sides on this PC; main's in-game numbers are from Unity's logs, this PR's in-game run is owed: Testing.) - [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] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated.
fix(intel): weak iGPU laptops: the scene's passes first and unoptimized at once, the pipeline cache saved between builds, 33% on 4 threads, a Debug button
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 3s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
9afadc4e3e
On an i3-1115G4's UHD Graphics (2 cores, 4 threads, 16 GB) the game's 37 dispatches took 0.3 s to 6.5 min each with Intel's optimizer, 22 minutes on the one serial thread behind the mesh fallback's builds; the Deku Tree's dialogue was drawn blown out meanwhile, and the pipeline cache was never saved (182 KB at every start).

- dispatches' builds go first in the serial queue; on Intel's serial builds the first is made without the optimizer and the optimized one is bound once built (Debug: Intel quick compute builds, RX_VK_COMPUTE_QUICK_FIRST)
- a pipeline cache save put off for builds under way is owed and runs on the serial thread between two builds
- Auto: an integrated GPU with 4 threads or fewer starts at 33%
- Debug: Set up for a weak laptop (integrated graphics), the lightest rows at once

Co-authored-by: Cursor <[email protected]>
fix(vk): Minimum's smaller texture mips on integrated GPUs with 16 GB of RAM or less
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
c39e9b70be
An integrated GPU's VRAM budget is a share of the system's RAM: Unity's i3-1115G4 (UHD Graphics, 16 GB) was allowed
7.4 GB, past the 4.5 GiB that turns on Minimum's 1024 limit for decoded ASTC textures, while the game, 2 GB of textures
and the driver held 12-13 GB of private memory and Windows paged the game out. On Minimum, an integrated GPU with 16 GB
of RAM or less now counts as small whatever the driver allows.

Co-authored-by: Cursor <[email protected]>
fix(intel): the shader preparation and a start's precompile build Intel's compute pipelines without the optimizer first
Some checks failed
PR description / Description follows the template (pull_request_target) Failing after 3s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
81a7775d72
With the optimizer, one of the game's compute pipelines took Intel's compiler up to 389.5 s on a UHD Graphics
(i3-1115G4): past the build's shader preparation's 300 s with nothing finished, so the preparation was stopped and left
longshot_prepare_skipped, and every later start built each shader when first drawn (all of Unity's runs: "the shaders'
preparation was skipped at the build").

On Intel's one-at-a-time builds with the Intel quick compute builds row on, precompile_run and precompile_warm now ask
the caches for the optimized pipeline first and otherwise build the one a dispatch's first build asks for, without the
optimizer. A program made so owes its optimized build to its first dispatch, which queues it behind the builds asked for
first: a first start makes every kept compute program's (323 dispatched on that laptop), most never dispatched.

Co-authored-by: Cursor <[email protected]>
Yeetbot90 changed title from 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 rows to 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 2026-11-14 10:57:23 +00:00
fix(vk): integrated GPUs keep no texture blocks made at the start, and Custom after the weak laptop button keeps the smaller mips
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 12s
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
922301bda0
Unity's laptop (UHD Graphics, 16 GB) lost the device in the Deku Tree's last cutscene: at 6.6 GB of the 6.5 the driver
allowed, a 1119 x 1119 depth image was not made, and the next submit failed with VK_ERROR_DEVICE_LOST. The textures' pool
started with 15% of the reported heap, nine 128 MB blocks (1152 MB) of the PC's RAM that VMA keeps for the whole run, while
the textures' budget had fallen to 720 MB; and the pool down to those blocks (kept_only) kept the 97% rule from squeezing.
On an integrated GPU no blocks are made at the start now: they are made as needed and given back, and the 97% rule applies.
RX_VK_IMAGE_PREALLOC still sets a number.

low_vram_texture_mips went by the Quality preset, and the Debug tab's Set up for a weak laptop leaves it on Custom with
Minimum's budgets: it now goes by those budgets (opts.budget 1) too.

Co-authored-by: Cursor <[email protected]>
First-time contributor

I 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.

I 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.
Author
Contributor

ok

ok
fix(intel): the quick compute builds only on Intel's Windows driver, where their row shows
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
e072164e3d
serial_builds_on() goes by Intel's vendor ID and the row defaulted to on where it is hidden, so the quick builds also ran
on Linux with Mesa's ANV. ANV ignores VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT: the same instructions, cycles, spills
and compile time with and without it on an Iris Xe (Mesa 26.2.4, reported on the pull request), so there each dispatch
only gained a second pipeline handle. intel_quick_compute() now also asks intel_compiler_row(), the row's own rule
(Intel graphics on Windows), so the row and the code agree.

Co-Authored-By: Cursor <[email protected]>
Author
Contributor

Thanks, that's right: the row was Windows-only but the code wasn't. e072164e makes intel_quick_compute() also ask intel_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.py checks it, and docs/development.md now says Windows only. Good to hear the branches merge cleanly; I'll look out for your ANV spilling PR.

Thanks, that's right: the row was Windows-only but the code wasn't. e072164e makes `intel_quick_compute()` also ask `intel_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.py` checks it, and `docs/development.md` now says Windows only. Good to hear the branches merge cleanly; I'll look out for your ANV spilling PR.
Merge branch 'main' into fix/igpu-weak-laptop
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 5s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled
af5f76576b
Merge branch 'main' into fix/igpu-weak-laptop
Some checks failed
Website / Website on Cloudflare (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 10s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
0c41ff5fd6
Merge branch 'main' into fix/igpu-weak-laptop
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 15s
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
fd8698c101
Merge branch 'main' into fix/igpu-weak-laptop
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 5s
33f63677aa
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 5s
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
Some workflows are waiting to be reviewed.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'fix/igpu-weak-laptop:Yeetbot90-fix/igpu-weak-laptop'
git switch 'Yeetbot90-fix/igpu-weak-laptop'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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!404
No description provided.