WIP: fix(vk): a slow movie shows its pictures, and a fault in Intel's Windows compiler leaves that shader out #252

Draft
Yeetbot90 wants to merge 19 commits from Yeetbot90/Longshot:fix/windows-movie-and-intel-compiler into main
First-time contributor

Why

This fix is for Unity's laptop. Every change below comes from his two logs and the hardware they report, so that Longshot runs on that laptop:

Unity's laptop (from his logs)
GPU Intel(R) UHD Graphics, integrated, Vulkan 1.4, driver 101.7088, 8061 MB shared
CPU 4 logical processors (the game reserves 2 cores); 11th Gen Core i3-1115G4 in the v3.0.0-rc.3 bug report
RAM 16,122 MB, 16,348 MB swap
Screen 1920x1080 at 60 Hz, SDR
Settings Auto (this PC): Minimum, the game's own upscaler

What the logs show on it:

  1. The game closes in Intel's driver. An access violation (0xc0000005) at igvk64.dll+0x14d102, read at 0x170. It happened in 5 of his 7 v3.0.0-rc.3 runs, all in Kokiri Forest, with the same backtrace: igvk64.dll+0x14d102 +0x134aaf +0x7f23a +0x322ef, then longshot_vk.dll+0x20ccbc, then +0x22375d, then the thread's start.
    • Mapped with nightly-70's longshot_vk.dll (dd02c6cc, whose gpu/vk is identical to v3.0.0-rc.3's 0c74253d): +0x22375d is the std::thread started by pipeline_cache_save, and +0x20ccbc returns from pipeline_cache_save(bool)::$_0 after callq *(%rdi), which is vkGetPipelineCacheData(dev.device, pcache, &n, data), right after PipelineCacheFile::writable(pcache_path, n).
    • So it is the background save copying the pipeline cache while other threads build pipelines into it, as #190 found on Arc. This GPU writes no play files (play_cache needs pipelineCreationCacheControl), so every pipeline built in play goes into that same cache.
  2. Shaders are not ready in play. Every log, from v3.0.0-rc.1 to all 7 runs of rc.3, says the shaders' preparation was skipped at the build. The builder writes that marker only when its preparation run stopped with "the GPU driver stopped responding", most likely the same driver problem during the build's own compiles. Every start since then compiles each shader when it is first drawn: 15 pipelines took 8.5 s, and 312 took 203 s in the older log.
  3. The opening movie loses its pictures. A slow decode on this CPU skipped most pictures to catch up with the sound.
  4. The title and the opening movie run at about 35 fps of 60 (v3.0.0-rc.1). On 76 frames the game's thread waited 14 to 24 ms in a submit's memory sync. dav1d, the movie decoder, ran one thread per logical processor, which is all 4 on this CPU, beside the game's own threads.

The Intel compiler and movie fixes are ported from https://github.com/NotRexed/Hookshot/pull/2849, without its updater change. Updated for HumanBean's review: see the reply below the review.

What changed

  • Intel's driver, problem 1. IntelDriverGate in gpu/vk/vk_internal.h lets one thread at a time into Intel's compiler on Windows. That covers the game's shaders, every compute pipeline of the renderer's own, and now vkGetPipelineCacheData too (pcache_data in vk_draw.cpp: all six reads). Other vendors, and Intel on Linux, are not held.

    • A create that compiles nothing (FAIL_ON_PIPELINE_COMPILE_REQUIRED: a draw's or a dispatch's ask) only tries the lock. While a worker compiles, it answers VK_PIPELINE_COMPILE_REQUIRED (cold), so the replay thread never waits behind a compile. On Intel a dispatch's module, for a program read from the cache without its code, is made on the worker, not on the replay thread.
    • A fault inside the driver (__try/__except) leaves that shader out. A fault making a shader module is now written to longshot_driver_faults.txt, as pipeline faults already were, so later starts on the same driver leave that program out (make_module, driver_faulted_module).
  • A row for a low-core Intel CPU. The Debug tab's Intel shader compiles row (Developer section, Intel graphics on Windows only):

    • One at a time: the default, and the safe choice on a CPU with 4 cores or fewer, like Unity's.
    • Side by side: faster builds on many cores, but the driver can crash the game.

    It applies after a restart and is saved as intel_shader_compiles=. RX_VK_NO_INTEL_SERIAL=1 is Side by side for one run.

  • The movie, problem 3. host/nn_video.c:

    • Every acquire waits about 100 ms, as on main. The 500 ms first wait is gone: decode_pending() has already decoded what was submitted, so the wait never showed the first picture (the review's item 2).
    • Catching up uses the recent pictures' decode time (recent_ns, about the last 8) instead of the movie's mean, which a slow first decode held high.
    • It decodes ahead at most one picture's time per acquire.
    • A decoder slower than the movie shows the late picture rather than decoding one only to drop it.
  • The movie decoder's threads, problem 4. host/dav1d_av1.c: with 4 logical processors or fewer, dav1d decodes on 2 threads; above 4, it keeps its own count. HOS_DAV1D_THREADS=<n> still sets it.

  • Tests.

    • test_intel_compiler_gate.py: the gate, the try-lock for asks, the dispatch's module on the worker, the fault record, pcache_data, the row, and the 8 compute sources.
    • test_video_catchup.py: a slow first decode no longer turns the catch-up off.
    • test_dav1d_av1.py: the thread rule.
    • Updated for the new functions: test_vcore_video_acquire.py, test_program_cache_one_variant.py, test_damage_debug_menu.py, and the program-cache and pipeline-cache C++ stubs.
  • Docs. The README covers this fix in every section it touches:

    • Project status: the Intel row, and a new row for movies on a slow CPU.
    • What you need: a "below the minimum" note for Unity's kind of laptop, also in the website's copy (website/src/content/docs/requirements.mdx).
    • Compile shaders: what longshot_prepare_skipped does.
    • If something goes wrong: rows for the Intel crash, the skipped preparation and the movie, and a new Intel laptops section with Unity's specs, what to set and what to send.
    • In-game menu: the Intel shader compiles row in the settings list.
    • Switches: the movie and Intel paragraphs.
    • docs/development.md has the switches.

How this relates to other Intel work

  • #190 wraps the same functions in a shared lock against vkGetPipelineCacheData. On Windows Intel this pull request now takes Intel's gate around that fetch too, which covers the same crash for every build that holds the gate. If both land, the lock order must be IntelDriverGate outside, #190's shared lock inside, in every function. That way a builder never waits for the gate while it holds the shared side. Glad to rebase on #190, or to drop pcache_data if #190 lands first.
  • RX_VK_COMPUTE_SERIAL on main sends the dispatch's compute pipeline jobs to one serial queue on Intel (issue 496). The gate is lower down: it orders every entry into Intel's compiler, from any thread, compute or graphics. The serial queue still keeps compute jobs from piling up behind each other. The two do not wait on each other.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Intel shader compiles row One at a time or Side by side into Intel's compiler One at a time One at a time on 4 cores or fewer Windows Intel (UHD, Arc) NVIDIA, AMD, Intel on Linux (row hidden) Unity's laptop, any Intel on Windows
RX_VK_NO_INTEL_SERIAL=1 Side by side for one run off keep off measuring compile speed
HOS_DAV1D_THREADS=<n> The movie decoder's thread count 2 with 4 or fewer logical processors, else dav1d's own leave unset setting the count by hand Unity's laptop
HOS_VIDEO_NO_CATCHUP=1 A movie skips no pictures behind its sound off keep off measuring decode speed
HOS_VIDEO_ACQUIRE_TRIES=1 The movie waits by 50 sleeps of 2 ms off (by the clock) keep off comparing with the old wait

Measurements

No measurement of main against this pull request yet: it needs Unity's laptop.

  • Unity's logs, before the fix: the crash in igvk64.dll (5 of 7 rc.3 runs, all in the background pipeline-cache save), the preparation skipped, about 35 fps on the title (30–50 fps in the rc.3 runs), and 14–24 ms memory-sync waits. None of these logs is a run of this branch.
  • One AMD play of the Hookshot build of the same fix (RX 9070 XT, Ryzen 9 7900X, Windows 11). Both movies played, 59.5 fps in the 3D scene, no crash. Intel's gate was never entered there.

Testing

Tested: python -I -B tests/run_all.py on Windows 11 at 2bc07a1d, with main d906c8f4 merged in, using llvm-mingw 20261104: 464 passed, 4 failed, 67 skipped. The game was not built.

  • The 4 failures are nx2/test_nup_paths, test_check_third_party, test_release and test_menu_i18n. They fail on main too, and #255 fixes them.
  • test_dav1d_av1 was skipped: there is no dav1d build on this PC.
  • 15 Vulkan files pass a clang syntax check for Windows.

Not tested:

  • Not on Unity's laptop, nor on any Intel GPU on Windows. This Longshot branch has not been built or run in the game.
  • Whether the driver keeps working after a caught fault (the review's item 5) is untested. A fault now also keeps that program out on later starts.
  • Whether 2 decoder threads keep up with the 1080p AV1 movies on his CPU is not measured.
  • What one-at-a-time compiles cost on Arc is not measured (the review's item 3).
  • Why the first movie picture can still be black (#73, the AMD run) is not known.

Needs other testers:

  • Unity's laptop (Intel UHD, 4 threads, 16 GB, Windows):
    1. Build this branch with Prepare shaders now ticked. If the folder is kept, delete longshot_prepare_skipped first.
    2. Start a new game with Skip opening off.
    3. Expect the preparation to finish, both movies to show their pictures, no crash in the first scene, and the log to show vk: Intel's compiler is entered by one thread and video: AV1 on dav1d ... (2 threads; 4 logical processors).
    4. Send the build's details, longshot_log.txt with HOS_VIDEO_LOG=1 (it reports how far the picture is behind the sound at the movie's end), and the fps on the title and the movie.
  • Windows, Intel Arc: one-at-a-time against side by side (the row), several interleaved runs each.
  • Linux: movies and the first scene unchanged.

Screenshots

None taken. Screenshots from Unity's laptop would be the useful ones.

Risk and rollback

  • On Windows Intel, compiles and cache fetches go one at a time: a cold first scene compiles slower, and a background cache save can wait for a compile. Draws and dispatches do not wait; they are left out until ready, as on a cold cache. The row's Side by side, or RX_VK_NO_INTEL_SERIAL=1, turns it off.
  • A shader the driver faults on is left out, with its draws, also on later starts on that driver (delete longshot_driver_faults.txt to try again).
  • On a slow decoder the movie's picture can fall behind its sound.
  • On 4 or fewer logical processors the decoder has 2 threads; HOS_DAV1D_THREADS changes it.
  • Reverting the pull request is enough.

Reviewer notes

Start with IntelDriverGate in gpu/vk/vk_internal.h, cached_graphics, cached_compute and pcache_data in vk_draw.cpp, make_module in vk_shader.cpp, dec_acquire() in host/nn_video.c and dav1d_av1_threads() in host/dav1d_av1.c. Frame generation was not changed: it did not run in either of Unity's logs.

Issues

See https://github.com/NotRexed/Hookshot/pull/2849 and #190.

Checklist

For everyone

  • One topic. (Fixes for one laptop's report. Splitting the movie half from the gate is offered in the review reply.)
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. (main d906c8f4 merged in.)
  • python -I -B tests/run_all.py run and passing. (Run; the 4 failures fail on main too, and #255 fixes them.)
  • 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.
  • Measured: main and this PR at named commits, same PC, at least 2 interleaved runs each. (Not yet: needs Unity's laptop and an Arc.)
  • No game files, dumps, build output or generated files.
  • third_party/ untouched.
  • The license is OK: GPL-3.0-or-later.

If applicable

  • AI assistance recorded with Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • A game-free test added for the fix.
  • Checks under tests/ that read changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux. (Syntax-checked for Windows; not built.)
  • Docs updated.
## Why This fix is for Unity's laptop. Every change below comes from his two logs and the hardware they report, so that Longshot runs on that laptop: | | Unity's laptop (from his logs) | |---|---| | GPU | Intel(R) UHD Graphics, integrated, Vulkan 1.4, driver 101.7088, 8061 MB shared | | CPU | 4 logical processors (the game reserves 2 cores); 11th Gen Core i3-1115G4 in the v3.0.0-rc.3 bug report | | RAM | 16,122 MB, 16,348 MB swap | | Screen | 1920x1080 at 60 Hz, SDR | | Settings | Auto (this PC): Minimum, the game's own upscaler | What the logs show on it: 1. **The game closes in Intel's driver.** An access violation (0xc0000005) at `igvk64.dll`+0x14d102, read at 0x170. It happened in 5 of his 7 v3.0.0-rc.3 runs, all in Kokiri Forest, with the same backtrace: `igvk64.dll+0x14d102 +0x134aaf +0x7f23a +0x322ef`, then `longshot_vk.dll+0x20ccbc`, then `+0x22375d`, then the thread's start. - Mapped with nightly-70's `longshot_vk.dll` (dd02c6cc, whose `gpu/vk` is identical to v3.0.0-rc.3's 0c74253d): `+0x22375d` is the `std::thread` started by `pipeline_cache_save`, and `+0x20ccbc` returns from `pipeline_cache_save(bool)::$_0` after `callq *(%rdi)`, which is `vkGetPipelineCacheData(dev.device, pcache, &n, data)`, right after `PipelineCacheFile::writable(pcache_path, n)`. - So it is the background save copying the pipeline cache while other threads build pipelines into it, as #190 found on Arc. This GPU writes no play files (`play_cache` needs `pipelineCreationCacheControl`), so every pipeline built in play goes into that same cache. 2. **Shaders are not ready in play.** Every log, from v3.0.0-rc.1 to all 7 runs of rc.3, says `the shaders' preparation was skipped at the build`. The builder writes that marker only when its preparation run stopped with "the GPU driver stopped responding", most likely the same driver problem during the build's own compiles. Every start since then compiles each shader when it is first drawn: 15 pipelines took 8.5 s, and 312 took 203 s in the older log. 3. **The opening movie loses its pictures.** A slow decode on this CPU skipped most pictures to catch up with the sound. 4. **The title and the opening movie run at about 35 fps of 60** (v3.0.0-rc.1). On 76 frames the game's thread waited 14 to 24 ms in a submit's memory sync. dav1d, the movie decoder, ran one thread per logical processor, which is all 4 on this CPU, beside the game's own threads. The Intel compiler and movie fixes are ported from https://github.com/NotRexed/Hookshot/pull/2849, without its updater change. Updated for HumanBean's review: see the reply below the review. ## What changed - **Intel's driver, problem 1.** `IntelDriverGate` in `gpu/vk/vk_internal.h` lets one thread at a time into Intel's compiler on Windows. That covers the game's shaders, every compute pipeline of the renderer's own, and now `vkGetPipelineCacheData` too (`pcache_data` in `vk_draw.cpp`: all six reads). Other vendors, and Intel on Linux, are not held. - A create that compiles nothing (`FAIL_ON_PIPELINE_COMPILE_REQUIRED`: a draw's or a dispatch's ask) only *tries* the lock. While a worker compiles, it answers `VK_PIPELINE_COMPILE_REQUIRED` (cold), so the replay thread never waits behind a compile. On Intel a dispatch's module, for a program read from the cache without its code, is made on the worker, not on the replay thread. - A fault inside the driver (`__try`/`__except`) leaves that shader out. A fault making a shader module is now written to `longshot_driver_faults.txt`, as pipeline faults already were, so later starts on the same driver leave that program out (`make_module`, `driver_faulted_module`). - **A row for a low-core Intel CPU.** The Debug tab's **Intel shader compiles** row (Developer section, Intel graphics on Windows only): - **One at a time**: the default, and the safe choice on a CPU with 4 cores or fewer, like Unity's. - **Side by side**: faster builds on many cores, but the driver can crash the game. It applies after a restart and is saved as `intel_shader_compiles=`. `RX_VK_NO_INTEL_SERIAL=1` is Side by side for one run. - **The movie, problem 3.** `host/nn_video.c`: - Every acquire waits about 100 ms, as on main. The 500 ms first wait is gone: `decode_pending()` has already decoded what was submitted, so the wait never showed the first picture (the review's item 2). - Catching up uses the recent pictures' decode time (`recent_ns`, about the last 8) instead of the movie's mean, which a slow first decode held high. - It decodes ahead at most one picture's time per acquire. - A decoder slower than the movie shows the late picture rather than decoding one only to drop it. - **The movie decoder's threads, problem 4.** `host/dav1d_av1.c`: with 4 logical processors or fewer, dav1d decodes on 2 threads; above 4, it keeps its own count. `HOS_DAV1D_THREADS=<n>` still sets it. - **Tests.** - `test_intel_compiler_gate.py`: the gate, the try-lock for asks, the dispatch's module on the worker, the fault record, `pcache_data`, the row, and the 8 compute sources. - `test_video_catchup.py`: a slow first decode no longer turns the catch-up off. - `test_dav1d_av1.py`: the thread rule. - Updated for the new functions: `test_vcore_video_acquire.py`, `test_program_cache_one_variant.py`, `test_damage_debug_menu.py`, and the program-cache and pipeline-cache C++ stubs. - **Docs.** The README covers this fix in every section it touches: - **Project status:** the Intel row, and a new row for movies on a slow CPU. - **What you need:** a "below the minimum" note for Unity's kind of laptop, also in the website's copy (`website/src/content/docs/requirements.mdx`). - **Compile shaders:** what `longshot_prepare_skipped` does. - **If something goes wrong:** rows for the Intel crash, the skipped preparation and the movie, and a new **Intel laptops** section with Unity's specs, what to set and what to send. - **In-game menu:** the Intel shader compiles row in the settings list. - **Switches:** the movie and Intel paragraphs. - `docs/development.md` has the switches. ## How this relates to other Intel work - **#190** wraps the same functions in a shared lock against `vkGetPipelineCacheData`. On Windows Intel this pull request now takes Intel's gate around that fetch too, which covers the same crash for every build that holds the gate. If both land, the lock order must be **IntelDriverGate outside, #190's shared lock inside**, in every function. That way a builder never waits for the gate while it holds the shared side. Glad to rebase on #190, or to drop `pcache_data` if #190 lands first. - **`RX_VK_COMPUTE_SERIAL`** on main sends the dispatch's compute pipeline jobs to one serial queue on Intel (issue 496). The gate is lower down: it orders every entry into Intel's compiler, from any thread, compute or graphics. The serial queue still keeps compute jobs from piling up behind each other. The two do not wait on each other. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Intel shader compiles row | One at a time or Side by side into Intel's compiler | One at a time | One at a time on 4 cores or fewer | Windows Intel (UHD, Arc) | NVIDIA, AMD, Intel on Linux (row hidden) | Unity's laptop, any Intel on Windows | | `RX_VK_NO_INTEL_SERIAL=1` | Side by side for one run | off | keep off | measuring compile speed | | | | `HOS_DAV1D_THREADS=<n>` | The movie decoder's thread count | 2 with 4 or fewer logical processors, else dav1d's own | leave unset | setting the count by hand | | Unity's laptop | | `HOS_VIDEO_NO_CATCHUP=1` | A movie skips no pictures behind its sound | off | keep off | measuring decode speed | | | | `HOS_VIDEO_ACQUIRE_TRIES=1` | The movie waits by 50 sleeps of 2 ms | off (by the clock) | keep off | comparing with the old wait | | | ## Measurements No measurement of main against this pull request yet: it needs Unity's laptop. - **Unity's logs, before the fix:** the crash in `igvk64.dll` (5 of 7 rc.3 runs, all in the background pipeline-cache save), the preparation skipped, about 35 fps on the title (30–50 fps in the rc.3 runs), and 14–24 ms memory-sync waits. None of these logs is a run of this branch. - **One AMD play of the Hookshot build of the same fix** (RX 9070 XT, Ryzen 9 7900X, Windows 11). Both movies played, 59.5 fps in the 3D scene, no crash. Intel's gate was never entered there. ## Testing **Tested:** `python -I -B tests/run_all.py` on Windows 11 at 2bc07a1d, with main d906c8f4 merged in, using llvm-mingw 20261104: 464 passed, 4 failed, 67 skipped. The game was not built. - The 4 failures are `nx2/test_nup_paths`, `test_check_third_party`, `test_release` and `test_menu_i18n`. They fail on main too, and #255 fixes them. - `test_dav1d_av1` was skipped: there is no dav1d build on this PC. - 15 Vulkan files pass a clang syntax check for Windows. **Not tested:** - Not on Unity's laptop, nor on any Intel GPU on Windows. This Longshot branch has not been built or run in the game. - Whether the driver keeps working after a caught fault (the review's item 5) is untested. A fault now also keeps that program out on later starts. - Whether 2 decoder threads keep up with the 1080p AV1 movies on his CPU is not measured. - What one-at-a-time compiles cost on Arc is not measured (the review's item 3). - Why the first movie picture can still be black (#73, the AMD run) is not known. **Needs other testers:** - **Unity's laptop (Intel UHD, 4 threads, 16 GB, Windows):** 1. Build this branch with **Prepare shaders now** ticked. If the folder is kept, delete `longshot_prepare_skipped` first. 2. Start a new game with Skip opening off. 3. Expect the preparation to finish, both movies to show their pictures, no crash in the first scene, and the log to show `vk: Intel's compiler is entered by one thread` and `video: AV1 on dav1d ... (2 threads; 4 logical processors)`. 4. Send the build's details, `longshot_log.txt` with `HOS_VIDEO_LOG=1` (it reports how far the picture is behind the sound at the movie's end), and the fps on the title and the movie. - Windows, Intel Arc: one-at-a-time against side by side (the row), several interleaved runs each. - Linux: movies and the first scene unchanged. ## Screenshots None taken. Screenshots from Unity's laptop would be the useful ones. ## Risk and rollback - On Windows Intel, compiles and cache fetches go one at a time: a cold first scene compiles slower, and a background cache save can wait for a compile. Draws and dispatches do not wait; they are left out until ready, as on a cold cache. The row's Side by side, or `RX_VK_NO_INTEL_SERIAL=1`, turns it off. - A shader the driver faults on is left out, with its draws, also on later starts on that driver (delete `longshot_driver_faults.txt` to try again). - On a slow decoder the movie's picture can fall behind its sound. - On 4 or fewer logical processors the decoder has 2 threads; `HOS_DAV1D_THREADS` changes it. - Reverting the pull request is enough. ## Reviewer notes Start with `IntelDriverGate` in `gpu/vk/vk_internal.h`, `cached_graphics`, `cached_compute` and `pcache_data` in `vk_draw.cpp`, `make_module` in `vk_shader.cpp`, `dec_acquire()` in `host/nn_video.c` and `dav1d_av1_threads()` in `host/dav1d_av1.c`. Frame generation was not changed: it did not run in either of Unity's logs. ## Issues See https://github.com/NotRexed/Hookshot/pull/2849 and #190. ## Checklist ### For everyone - [ ] One topic. (Fixes for one laptop's report. Splitting the movie half from the gate is offered in the review reply.) - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. (main d906c8f4 merged in.) - [ ] `python -I -B tests/run_all.py` run and passing. (Run; the 4 failures fail on main too, and #255 fixes them.) - [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. - [ ] Measured: main and this PR at named commits, same PC, at least 2 interleaved runs each. (Not yet: needs Unity's laptop and an Arc.) - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched. - [x] The license is OK: GPL-3.0-or-later. ### If applicable - [x] AI assistance recorded with `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. - [x] Checks under `tests/` that read changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux. (Syntax-checked for Windows; not built.) - [x] Docs updated.
A decoder slower than the gap between pictures was asked to decode the next one so it could be dropped. The clock gained every decode, and the opening skipped 1933 of 2221 pictures. The first acquire waits about 500 ms, by the same clock as the later 100 ms wait, and a stopped decoder still does not wait.

Co-authored-by: Cursor <[email protected]>
(cherry picked from commit 8b65b38b28ba49e8a59ba4b38e09ed9aa7c61834)
Intel's compiler on Windows was entered by several threads, and vkCreateShaderModule had no guard. A read of address 0x170 in igvk64 ended the process during the first scene. On that driver one thread enters the compiler, and a fault drops the shader instead of the process. Other vendors, and Intel on other systems, are unchanged.

Co-authored-by: Cursor <[email protected]>
(cherry picked from commit f22b60bb5c73c3faf62ab68c6c38c0b9535c64b9)
Declaring them in the header made a second function beside the ones in the unnamed namespace, so every call in vk_draw.cpp was ambiguous and the Windows build stopped. Other files call the same functions through a wrapper.

Co-authored-by: Cursor <[email protected]>
(cherry picked from commit 80f981210576afd0a5c987fec87802f54444bf1b)
The stopped-decoder check was still counting a decoder that had already acquired once.

Co-authored-by: Cursor <[email protected]>
(cherry picked from commit d814c04b9984b81fde303f7c1d0e1838218ad678)
make_module now enters that compiler through the gate, and the cut-out check had no stand-in for it.

Co-authored-by: Cursor <[email protected]>
(cherry picked from commit 311a462f282e152fe574b48dbffcbdfb1ba7c2b1)
Co-authored-by: Cursor <[email protected]>
(cherry picked from commit 4f7590fd7fb6475197263949031b32508a8991fa)
fix: Longshot's names in the Intel compiler and movie changes
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
750a3966cb
Co-authored-by: Cursor <[email protected]>
Merge branch 'main' into fix/windows-movie-and-intel-compiler
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
Website / Website on Cloudflare (pull_request) Has been cancelled
83c18ab312
HumanBean added this to the v3.0.0 milestone 2026-11-13 17:39:11 +00:00
docs(readme): the Intel status row names the Windows compiler fix, not yet tested on Intel
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
7734d426c1
Co-authored-by: Cursor <[email protected]>
Author
First-time contributor

Updated after main fbd42024 was merged in (83c18ab3):

  • Checked main's 13 new commits against the fix. They add no new shader or pipeline creation call. The new RGBA16F DLSS pipeline goes through make_pipeline(), which already takes Intel's gate and the guarded calls. host/nn_video.c is unchanged on main. No code change was needed.
  • README: the Intel row of the project status table now names the Windows compiler fix, as not yet tested on an Intel GPU (7734d426).
  • Tests rerun without building the game: 460 passed with llvm-mingw (5 failed), 446 with clang 22.1.5 (13 failed). The fix's tests pass in both. Every failure also fails on main on this PC, and is named under Testing.

Still WIP: this branch has not been built or played, and nobody has run it on an Intel GPU.

Updated after main fbd42024 was merged in (83c18ab3): - Checked main's 13 new commits against the fix. They add no new shader or pipeline creation call. The new RGBA16F DLSS pipeline goes through `make_pipeline()`, which already takes Intel's gate and the guarded calls. `host/nn_video.c` is unchanged on main. No code change was needed. - README: the Intel row of the project status table now names the Windows compiler fix, as not yet tested on an Intel GPU (7734d426). - Tests rerun without building the game: 460 passed with llvm-mingw (5 failed), 446 with clang 22.1.5 (13 failed). The fix's tests pass in both. Every failure also fails on main on this PC, and is named under Testing. Still WIP: this branch has not been built or played, and nobody has run it on an Intel GPU.
HumanBean left a comment

Thanks for bringing https://github.com/NotRexed/Hookshot/pull/2849 over and leaving the updater out. The description says plainly what was not run, and the switches are documented. Some parts are good: the guarded module create follows the existing guarded_graphics / guarded_compute pattern, a faulted module is not saved to the program cache (vk_shader.cpp throws before program_cache_save), and in this run the program is marked failed rather than asked for again. IntelDriverGate has external linkage, so its static std::mutex is one lock across vk_draw.cpp, vk_shader.cpp and vk_temporal.cpp. Pipeline-cache and program-cache keys are unchanged: no create info, flag or stamp changes.

The PR is WIP and has no run of this branch on any PC, so this is request-changes. Below is what to fix before the Intel UHD run.

Must change

  1. On Windows Intel the gate makes the replay thread wait behind a background compile. cached_graphics and cached_compute take the lock around all of create_cached, including the ask-only calls (VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT). Those calls exist so that a draw or dispatch never waits for a compile. The dispatch path calls compute_pipeline_cached(p, true) (vk_draw.cpp:9479, "it comes back at once"), and program_cache_complete → make_module on the same path. Both now block on the mutex while a worker sits in a full Intel compile, which can take seconds. The cold first scene would hitch on every Intel Windows PC, not just the faulting UHD. Ask-only calls compile nothing: either leave them out of the gate, or try_lock the gate and treat a busy one as cold.

  2. The black first frame. The 500 ms first wait does not fit the code it is meant to fix:

    • decode_pending() runs synchronously before the wait loop (nn_video.c:751). A 426 ms first decode has already finished when the 100 ms wait starts, so the old wait never cut a slow decode short.
    • The wait loop only helps when another thread submits. With dav1d (dav1d_av1.c pictures(..., 1) is non-blocking), a picture still in flight in dav1d's frame threads is collected only at the next decode call. A loop with no new submission never picks it up, and #110 notes that OoT submits from the thread that takes the pictures.
    • The same black frame is in #73 on a fast Linux PC, and in this PR's own AMD run (first decode 73.8 ms worst).

    As written, the change lengthens the first acquire's stall from 100 to 500 ms on every PC whose first acquire finds nothing decoded, and does not show the picture. That includes fast PCs. Either find the real cause (an HOS_VIDEO_LOG=1 run shows the submits before acquire 1), or drop this half. Also, d->acquires is never reset by Flush or Stop, so a decoder reused for a second movie gets 100 ms, not 500.

  3. A new default with no measurement. Serialising every shader-module and pipeline create on Windows Intel (UHD and Arc) is a new default. It has not run on any Intel PC, and nothing says what it costs on Arc, where the --prepare-shaders run and play compiles now use one thread. Keep the PR WIP until there are the Intel UHD run and an Arc before/after, with several interleaved runs each. The Measured box is honestly unticked. This item is that box.

Should change

  1. A/V drift on slow decoders is unbounded and unmeasured. With each > spacing, the catch-up stops decoding ahead. The stream then moves by at most one picture per acquire, so a frame that is late for any other reason (the late frames of #73) is never made up, and the lag only grows. each is the movie's cumulative mean and includes the first decode (426 ms in the report), so early in a movie it also turns the catch-up off on mid-range PCs until enough pictures have been decoded to bring the mean down. At the report's 19.5 ms against 16.7 ms, the picture ends roughly 15 % behind: several seconds on the first movie and over 20 s on the 154 s second one, if acquires are frame-paced. Consider a bound instead of an off switch: decode ahead only within a time budget per acquire, or allow a maximum lag. Use a recent-window decode time, not the whole-movie mean. Either way, report the end-of-movie lag (HOS_VIDEO_LOG prints it) on the slow PC.
  2. A caught fault inside igvk64 can turn a crash into a hang. On AMD a caught fault left the driver waiting on itself (driver_faults.h, issue 996). If Intel's compiler is left holding an internal lock after the SEH unwind, the next create blocks inside the driver while holding IntelDriverGate. Every compile thread, and (through item 1) the replay thread, then freezes with no crash report. Consider latching: after one caught fault on Intel, log it and stop handing the driver new work, or at least say in the PR that the recovery is untested. The module fault is also not written to longshot_driver_faults.txt, so a deterministic fault is hit again on every start.
  3. The gate does not cover every create. vk_texture.cpp (ASTC, unswizzle), vk_memory.cpp (write-back diff), vk_framegen.cpp, vk_reactive.cpp, vk_fsr3*.cpp and vk_coopmat.cpp still call vkCreateShaderModule / vkCreateComputePipelines directly. Some may run lazily, during play, beside the translation workers. "One thread enters vkCreateShaderModule and vkCreate*Pipelines" is not yet true. Gate them, or narrow the claim.
  4. Overlap with the other Intel work.
    • #190 wraps the same functions (cached_graphics, cached_compute, graphics_with, the warm pass) in a shared lock against vkGetPipelineCacheData. Whichever lands second has to merge the two lock orders deliberately. With an exclusive gate inside a shared lock, a forced save waiting for the exclusive side can deadlock against a builder that holds the gate and asks for the shared side. Coordinate with that PR, or say which one goes first.
    • Main already runs dispatch computes one at a time on Intel for the same issue 496 (RX_VK_COMPUTE_SERIAL, vk_draw.cpp:9474). Say how the two relate.
    • #191 and #189 don't touch these paths.
    • Main's quarantine (fault_quarantine().begin, kBusy/kFaulted) sits outside graphics_with, so its lock order is fine. Its "a cold probe does not wait" is undone on Intel by item 1.
  5. One topic. The box is honestly unticked. The movie half is host code for every PC and the gate is Intel Windows only. Split them, so the gate can be measured on Intel without the video change and the other way round.

I could not check the in-game behaviour, the llvm-mingw build of this branch, or whether OoT creates a new decoder for each movie. I ran nothing.

Thanks for bringing https://github.com/NotRexed/Hookshot/pull/2849 over and leaving the updater out. The description says plainly what was not run, and the switches are documented. Some parts are good: the guarded module create follows the existing `guarded_graphics` / `guarded_compute` pattern, a faulted module is not saved to the program cache (`vk_shader.cpp` throws before `program_cache_save`), and in this run the program is marked `failed` rather than asked for again. `IntelDriverGate` has external linkage, so its `static std::mutex` is one lock across `vk_draw.cpp`, `vk_shader.cpp` and `vk_temporal.cpp`. Pipeline-cache and program-cache keys are unchanged: no create info, flag or stamp changes. The PR is WIP and has no run of this branch on any PC, so this is request-changes. Below is what to fix before the Intel UHD run. ## Must change 1. **On Windows Intel the gate makes the replay thread wait behind a background compile.** `cached_graphics` and `cached_compute` take the lock around all of `create_cached`, including the ask-only calls (`VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT`). Those calls exist so that a draw or dispatch never waits for a compile. The dispatch path calls `compute_pipeline_cached(p, true)` (vk_draw.cpp:9479, "it comes back at once"), and `program_cache_complete` → `make_module` on the same path. Both now block on the mutex while a worker sits in a full Intel compile, which can take seconds. The cold first scene would hitch on every Intel Windows PC, not just the faulting UHD. Ask-only calls compile nothing: either leave them out of the gate, or `try_lock` the gate and treat a busy one as cold. 2. **The black first frame.** The 500 ms first wait does not fit the code it is meant to fix: - `decode_pending()` runs synchronously *before* the wait loop (nn_video.c:751). A 426 ms first decode has already finished when the 100 ms wait starts, so the old wait never cut a slow decode short. - The wait loop only helps when another thread submits. With dav1d (`dav1d_av1.c` `pictures(..., 1)` is non-blocking), a picture still in flight in dav1d's frame threads is collected only at the next decode call. A loop with no new submission never picks it up, and https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/110 notes that OoT submits from the thread that takes the pictures. - The same black frame is in https://git.magicbean.dev/MagicBeanDev/Longshot/issues/73 on a fast Linux PC, and in this PR's own AMD run (first decode 73.8 ms worst). As written, the change lengthens the first acquire's stall from 100 to 500 ms on every PC whose first acquire finds nothing decoded, and does not show the picture. That includes fast PCs. Either find the real cause (an `HOS_VIDEO_LOG=1` run shows the submits before acquire 1), or drop this half. Also, `d->acquires` is never reset by Flush or Stop, so a decoder reused for a second movie gets 100 ms, not 500. 3. **A new default with no measurement.** Serialising every shader-module and pipeline create on Windows Intel (UHD and Arc) is a new default. It has not run on any Intel PC, and nothing says what it costs on Arc, where the `--prepare-shaders` run and play compiles now use one thread. Keep the PR WIP until there are the Intel UHD run and an Arc before/after, with several interleaved runs each. The Measured box is honestly unticked. This item is that box. ## Should change 4. **A/V drift on slow decoders is unbounded and unmeasured.** With `each > spacing`, the catch-up stops decoding ahead. The stream then moves by at most one picture per acquire, so a frame that is late for any other reason (the late frames of https://git.magicbean.dev/MagicBeanDev/Longshot/issues/73) is never made up, and the lag only grows. `each` is the movie's cumulative mean and includes the first decode (426 ms in the report), so early in a movie it also turns the catch-up off on mid-range PCs until enough pictures have been decoded to bring the mean down. At the report's 19.5 ms against 16.7 ms, the picture ends roughly 15 % behind: several seconds on the first movie and over 20 s on the 154 s second one, if acquires are frame-paced. Consider a bound instead of an off switch: decode ahead only within a time budget per acquire, or allow a maximum lag. Use a recent-window decode time, not the whole-movie mean. Either way, report the end-of-movie lag (`HOS_VIDEO_LOG` prints it) on the slow PC. 5. **A caught fault inside igvk64 can turn a crash into a hang.** On AMD a caught fault left the driver waiting on itself (`driver_faults.h`, issue 996). If Intel's compiler is left holding an internal lock after the SEH unwind, the next create blocks inside the driver while holding `IntelDriverGate`. Every compile thread, and (through item 1) the replay thread, then freezes with no crash report. Consider latching: after one caught fault on Intel, log it and stop handing the driver new work, or at least say in the PR that the recovery is untested. The module fault is also not written to `longshot_driver_faults.txt`, so a deterministic fault is hit again on every start. 6. **The gate does not cover every create.** `vk_texture.cpp` (ASTC, unswizzle), `vk_memory.cpp` (write-back diff), `vk_framegen.cpp`, `vk_reactive.cpp`, `vk_fsr3*.cpp` and `vk_coopmat.cpp` still call `vkCreateShaderModule` / `vkCreateComputePipelines` directly. Some may run lazily, during play, beside the translation workers. "One thread enters vkCreateShaderModule and vkCreate*Pipelines" is not yet true. Gate them, or narrow the claim. 7. **Overlap with the other Intel work.** - https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/190 wraps the same functions (`cached_graphics`, `cached_compute`, `graphics_with`, the warm pass) in a shared lock against `vkGetPipelineCacheData`. Whichever lands second has to merge the two lock orders deliberately. With an exclusive gate inside a shared lock, a forced save waiting for the exclusive side can deadlock against a builder that holds the gate and asks for the shared side. Coordinate with that PR, or say which one goes first. - Main already runs dispatch computes one at a time on Intel for the same issue 496 (`RX_VK_COMPUTE_SERIAL`, vk_draw.cpp:9474). Say how the two relate. - https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/191 and https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/189 don't touch these paths. - Main's quarantine (`fault_quarantine().begin`, `kBusy`/`kFaulted`) sits outside `graphics_with`, so its lock order is fine. Its "a cold probe does not wait" is undone on Intel by item 1. 8. **One topic.** The box is honestly unticked. The movie half is host code for every PC and the gate is Intel Windows only. Split them, so the gate can be measured on Intel without the video change and the other way round. I could not check the in-game behaviour, the llvm-mingw build of this branch, or whether OoT creates a new decoder for each movie. I ran nothing.
@ -1235,0 +1236,4 @@
// igvk64 is short: an access violation there is not the pipeline guards' "driver faulted compiling" line, and it ends
// the process. The same answer as those guards: that program is left out.
#ifdef _WIN32
__declspec(noinline) VkResult guarded_shader_module(const VkShaderModuleCreateInfo* ci, VkShaderModule* m) {
Owner

If igvk64 faults while holding an internal lock, the SEH unwind leaves it held. The next create then blocks inside the driver with IntelDriverGate held, and every compile thread and the replay thread freeze: a hang instead of a crash. On AMD a caught fault did exactly that (driver_faults.h, issue 996). Consider a latch on Intel after the first caught fault, and recording the program in longshot_driver_faults.txt so it isn't faulted again on every start.

If igvk64 faults while holding an internal lock, the SEH unwind leaves it held. The next create then blocks inside the driver with `IntelDriverGate` held, and every compile thread and the replay thread freeze: a hang instead of a crash. On AMD a caught fault did exactly that (driver_faults.h, issue 996). Consider a latch on Intel after the first caught fault, and recording the program in `longshot_driver_faults.txt` so it isn't faulted again on every start.
@ -1237,3 +1267,4 @@
thread_local VkPipelineCache driver_ask_cache = VK_NULL_HANDLE;
/// (with the pipeline cache: from it, or in play into the play generation's, create_cached)
VkResult cached_graphics(const VkGraphicsPipelineCreateInfo* ci, VkPipeline* pl) {
IntelDriverGate gate;
Owner

On Windows Intel this holds the gate for the ask-only calls too (FAIL_ON_PIPELINE_COMPILE_REQUIRED). They compile nothing, and they are what the dispatch path uses not to wait (compute_pipeline_cached, line 9479). Now the replay thread waits here behind a worker's whole compile. Leave the ask-only calls out of the gate, or try_lock it and answer 'cold' when it is busy. The same applies to cached_compute below.

On Windows Intel this holds the gate for the ask-only calls too (`FAIL_ON_PIPELINE_COMPILE_REQUIRED`). They compile nothing, and they are what the dispatch path uses not to wait (`compute_pipeline_cached`, line 9479). Now the replay thread waits here behind a worker's whole compile. Leave the ask-only calls out of the gate, or `try_lock` it and answer 'cold' when it is busy. The same applies to `cached_compute` below.
@ -122,0 +135,4 @@
std::call_once(once, [] {
logf("vk: Intel's compiler is entered by one thread (RX_VK_NO_INTEL_SERIAL: side by side)");
});
hold = std::unique_lock<std::mutex>(mu);
Owner

Not every create goes through this lock: vk_texture.cpp (ASTC, unswizzle), vk_memory.cpp, vk_framegen.cpp, vk_reactive.cpp, vk_fsr3*.cpp and vk_coopmat.cpp still call vkCreateShaderModule / vkCreateComputePipelines directly. #190 also takes a shared lock in the same functions, so the two lock orders need settling before both land.

Not every create goes through this lock: vk_texture.cpp (ASTC, unswizzle), vk_memory.cpp, vk_framegen.cpp, vk_reactive.cpp, vk_fsr3*.cpp and vk_coopmat.cpp still call `vkCreateShaderModule` / `vkCreateComputePipelines` directly. https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/190 also takes a shared lock in the same functions, so the two lock orders need settling before both land.
@ -723,3 +723,3 @@
ci.pCode = spirv.data();
VkShaderModule m = VK_NULL_HANDLE;
vkCreateShaderModule(dev.device, &ci, nullptr, &m);
IntelDriverGate gate;
Owner

make_module is also reached from the dispatch path (program_cache_complete, vk_draw.cpp:9470). On Intel Windows the draw thread now waits for this lock while a worker compiles.

`make_module` is also reached from the dispatch path (`program_cache_complete`, vk_draw.cpp:9470). On Intel Windows the draw thread now waits for this lock while a worker compiles.
host/nn_video.c Outdated
@ -755,3 +757,3 @@
static int by_tries = -1;
if (by_tries < 0) by_tries = env_on("HOS_VIDEO_ACQUIRE_TRIES");
const int64_t wait_until = hos_now_ns() + 100000000;
const int64_t wait_until = hos_now_ns() + (d->acquires ? 100000000 : 500000000);
Owner

decode_pending() (line 751) decodes synchronously before this loop starts, so a 426 ms first decode was never cut short by the 100 ms wait. The loop only helps if another thread submits. With dav1d, a picture still in its frame threads is collected only at the next decode call. Issue #73 (fast Linux) and this PR's AMD run both still show the black first frame. As it stands, this adds up to 400 ms to the first acquire on every PC that reaches it with nothing decoded. d->acquires is also never reset by Flush or Stop.

`decode_pending()` (line 751) decodes synchronously before this loop starts, so a 426 ms first decode was never cut short by the 100 ms wait. The loop only helps if another thread submits. With dav1d, a picture still in its frame threads is collected only at the next decode call. Issue https://git.magicbean.dev/MagicBeanDev/Longshot/issues/73 (fast Linux) and this PR's AMD run both still show the black first frame. As it stands, this adds up to 400 ms to the first acquire on every PC that reaches it with nothing decoded. `d->acquires` is also never reset by Flush or Stop.
host/nn_video.c Outdated
@ -804,1 +809,4 @@
if (!d->phead) break;
const int64_t spacing = d->decoded > 1 ? (d->end_pts - d->first_pts) / (d->decoded - 1) : 0;
const int64_t each = d->decoded > 0 ? d->decode_ns / d->decoded : 0;
if (spacing > 0 && each > spacing) break;
Owner

This turns the catch-up off rather than bounding it. From here on the stream moves at most one picture per acquire, so a frame that is late for any other reason is never made up, and the lag behind the sound only grows. each is the movie's cumulative mean and includes the slow first decode, so on mid-range PCs it also turns the catch-up off for a movie's first pictures. Consider a per-acquire time budget for decoding ahead, or a maximum lag, and a recent-window decode time. Please report the end-of-movie lag (HOS_VIDEO_LOG) from the slow PC.

This turns the catch-up off rather than bounding it. From here on the stream moves at most one picture per acquire, so a frame that is late for any other reason is never made up, and the lag behind the sound only grows. `each` is the movie's cumulative mean and includes the slow first decode, so on mid-range PCs it also turns the catch-up off for a movie's first pictures. Consider a per-acquire time budget for decoding ahead, or a maximum lag, and a recent-window decode time. Please report the end-of-movie lag (`HOS_VIDEO_LOG`) from the slow PC.
ASTC, BC and unswizzle, the write-back diff, the reactive mask, FSR 3.1 and its inputs and
interpolation, frame generation and the cooperative-matrix check still called vkCreateShaderModule
and vkCreateComputePipelines directly. Built beside a worker's compile, that is two threads inside
Intel's Windows compiler again, and a fault in one of them ended the game. They take IntelDriverGate
and the guarded calls; FSR 3.1 holds the lock only for its module, since shared_compute_pipeline
takes the same lock.
feat(menu): an Intel shader compiles row, one at a time or side by side
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
0fb07d94f4
Intel graphics on Windows only (the Debug tab's Developer section). One at a time, the default,
keeps Intel's compiler to one thread: the safe choice, and on a CPU with 4 cores or fewer it costs
little. Side by side builds faster on many cores, but Intel's driver can crash while building.
Applies after a restart; RX_VK_NO_INTEL_SERIAL=1 holds the row at Side by side for a run.
# Conflicts:
#	README.md
#	gpu/vk/vk_menu.cpp
fix(tests): the Debug menu fixture knows the Intel shader compiles row (hidden: not Intel graphics on Windows)
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
Website / Website on Cloudflare (pull_request) Has been cancelled
44411fee90
fix(video): the movie decoder takes 2 threads on a PC with 4 logical processors or fewer
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
cc1b3095ca
Unity's log (Intel UHD Graphics, 4 threads, 16 GB, v3.0.0-rc.1): dav1d ran a thread per logical processor, and while the title and the opening movie played the game's thread waited 14-24 ms on most submits, at about 35 fps of 60. 2 threads leave the game's 2 reserved cores their time. HOS_DAV1D_THREADS still sets the count. Not run on that PC.

Co-authored-by: Cursor <[email protected]>
docs(readme): the decoder threads paragraph names the laptop it is for (Unity's)
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
6852d2dc19
Co-authored-by: Cursor <[email protected]>
- IntelDriverGate(ask): a create that compiles nothing (FAIL_ON_PIPELINE_COMPILE_REQUIRED) try-locks the gate and is answered VK_PIPELINE_COMPILE_REQUIRED (cold) while a worker compiles. On Intel a dispatch's module is made on the worker, not the replay thread.
- make_module: a program the driver faulted on is noted in longshot_driver_faults.txt and not handed to the driver again on that driver.
- pcache_data: vkGetPipelineCacheData inside the gate (igvk64.dll+0x14d102 fetching while building, #190).
- nn_video.c: every acquire waits ~100 ms (the 500 ms first wait did not show the first picture). The catch-up uses the recent pictures' decode time and decodes ahead at most one picture's time per acquire.
- README and docs: the shaders' preparation after a stopped build (longshot_prepare_skipped), as on Unity's laptop.

Co-authored-by: Cursor <[email protected]>
Merge remote-tracking branch 'forge/main' into fix/windows-movie-and-intel-compiler
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
2bc07a1d91
Author
First-time contributor

Thanks for the review. At 2bc07a1d, with main d906c8f4 merged in:

  1. An ask waits behind a compile. Fixed. A create with FAIL_ON_PIPELINE_COMPILE_REQUIRED only tries the gate (IntelDriverGate(ask), std::try_to_lock). While a worker compiles, it answers VK_PIPELINE_COMPILE_REQUIRED, so the draw is left out as cold. That covers cached_graphics, cached_compute and graphics_with. On Intel a dispatch's first module, for a program read without its code, is now made on the worker (program_cache_complete(q) in the job), not on the replay thread. test_intel_compiler_gate.py and test_program_cache_one_variant.py check both.
  2. The black first frame. The 500 ms first wait is gone: every acquire waits ~100 ms, as on main. You were right that decode_pending() decodes synchronously before the wait, so the wait never helped. Without it, acquires not being reset on Flush/Stop no longer matters. The README now says the first picture can still be black and that why is not known.
  3. One at a time on Arc. Not measured; there is no Arc here. The row keeps Side by side one click away. The PR stays WIP until a run on Intel.
  4. The catch-up. It now uses the recent pictures' decode time (recent_ns, about the last 8), not the movie's mean, so a slow first decode no longer turns it off. It decodes ahead at most one picture's time per acquire. test_video_catchup.py has the case of a 426 ms first decode followed by fast ones. With a decoder slower than the movie, the picture still falls behind; the README says so.
  5. After a caught fault. Still untested whether the driver keeps working. A fault making a shader module is now noted in longshot_driver_faults.txt, as pipeline faults were, so later starts on that driver leave the program out instead of faulting again.
  6. Every create under the gate. The 8 compute sources were already gated. vkGetPipelineCacheData is now too, through pcache_data (all 6 reads), for #190's crash.
  7. #190 and RX_VK_COMPUTE_SERIAL. See the description's "How this relates to other Intel work". In short: the gate goes outside #190's shared lock in every function, or I drop pcache_data if #190 lands first. RX_VK_COMPUTE_SERIAL still orders the compute jobs, while the gate orders every entry into the compiler; they don't wait on each other.
  8. Splitting. I can open the movie part (nn_video.c, dav1d_av1.c and their tests) as its own PR now. Unity's test needs both halves, so I'd rather keep them together until he has run it, unless you want the split first.
  9. WIP. It stays WIP until it is measured on Intel hardware, Unity's laptop first.

Game-free suite at 2bc07a1d: 464 passed, 4 failed, 67 skipped. The 4 failures fail on main too, and #255 fixes them.

Thanks for the review. At 2bc07a1d, with main d906c8f4 merged in: 1. **An ask waits behind a compile.** Fixed. A create with `FAIL_ON_PIPELINE_COMPILE_REQUIRED` only tries the gate (`IntelDriverGate(ask)`, `std::try_to_lock`). While a worker compiles, it answers `VK_PIPELINE_COMPILE_REQUIRED`, so the draw is left out as cold. That covers `cached_graphics`, `cached_compute` and `graphics_with`. On Intel a dispatch's first module, for a program read without its code, is now made on the worker (`program_cache_complete(q)` in the job), not on the replay thread. `test_intel_compiler_gate.py` and `test_program_cache_one_variant.py` check both. 2. **The black first frame.** The 500 ms first wait is gone: every acquire waits ~100 ms, as on main. You were right that `decode_pending()` decodes synchronously before the wait, so the wait never helped. Without it, `acquires` not being reset on Flush/Stop no longer matters. The README now says the first picture can still be black and that why is not known. 3. **One at a time on Arc.** Not measured; there is no Arc here. The row keeps Side by side one click away. The PR stays WIP until a run on Intel. 4. **The catch-up.** It now uses the recent pictures' decode time (`recent_ns`, about the last 8), not the movie's mean, so a slow first decode no longer turns it off. It decodes ahead at most one picture's time per acquire. `test_video_catchup.py` has the case of a 426 ms first decode followed by fast ones. With a decoder slower than the movie, the picture still falls behind; the README says so. 5. **After a caught fault.** Still untested whether the driver keeps working. A fault making a shader module is now noted in `longshot_driver_faults.txt`, as pipeline faults were, so later starts on that driver leave the program out instead of faulting again. 6. **Every create under the gate.** The 8 compute sources were already gated. `vkGetPipelineCacheData` is now too, through `pcache_data` (all 6 reads), for #190's crash. 7. **#190 and `RX_VK_COMPUTE_SERIAL`.** See the description's "How this relates to other Intel work". In short: the gate goes outside #190's shared lock in every function, or I drop `pcache_data` if #190 lands first. `RX_VK_COMPUTE_SERIAL` still orders the compute jobs, while the gate orders every entry into the compiler; they don't wait on each other. 8. **Splitting.** I can open the movie part (`nn_video.c`, `dav1d_av1.c` and their tests) as its own PR now. Unity's test needs both halves, so I'd rather keep them together until he has run it, unless you want the split first. 9. **WIP.** It stays WIP until it is measured on Intel hardware, Unity's laptop first. Game-free suite at 2bc07a1d: 464 passed, 4 failed, 67 skipped. The 4 failures fail on main too, and #255 fixes them.
docs(readme): the Intel and movie fixes in every section they touch, and an Intel laptops section (Unity's)
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 5s
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
Website / Website on Cloudflare (pull_request) Has been cancelled
9523024ee8
The status table's Intel row and a row for movies on a slow CPU; a below-the-minimum note in What you need (and the website's copy); what longshot_prepare_skipped does in Compile shaders; troubleshooting rows for the igvk64.dll crash, a stopped preparation and a movie behind its sound; the Intel shader compiles row in the menu's list; a new Intel laptops section with Unity's specs, what to set and what to send.

Co-authored-by: Cursor <[email protected]>
Owner

Please test

Please test
HumanBean left a comment

Re-review at 9523024e. Code only: I didn't build it, run the tests or run the game.

I diffed against d906c8f4, the main this branch merged. No shader or *_spv.h header changed, and vk_api.h is untouched. The main commit since then (d9648863) changes other parts of vk_menu.cpp, so it shouldn't conflict.

Earlier points

  1. An ask waits behind a compile. Addressed. cached_graphics, cached_compute and graphics_with only try the gate for a FAIL_ON_PIPELINE_COMPILE_REQUIRED create, and answer cold while it's busy. On Intel the dispatch's module is now made on the worker. I found no path that holds the gate and then takes it again. clear_pipeline and vk_fsr3.cpp let go of it before cached_*, and play_cache_save waits for users before pcache_data takes the gate. That fix has two costs; see new points 1 and 2.
  2. The black first frame. Addressed. The 500 ms wait is gone, dec_acquire's wait is the same as main's, and the README says the black first picture is still unexplained.
  3. A new default with no measurement. Still open. That's expected while the PR is WIP. The Measured box is honestly unticked.
  4. Catch-up drift. Addressed in the code. recent_ns (about the last 8 pictures) replaces the movie's mean, and decoding ahead is capped at one picture's spacing per acquire. A decoder slower than the movie still falls behind without limit, and the README says so. The end-of-movie lag from Unity's HOS_VIDEO_LOG=1 run is part of point 3.
  5. A caught fault can become a hang. Addressed. There's no latch, but the PR says the recovery is untested. A fault in a module create now goes into longshot_driver_faults.txt (driver_faulted_module), and make_module and translate_into check it first.
  6. Not every create is gated. Addressed. The texture, write-back diff, reactive, FSR 3.1 (all three), frame generation, coopmat and temporal creates all use the guarded calls under the gate. vkGetPipelineCacheData goes through pcache_data. The only raw creates left are inside the guards, plus vk_fsr4.cpp's hooks, which never run on Intel.
  7. #190 and RX_VK_COMPUTE_SERIAL. Addressed. The description sets the lock order (the gate outside, #190's shared lock inside) and explains how the gate relates to the serial queue.
  8. One topic. Not addressed. CONTRIBUTING says "two unrelated fixes are two PRs". The dav1d threads and the catch-up change movies on every PC. The gate is for Intel on Windows only. Please split now. Unity can still test both: give him a build of a branch that merges the two PRs, and post one test request that names both.

New

  1. On Intel a prepared compute program loses its first dispatch (inline). Before, compute_pipeline_cached(p, true) on the replay thread got a prepared pipeline at once. Now, on Intel, every program read without its code goes to the serial worker queue. Its first dispatch waits up to 50 ms and is then left out until the worker gets to it, even on a fully prepared cache. Suggestion: make the module on the replay thread under a try-lock, like the asks do, and send it to the worker only when the gate is busy. Otherwise, add this to Risk and count st_pending_skips in the Intel runs.
  2. A cache hit reads as cold while anything holds the gate (inline). With the try-lock, a draw whose pipeline is in pcache or the driver's cache is left out whenever a worker is compiling or a save is in pcache_data. A worker then rebuilds it behind the same gate. Risk says draws are left out "as on a cold cache". On Intel it also hits a prepared cache during any compile or save. Please say so in Risk, and count these answers in the log (for example vk: … asked cold: Intel's gate busy) so the Intel runs can show how often it happens.
  3. One-time creates on the recording thread still wait for the gate (inline on movie_upscale). These are movie_upscale, typed_upscale, mask_stabilize, astc_ready/bc_ready/unswizzle_ready, wbd_pipe_ready, the first masked clear, and gpl_link (behind RX_VK_GPL). Each now waits behind a worker's whole compile. On Unity's laptop the preparation was skipped, so the first movie or the first ASTC texture can stall for as long as a play compile takes. The description says the replay thread "never waits behind a compile", which is true for asks only. Either narrow that sentence and name these in Risk, or make them before play.
  4. Nit, a data race. on_worker reads p.code_words before the CAS. A worker may be clearing that field at the same moment in complete_from. Only the thread that wins the CAS uses the value, so work it out after the CAS.
  5. Nit, README. "On Windows, a PC with 4 logical processors or fewer…" (line 1053): dav1d_av1_threads also applies on Linux, through sysconf. Please also leave Unity's name and his laptop's details out of the README and the website (inline). They fit the PR and the test request better than the user docs.

Verdict

Request changes. Points 1, 2, 4, 5, 6 and 7 are addressed, and the gate's locking looks right to me. Before this is marked ready, it needs the split (point 8), Risk text and log counts for new points 1 to 3, and then the WIP gates:

  • Unity's run and an Arc A/B with several interleaved runs each.
  • The three test requests opened.
  • The Windows/Linux build box.
Re-review at 9523024e. Code only: I didn't build it, run the tests or run the game. I diffed against d906c8f4, the main this branch merged. No shader or `*_spv.h` header changed, and `vk_api.h` is untouched. The main commit since then (d9648863) changes other parts of `vk_menu.cpp`, so it shouldn't conflict. ## Earlier points 1. **An ask waits behind a compile.** Addressed. `cached_graphics`, `cached_compute` and `graphics_with` only try the gate for a `FAIL_ON_PIPELINE_COMPILE_REQUIRED` create, and answer cold while it's busy. On Intel the dispatch's module is now made on the worker. I found no path that holds the gate and then takes it again. `clear_pipeline` and `vk_fsr3.cpp` let go of it before `cached_*`, and `play_cache_save` waits for `users` before `pcache_data` takes the gate. That fix has two costs; see new points 1 and 2. 2. **The black first frame.** Addressed. The 500 ms wait is gone, `dec_acquire`'s wait is the same as main's, and the README says the black first picture is still unexplained. 3. **A new default with no measurement.** Still open. That's expected while the PR is WIP. The Measured box is honestly unticked. 4. **Catch-up drift.** Addressed in the code. `recent_ns` (about the last 8 pictures) replaces the movie's mean, and decoding ahead is capped at one picture's spacing per acquire. A decoder slower than the movie still falls behind without limit, and the README says so. The end-of-movie lag from Unity's `HOS_VIDEO_LOG=1` run is part of point 3. 5. **A caught fault can become a hang.** Addressed. There's no latch, but the PR says the recovery is untested. A fault in a module create now goes into `longshot_driver_faults.txt` (`driver_faulted_module`), and `make_module` and `translate_into` check it first. 6. **Not every create is gated.** Addressed. The texture, write-back diff, reactive, FSR 3.1 (all three), frame generation, coopmat and temporal creates all use the guarded calls under the gate. `vkGetPipelineCacheData` goes through `pcache_data`. The only raw creates left are inside the guards, plus `vk_fsr4.cpp`'s hooks, which never run on Intel. 7. **[#190](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/190) and `RX_VK_COMPUTE_SERIAL`.** Addressed. The description sets the lock order (the gate outside, [#190](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/190)'s shared lock inside) and explains how the gate relates to the serial queue. 8. **One topic.** Not addressed. CONTRIBUTING says "two unrelated fixes are two PRs". The dav1d threads and the catch-up change movies on every PC. The gate is for Intel on Windows only. Please split now. Unity can still test both: give him a build of a branch that merges the two PRs, and post one test request that names both. ## New 1. **On Intel a prepared compute program loses its first dispatch** (inline). Before, `compute_pipeline_cached(p, true)` on the replay thread got a prepared pipeline at once. Now, on Intel, every program read without its code goes to the serial worker queue. Its first dispatch waits up to 50 ms and is then left out until the worker gets to it, even on a fully prepared cache. Suggestion: make the module on the replay thread under a try-lock, like the asks do, and send it to the worker only when the gate is busy. Otherwise, add this to Risk and count `st_pending_skips` in the Intel runs. 2. **A cache hit reads as cold while anything holds the gate** (inline). With the try-lock, a draw whose pipeline is in pcache or the driver's cache is left out whenever a worker is compiling or a save is in `pcache_data`. A worker then rebuilds it behind the same gate. Risk says draws are left out "as on a cold cache". On Intel it also hits a prepared cache during any compile or save. Please say so in Risk, and count these answers in the log (for example `vk: … asked cold: Intel's gate busy`) so the Intel runs can show how often it happens. 3. **One-time creates on the recording thread still wait for the gate** (inline on `movie_upscale`). These are `movie_upscale`, `typed_upscale`, `mask_stabilize`, `astc_ready`/`bc_ready`/`unswizzle_ready`, `wbd_pipe_ready`, the first masked clear, and `gpl_link` (behind `RX_VK_GPL`). Each now waits behind a worker's whole compile. On Unity's laptop the preparation was skipped, so the first movie or the first ASTC texture can stall for as long as a play compile takes. The description says the replay thread "never waits behind a compile", which is true for asks only. Either narrow that sentence and name these in Risk, or make them before play. 4. **Nit, a data race.** `on_worker` reads `p.code_words` before the CAS. A worker may be clearing that field at the same moment in `complete_from`. Only the thread that wins the CAS uses the value, so work it out after the CAS. 5. **Nit, README.** "On Windows, a PC with 4 logical processors or fewer…" (line 1053): `dav1d_av1_threads` also applies on Linux, through `sysconf`. Please also leave Unity's name and his laptop's details out of the README and the website (inline). They fit the PR and the test request better than the user docs. ## Verdict Request changes. Points 1, 2, 4, 5, 6 and 7 are addressed, and the gate's locking looks right to me. Before this is marked ready, it needs the split (point 8), Risk text and log counts for new points 1 to 3, and then the WIP gates: - Unity's run and an Arc A/B with several interleaved runs each. - The three test requests opened. - The Windows/Linux build box.
@ -332,1 +343,4 @@
#### Intel laptops
What [#252](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/252) changes was made from one laptop's logs (Unity's:
Owner

I'd leave a tester's name and laptop details out of the README and the website copy. Describe the kind of PC instead (Intel UHD, a 4-thread CPU, Windows), and keep Unity's specifics in the PR and the test request.

I'd leave a tester's name and laptop details out of the README and the website copy. Describe the kind of PC instead (Intel UHD, a 4-thread CPU, Windows), and keep Unity's specifics in the PR and the test request.
@ -1257,1 +1294,4 @@
bool compiles_nothing(VkPipelineCreateFlags flags) { return (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT) != 0; }
VkResult cached_graphics(const VkGraphicsPipelineCreateInfo* ci, VkPipeline* pl) {
IntelDriverGate gate(compiles_nothing(ci->flags));
if (gate.busy) return VK_PIPELINE_COMPILE_REQUIRED;
Owner

This fixes the wait. But a pipeline that pcache or the driver's cache does have also comes back cold while any worker compiles or a save is in pcache_data. The draw is left out, and a worker then rebuilds it behind the same gate. Please say in Risk that this also happens on a prepared cache, and count these answers (a log line or a counter) so the Intel runs show how often it happens.

This fixes the wait. But a pipeline that pcache or the driver's cache does have also comes back cold while any worker compiles or a save is in `pcache_data`. The draw is left out, and a worker then rebuilds it behind the same gate. Please say in Risk that this also happens on a prepared cache, and count these answers (a log line or a counter) so the Intel runs show how often it happens.
@ -7774,3 +7846,3 @@
mi.codeSize = sizeof MOVIE_UPSCALE_COMP_SPV, mi.pCode = MOVIE_UPSCALE_COMP_SPV;
VkShaderModule m{};
vkCreateShaderModule(dev.device, &mi, nullptr, &m);
IntelDriverGate gate;
Owner

A blocking gate on the thread that records the movie: the first movie_upscale now waits behind a worker's whole compile. The same goes for typed_upscale, mask_stabilize, the texture *_ready functions, wbd_pipe_ready, the first masked clear and gpl_link. On a PC whose preparation was skipped, like Unity's, a play compile can take seconds. Either name these in Risk and narrow the description's "never waits behind a compile" to asks, or make them before play.

A blocking gate on the thread that records the movie: the first `movie_upscale` now waits behind a worker's whole compile. The same goes for `typed_upscale`, `mask_stabilize`, the texture `*_ready` functions, `wbd_pipe_ready`, the first masked clear and `gpl_link`. On a PC whose preparation was skipped, like Unity's, a play compile can take seconds. Either name these in Risk and narrow the description's "never waits behind a compile" to asks, or make them before play.
@ -9610,1 +9685,3 @@
// pipeline. One whose code does not read is failed, and left out below)
// pipeline. One whose code does not read is failed, and left out below. On Windows Intel the module is made on the
// worker instead: here it would wait for the compiler's gate behind a worker's whole compile, IntelDriverGate)
const bool on_worker = p.code_words && intel_gate_on();
Owner

On Windows Intel this sends every program read without its code to the serial worker queue, even when its pipeline is prepared. Main got that pipeline at once through compute_pipeline_cached(p, true). Now the first dispatch waits up to 50 ms and is then left out until the worker gets to it. Could the module be made here under a try-lock (as the asks are), with the worker used only when the gate is busy? Also: p.code_words is read here before the CAS while a worker may be clearing it in complete_from. Work out on_worker after the CAS wins.

On Windows Intel this sends every program read without its code to the serial worker queue, even when its pipeline is prepared. Main got that pipeline at once through `compute_pipeline_cached(p, true)`. Now the first dispatch waits up to 50 ms and is then left out until the worker gets to it. Could the module be made here under a try-lock (as the asks are), with the worker used only when the gate is busy? Also: `p.code_words` is read here before the CAS while a worker may be clearing it in `complete_from`. Work out `on_worker` after the CAS wins.
Author
First-time contributor

Unity sent 7 logs and a bug report from v3.0.0-rc.3 (Intel UHD, driver 101.7088, i3-1115G4, 16 GB, Windows 11). The crash is located now:

  • 5 of the 7 runs closed at igvk64.dll+0x14d102 (read 0x170), all in Kokiri Forest, with the same backtrace: igvk64.dll+0x14d102 +0x134aaf +0x7f23a +0x322ef, then longshot_vk.dll+0x20ccbc, then +0x22375d, then the thread's start.
  • gpu/vk is the same at v3.0.0-rc.3 (0c74253d) and at nightly-70 (dd02c6cc), so I mapped the two longshot_vk.dll addresses with nightly-70's DLL and its symbols:
    • +0x22375d is the std::thread proxy of pipeline_cache_save(bool)::, the background save.
    • +0x20ccbc is the return from callq *(%rdi) in that lambda, right after PipelineCacheFile::writable(pcache_path, n). That call is kGetPipelineCacheData(dev.device, pcache, &n, data), the copy of the whole cache.
  • This GPU writes no play files, so every pipeline built in play goes into pcache while the save copies it. It is the race #190 found on Arc, now on UHD too.

On this branch, all six kGetPipelineCacheData calls go through pcache_data, which takes IntelDriverGate ( est_intel_compiler_gate.py checks that no other call is left). The save then waits for the build in progress, and builds wait for the save. The only read the draw thread can make is pcache_init's, once, when it creates the cache. The gate holds only the driver call, so nothing waits on another lock while holding it.

Every one of the 7 runs also logs he shaders' preparation was skipped at the build, so each built its shaders in play. Unity's test steps in the description start with deleting longshot_prepare_skipped. His report also has ASTC as RGBA8 on, the AMD workaround, which takes shared memory on integrated graphics; the README's Intel laptops section now says to leave it off.

Still untested on Intel: this branch has not been built or run on his laptop.

Unity sent 7 logs and a bug report from v3.0.0-rc.3 (Intel UHD, driver 101.7088, i3-1115G4, 16 GB, Windows 11). The crash is located now: - 5 of the 7 runs closed at igvk64.dll+0x14d102 (read 0x170), all in Kokiri Forest, with the same backtrace: igvk64.dll+0x14d102 +0x134aaf +0x7f23a +0x322ef, then longshot_vk.dll+0x20ccbc, then +0x22375d, then the thread's start. - gpu/vk is the same at v3.0.0-rc.3 (0c74253d) and at nightly-70 (dd02c6cc), so I mapped the two longshot_vk.dll addresses with nightly-70's DLL and its symbols: - +0x22375d is the std::thread proxy of pipeline_cache_save(bool)::, the background save. - +0x20ccbc is the return from callq *(%rdi) in that lambda, right after PipelineCacheFile::writable(pcache_path, n). That call is kGetPipelineCacheData(dev.device, pcache, &n, data), the copy of the whole cache. - This GPU writes no play files, so every pipeline built in play goes into pcache while the save copies it. It is the race #190 found on Arc, now on UHD too. On this branch, all six kGetPipelineCacheData calls go through pcache_data, which takes IntelDriverGate ( est_intel_compiler_gate.py checks that no other call is left). The save then waits for the build in progress, and builds wait for the save. The only read the draw thread can make is pcache_init's, once, when it creates the cache. The gate holds only the driver call, so nothing waits on another lock while holding it. Every one of the 7 runs also logs he shaders' preparation was skipped at the build, so each built its shaders in play. Unity's test steps in the description start with deleting longshot_prepare_skipped. His report also has ASTC as RGBA8 on, the AMD workaround, which takes shared memory on integrated graphics; the README's Intel laptops section now says to leave it off. Still untested on Intel: this branch has not been built or run on his laptop.
docs(readme): Unity's rc.3 crashes were the background pipeline-cache save; leave ASTC as RGBA8 off on integrated graphics
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 / The same as upstream (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 4s
30c7efa344
Co-authored-by: Cursor <[email protected]>
First-time contributor

Code review only; not built or run.

Thanks for the quick turnaround on the first review. HumanBean's re-review covers the gate's lock order, the one-time creates and the split, so I'll stick to the movie half and how it meets #110's input limit. That pairing is what the Steam Deck is testing now: this branch's base has #110 (ae7b1165), so a Deck run of it tests the limit and the new catch-up budget together. The dav1d thread rule doesn't apply on the Deck (8 logical processors), so it isn't part of that test.

1. The budget assumes about one acquire per picture. The catch-up stops decoding ahead once one spacing (16.7 ms) has passed in an acquire. So an acquire decodes at most ceil(spacing / d) pictures ahead, plus decode_pending's one when the queue starts empty. Take the T-BW29 Deck run in #110: the game took about 24 pictures a second of a 60-a-second movie, so each acquire had to advance 2.5.

  • Limit off (d = 6.7 ms): up to 4 pictures an acquire, so the picture holds down to about 15 acquires a second.
  • Limit on (d = 9.6 ms): up to 3 an acquire, so it holds only down to 20 a second. Below that it drifts behind, even though the decoder is faster than the movie.

2. But the budget is also what can end the Deck's freeze. On main the catch-up decodes everything that came due, so the time between acquires is A = B + (A / spacing) × d, that is A = B / (1 − d / spacing), where B is the rest of the loop. That runs away as d nears the spacing.

  • From T-BW29's limit-off run: A ≈ 42 ms at d = 6.7 ms, so B ≈ 25 ms.
  • At d = 9.6 ms, the limit-on mean, A is already about 59 ms.
  • To match the freeze's ~7 acquires a second, each advancing about 6.8 pictures, d would need to be about 14 ms there.

The budget caps the decoding in one acquire at roughly a spacing plus two decodes, so the loop can't run away. A cap of two spacings (33 ms) would keep that bound (under ~55 ms at 9.6 ms). It would also keep the picture in time down to about 12 acquires a second.

How to tell which happened in the Deck runs (HOS_VIDEO_LOG=1):

  • video: N pictures skipped to catch up with the movie's clock with a large N during the freeze means the catch-up's own decoding. That is the case this budget bounds.
  • video: acquire N: nothing decoded means the 100 ms empty wait, which neither PR changes.
  • A run of this branch with HOS_VIDEO_INPUT_LIMIT=0 beside one with the limit on would separate the budget from the limit.

3. The fixture doesn't reach the budget. In test_video_catchup.py, decode_next never advances clock_ns, so hos_now_ns() - now >= spacing is never true, and each case has only one pending submission. A multi-acquire case would pin the budget and its interplay with #110:

  • a 60-a-second movie, acquired every 41.7 ms (24 a second);
  • decodes of 7 and 10 ms;
  • the queue refilled to 16 before each acquire, as the game does under the limit.

It could check that the lag after 10 s stays within a frame or two, and that an acquire's decoding stays bounded.

This applies to the movie half wherever it lands after the split.

Code review only; not built or run. Thanks for the quick turnaround on the first review. HumanBean's re-review covers the gate's lock order, the one-time creates and the split, so I'll stick to the movie half and how it meets #110's input limit. That pairing is what the Steam Deck is testing now: this branch's base has #110 (ae7b1165), so a Deck run of it tests the limit and the new catch-up budget together. The dav1d thread rule doesn't apply on the Deck (8 logical processors), so it isn't part of that test. **1. The budget assumes about one acquire per picture.** The catch-up stops decoding ahead once one spacing (16.7 ms) has passed in an acquire. So an acquire decodes at most ceil(spacing / d) pictures ahead, plus `decode_pending`'s one when the queue starts empty. Take the T-BW29 Deck run in #110: the game took about 24 pictures a second of a 60-a-second movie, so each acquire had to advance 2.5. - **Limit off (d = 6.7 ms):** up to 4 pictures an acquire, so the picture holds down to about 15 acquires a second. - **Limit on (d = 9.6 ms):** up to 3 an acquire, so it holds only down to 20 a second. Below that it drifts behind, even though the decoder is faster than the movie. **2. But the budget is also what can end the Deck's freeze.** On main the catch-up decodes everything that came due, so the time between acquires is A = B + (A / spacing) × d, that is A = B / (1 − d / spacing), where B is the rest of the loop. That runs away as d nears the spacing. - **From T-BW29's limit-off run:** A ≈ 42 ms at d = 6.7 ms, so B ≈ 25 ms. - **At d = 9.6 ms**, the limit-on mean, A is already about 59 ms. - **To match the freeze's ~7 acquires a second**, each advancing about 6.8 pictures, d would need to be about 14 ms there. The budget caps the decoding in one acquire at roughly a spacing plus two decodes, so the loop can't run away. A cap of two spacings (33 ms) would keep that bound (under ~55 ms at 9.6 ms). It would also keep the picture in time down to about 12 acquires a second. **How to tell which happened in the Deck runs (`HOS_VIDEO_LOG=1`):** - `video: N pictures skipped to catch up with the movie's clock` with a large N during the freeze means the catch-up's own decoding. That is the case this budget bounds. - `video: acquire N: nothing decoded` means the 100 ms empty wait, which neither PR changes. - A run of this branch with `HOS_VIDEO_INPUT_LIMIT=0` beside one with the limit on would separate the budget from the limit. **3. The fixture doesn't reach the budget.** In `test_video_catchup.py`, `decode_next` never advances `clock_ns`, so `hos_now_ns() - now >= spacing` is never true, and each case has only one pending submission. A multi-acquire case would pin the budget and its interplay with #110: - a 60-a-second movie, acquired every 41.7 ms (24 a second); - decodes of 7 and 10 ms; - the queue refilled to 16 before each acquire, as the game does under the limit. It could check that the lag after 10 s stays within a frame or two, and that an acquire's decoding stays bounded. This applies to the movie half wherever it lands after the split.
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 / The same as upstream (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 4s
This pull request is marked as a work in progress.
Some workflows are waiting to be reviewed.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'fix/windows-movie-and-intel-compiler:Yeetbot90-fix/windows-movie-and-intel-compiler'
git switch 'Yeetbot90-fix/windows-movie-and-intel-compiler'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 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!252
No description provided.