fix(vk): Intel Windows runtime fixes (pipeline cache saves, alpha to coverage) #2456

Open
hckrman101 wants to merge 6 commits from hckrman101/fix/intel-runtime into main
hckrman101 commented 2026-11-11 19:50:24 +00:00 (Migrated from github.com)

Intel's Windows driver crashes when the pipeline cache is saved while pipelines are being built, and on Intel's integrated GPUs it draws coloured noise on foliage with dynamic alpha to coverage. This PR works around both, on that driver only. Every other driver, NVIDIA's included, runs exactly as before, and nothing in shader translation changes, so players don't need to prepare shaders again.

What changed

Which workarounds a GPU gets is decided once, from its Vulkan properties, in gpu/vk/vk_vendor.h. The log prints the result as one vk: vendor fixes line. Each workaround has an RX_VK_ switch that forces it on or off on any GPU (listed in docs/development.md).

Fix GPUs Switch
Pipeline builds into a pipeline cache are kept apart from the copy of a cache's data when it is saved. Builds take a shared lock and the copy takes it exclusively; this covers pcache and the play files. The file is written after the lock is released. The copy never blocks on the lock. During play, a save tries once, both for pcache and for the play files. One that can't get the lock is put off and kept for the next save, and builds are not held back for it, so the build a draw waits on never waits for a save. A save before play tries for up to 2 s. A forced save (exit, window close, Restart now, the prepare's end) tries for up to 30 s, measured on the clock, for pcache and the play files alike, then logs and skips. Only while a forced copy waits do new builds hold back for it, for at most 1 s, so builds that overlap without a gap can't keep it out. A play generation is written once its builds have ended; that wait is also bounded at 30 s, after which the generation is kept for a later save. So a compile stuck in the driver cannot hang the exit or hold back other builds. On every other driver, no lock is taken. Intel's Windows driver (any Intel GPU) RX_VK_PCACHE_APART=0/1
Alpha to coverage is set in the pipeline instead of as dynamic state (EDS3). The pipeline key already holds it for drivers without the dynamic state. Intel's Windows driver on the GPUs it reports as integrated: UHD, Iris Xe, and the Arc Graphics built into Meteor, Lunar and Arrow Lake processors. Discrete Arc cards and Mesa's ANV are unchanged. RX_VK_DYN_A2C=0/1 (0 turns the fix on)
  • These may address the Intel rows in docs/worklist.md: the access violation in igvk64.dll after the owl intro, and the black screens on Intel. Those rows have no logs yet, so this is not confirmed. An Arc B580 report (discrete) gets the pipeline-cache fix but not the alpha-to-coverage one.
  • The RX_VK_GPL stage libraries (opt-in) need alpha to coverage to be dynamic, so they stay off on the GPUs that get the second fix.
  • Intel's dynamic vertex input problem (from the same totk-pc-recomp commit) does not apply: Hookshot never uses VK_EXT_vertex_input_dynamic_state.
  • Overlap with the AMD/Intel shader translation PR. Both PRs add gpu/vk/vk_vendor.h, the vk: vendor fixes block in vk_main.cpp, its switches row in docs/development.md and tests/test_vendor_fixes.py. Each carries only its own fixes, so either can merge first. Whichever merges second gets a trivial conflict in those four files, resolved by keeping both sets of fields, lines and test rows.

Credit

These are reimplementations in Hookshot's own code, not copies. Their authors are credited in the code comments and in the commit.

Verified on NVIDIA (RTX 3090, Linux, driver 620.70.06)

  • Gates, on made-up devices. The new tests/test_vendor_fixes.py gives 15 sets of device properties to the real vendor_fixes(): NVIDIA on Windows and Linux, NVK, AMD's Windows driver in both branches, RADV, AMDVLK, Intel Windows on integrated and Arc, ANV, and llvmpipe.
    • Each fix turns on only for the GPUs it is meant for. NVIDIA's driver gets none.
    • Every switch forces its fix both ways.
    • The test also checks the wiring. Every build into a pipeline cache goes through the lock. Every read of a cache's data after the start (pcache's and the play files') is inside the copy's gate, and the gate is never a blocking lock. On drivers that don't need it, no lock is taken. Only the start-up merge of the play files reads a cache outside the gate, and no builds run at that point.
  • The save logic. tests/test_pipeline_cache_save.py has two new cases.
    • A save that can't get the lock copies and writes nothing and is tried again. A forced save gets the lock unless a build is stuck, and then gives up after its bounded wait without writing. The lock is never left held.
    • A save during play tries once, a save before play tries for up to 2 s, and a forced save uses the bounded wait. The play files get the forced wait only with a forced save.
    • The existing cases pass too, including main's in-play growth threshold.
  • The play files. tests/test_pipeline_play_cache.py passes with the play files' copy inside the gate. It has two new cases. With a compile stuck in a generation, the save returns after its bound without writing it, and a later save writes it once the compile has ended. A play file's copy tries once in play and gets the forced wait at the window's close and with a forced save. tests/test_vendor_fixes.py also checks the close path and that only forced copies hold builds back.
  • The non-NVIDIA paths, forced on NVIDIA (before the review fixes). One headless run in Kokiri Forest from a save, with RX_VK_PCACHE_APART=1 RX_VK_DYN_A2C=0. It drew 2,434 draws a frame with 0 skipped, at ~49 fps headless. The pipeline cache was saved twice during play through the lock, with no stall, fault or lost device. The picture was normal: foliage, ground haze and characters, nothing missing.
  • Test suite. tests/run_all.py passes, apart from checks that fail on this PC without the change too (no zstandard or tkinter here).

Not tested: please help if you have an Intel GPU on Windows

I have no Intel GPU, so neither fix has been seen working on the hardware it is for. Reports with hookshot_log.txt are very welcome.

  • Any Intel GPU on Windows (Arc or integrated). Does the crash in igvk64.dll or the black screen go away? The log should say pipeline cache saves apart from builds 1. Is there any new stutter when the cache is saved during play? A save that had to wait logs "save put off".
  • UHD or Iris Xe on Windows. Is the coloured noise on branches and foliage (Kokiri Forest, trees) gone? Compare with RX_VK_DYN_A2C=1.
Intel's Windows driver crashes when the pipeline cache is saved while pipelines are being built, and on Intel's integrated GPUs it draws coloured noise on foliage with dynamic alpha to coverage. This PR works around both, on that driver only. Every other driver, NVIDIA's included, runs exactly as before, and nothing in shader translation changes, so players don't need to prepare shaders again. ## What changed Which workarounds a GPU gets is decided once, from its Vulkan properties, in `gpu/vk/vk_vendor.h`. The log prints the result as one `vk: vendor fixes` line. Each workaround has an `RX_VK_` switch that forces it on or off on any GPU (listed in docs/development.md). | Fix | GPUs | Switch | |---|---|---| | Pipeline builds into a pipeline cache are kept apart from the copy of a cache's data when it is saved. Builds take a shared lock and the copy takes it exclusively; this covers pcache and the play files. The file is written after the lock is released. The copy never blocks on the lock. During play, a save tries once, both for pcache and for the play files. One that can't get the lock is put off and kept for the next save, and builds are not held back for it, so the build a draw waits on never waits for a save. A save before play tries for up to 2 s. A forced save (exit, window close, Restart now, the prepare's end) tries for up to 30 s, measured on the clock, for pcache and the play files alike, then logs and skips. Only while a forced copy waits do new builds hold back for it, for at most 1 s, so builds that overlap without a gap can't keep it out. A play generation is written once its builds have ended; that wait is also bounded at 30 s, after which the generation is kept for a later save. So a compile stuck in the driver cannot hang the exit or hold back other builds. On every other driver, no lock is taken. | Intel's Windows driver (any Intel GPU) | `RX_VK_PCACHE_APART=0/1` | | Alpha to coverage is set in the pipeline instead of as dynamic state (EDS3). The pipeline key already holds it for drivers without the dynamic state. | Intel's Windows driver on the GPUs it reports as integrated: UHD, Iris Xe, and the Arc Graphics built into Meteor, Lunar and Arrow Lake processors. Discrete Arc cards and Mesa's ANV are unchanged. | `RX_VK_DYN_A2C=0/1` (`0` turns the fix on) | - These **may** address the Intel rows in docs/worklist.md: the access violation in `igvk64.dll` after the owl intro, and the black screens on Intel. Those rows have no logs yet, so this is not confirmed. An Arc B580 report (discrete) gets the pipeline-cache fix but not the alpha-to-coverage one. - The `RX_VK_GPL` stage libraries (opt-in) need alpha to coverage to be dynamic, so they stay off on the GPUs that get the second fix. - Intel's dynamic vertex input problem (from the same totk-pc-recomp commit) does not apply: Hookshot never uses `VK_EXT_vertex_input_dynamic_state`. - **Overlap with the AMD/Intel shader translation PR.** Both PRs add `gpu/vk/vk_vendor.h`, the `vk: vendor fixes` block in vk_main.cpp, its switches row in docs/development.md and `tests/test_vendor_fixes.py`. Each carries only its own fixes, so either can merge first. Whichever merges second gets a trivial conflict in those four files, resolved by keeping both sets of fields, lines and test rows. ## Credit - **Pipeline cache kept apart from builds.** Found by [totk-pc-recomp b358b8f1f1](https://github.com/valentderah/totk-pc-recomp/commit/b358b8f1f1) (itaskaev2, MIT) and [Eglantine db093d7325](https://github.com/Eglantine-Community/Eglantine/commit/db093d7325) (kraibse, GPL-3.0). The lock design follows totk-pc-recomp. - **Static alpha to coverage on Intel integrated GPUs.** From [totk-pc-recomp 905e2e720d](https://github.com/valentderah/totk-pc-recomp/commit/905e2e720d) (Valiantsin Dzerakh, MIT), where players confirmed the setting cleared the noise. These are reimplementations in Hookshot's own code, not copies. Their authors are credited in the code comments and in the commit. ## Verified on NVIDIA (RTX 3090, Linux, driver 620.70.06) - **Gates, on made-up devices.** The new `tests/test_vendor_fixes.py` gives 15 sets of device properties to the real `vendor_fixes()`: NVIDIA on Windows and Linux, NVK, AMD's Windows driver in both branches, RADV, AMDVLK, Intel Windows on integrated and Arc, ANV, and llvmpipe. - Each fix turns on only for the GPUs it is meant for. NVIDIA's driver gets none. - Every switch forces its fix both ways. - The test also checks the wiring. Every build into a pipeline cache goes through the lock. Every read of a cache's data after the start (pcache's and the play files') is inside the copy's gate, and the gate is never a blocking lock. On drivers that don't need it, no lock is taken. Only the start-up merge of the play files reads a cache outside the gate, and no builds run at that point. - **The save logic.** `tests/test_pipeline_cache_save.py` has two new cases. - A save that can't get the lock copies and writes nothing and is tried again. A forced save gets the lock unless a build is stuck, and then gives up after its bounded wait without writing. The lock is never left held. - A save during play tries once, a save before play tries for up to 2 s, and a forced save uses the bounded wait. The play files get the forced wait only with a forced save. - The existing cases pass too, including main's in-play growth threshold. - **The play files.** `tests/test_pipeline_play_cache.py` passes with the play files' copy inside the gate. It has two new cases. With a compile stuck in a generation, the save returns after its bound without writing it, and a later save writes it once the compile has ended. A play file's copy tries once in play and gets the forced wait at the window's close and with a forced save. `tests/test_vendor_fixes.py` also checks the close path and that only forced copies hold builds back. - **The non-NVIDIA paths, forced on NVIDIA** (before the review fixes). One headless run in Kokiri Forest from a save, with `RX_VK_PCACHE_APART=1 RX_VK_DYN_A2C=0`. It drew 2,434 draws a frame with 0 skipped, at ~49 fps headless. The pipeline cache was saved twice during play through the lock, with no stall, fault or lost device. The picture was normal: foliage, ground haze and characters, nothing missing. - **Test suite.** `tests/run_all.py` passes, apart from checks that fail on this PC without the change too (no `zstandard` or `tkinter` here). ## Not tested: please help if you have an Intel GPU on Windows I have no Intel GPU, so neither fix has been seen working on the hardware it is for. Reports with `hookshot_log.txt` are very welcome. - **Any Intel GPU on Windows (Arc or integrated).** Does the crash in `igvk64.dll` or the black screen go away? The log should say `pipeline cache saves apart from builds 1`. Is there any new stutter when the cache is saved during play? A save that had to wait logs "save put off". - **UHD or Iris Xe on Windows.** Is the coloured noise on branches and foliage (Kokiri Forest, trees) gone? Compare with `RX_VK_DYN_A2C=1`.
Andrade2244 commented 2026-11-11 22:11:53 +00:00 (Migrated from github.com)

I will try to build the pr #2456 and will report back. I'm using the Intel Arc 7 cores + Intel Core Ultra 5 125h and there are a lot of issues. Managed to get to in game and saved the game but now it always crashes from that point. I have to use an older driver ( 31.0.101.5334 ), thats the only one that works.

I will try to build the pr #2456 and will report back. I'm using the Intel Arc 7 cores + Intel Core Ultra 5 125h and there are a lot of issues. Managed to get to in game and saved the game but now it always crashes from that point. I have to use an older driver ( 31.0.101.5334 ), thats the only one that works.
hckrman101 (Migrated from github.com) reviewed 2026-11-11 22:19:03 +00:00
hckrman101 (Migrated from github.com) left a comment

Read through the whole change. The gating looks right to me: every build that takes a cache goes through apart_graphics / apart_compute (no nested shared lock, since create_cached calls create one at a time), every vkGetPipelineCacheData after start-up is inside the gate, the gate only ever uses try_lock, so a stuck compile can't wedge a writer-preferring shared_mutex, and the SEH-caught driver faults return through apart_*, so the shared lock is always released. On non-Intel drivers both cache_use_begin and cache_copy_begin return before touching the lock, so NVIDIA/AMD behave exactly as before. The static A2C side is also sound: the feature bit is cleared before vkCreateDevice, and with eds3_a2c false the pipeline key, alphaToCoverageEnable and the dynamic-state list already handle it, and gpl_wanted drops GPL as described. Bounding the old unbounded users drain in play_cache_save is a nice side fix too.

CI is green and the branch merges cleanly with main.

Two things worth a look, neither blocking:

  1. Play-file copies in play wait 2 s, not one try. play_file_write always uses kCopyWaitStart, and it runs on the save thread during play. While it waits, copy_pending makes every new build wait up to 1 s in cache_use_begin, and that includes the build a draw is waiting on. So on Intel a long compile in flight can cost a visible hitch of up to 1 s at a save point. The description says "A save during play tries once", which only holds for pcache. Maybe a single try for play files in play too (the generation is kept and retried anyway), or skip the hold-back when the copy's own wait is short? At least worth asking Intel testers to watch for it, as the description already does.
  2. At the window's close (pipeline_cache_close -> play_cache_save), the play file also only gets 2 s, not the 30 s a forced save gets. If builds are still running then, this run's last generation is dropped. It's minor (it gets recompiled next run), but it doesn't quite match the description's "a forced save (exit ...) tries for up to 30 s".

Nit: create_device now queries VkPhysicalDeviceDriverProperties twice (the new block and the subgroup block, which sets dev.driver_id). One query could feed both.

@Andrade2244, thanks for offering to test. Your Core Ultra 5 125H (Meteor Lake Arc Graphics) is reported as integrated, so it should get both fixes. If you can, please attach hookshot_log.txt from a run on the current driver. The vk: vendor fixes line will show what was applied, and the log should also show whether the crash after your save is still the igvk64.dll one.

Read through the whole change. The gating looks right to me: every build that takes a cache goes through `apart_graphics` / `apart_compute` (no nested shared lock, since `create_cached` calls `create` one at a time), every `vkGetPipelineCacheData` after start-up is inside the gate, the gate only ever uses `try_lock`, so a stuck compile can't wedge a writer-preferring `shared_mutex`, and the SEH-caught driver faults return through `apart_*`, so the shared lock is always released. On non-Intel drivers both `cache_use_begin` and `cache_copy_begin` return before touching the lock, so NVIDIA/AMD behave exactly as before. The static A2C side is also sound: the feature bit is cleared before `vkCreateDevice`, and with `eds3_a2c` false the pipeline key, `alphaToCoverageEnable` and the dynamic-state list already handle it, and `gpl_wanted` drops GPL as described. Bounding the old unbounded `users` drain in `play_cache_save` is a nice side fix too. CI is green and the branch merges cleanly with main. Two things worth a look, neither blocking: 1. **Play-file copies in play wait 2 s, not one try.** `play_file_write` always uses `kCopyWaitStart`, and it runs on the save thread during play. While it waits, `copy_pending` makes every new build wait up to 1 s in `cache_use_begin`, and that includes the build a draw is waiting on. So on Intel a long compile in flight can cost a visible hitch of up to 1 s at a save point. The description says "A save during play tries once", which only holds for pcache. Maybe a single try for play files in play too (the generation is kept and retried anyway), or skip the hold-back when the copy's own wait is short? At least worth asking Intel testers to watch for it, as the description already does. 2. **At the window's close** (`pipeline_cache_close` -> `play_cache_save`), the play file also only gets 2 s, not the 30 s a forced save gets. If builds are still running then, this run's last generation is dropped. It's minor (it gets recompiled next run), but it doesn't quite match the description's "a forced save (exit ...) tries for up to 30 s". Nit: `create_device` now queries `VkPhysicalDeviceDriverProperties` twice (the new block and the subgroup block, which sets `dev.driver_id`). One query could feed both. @Andrade2244, thanks for offering to test. Your Core Ultra 5 125H (Meteor Lake Arc Graphics) is reported as integrated, so it should get both fixes. If you can, please attach `hookshot_log.txt` from a run on the current driver. The `vk: vendor fixes` line will show what was applied, and the log should also show whether the crash after your save is still the `igvk64.dll` one.
hckrman101 (Migrated from github.com) commented 2026-11-11 22:19:03 +00:00

This runs in play too (from the save thread via play_cache_save), so play files get the 2 s wait plus the copy_pending hold-back on builds, unlike pcache's single try in play. See point 1 in the review body.

This runs in play too (from the save thread via `play_cache_save`), so play files get the 2 s wait plus the `copy_pending` hold-back on builds, unlike pcache's single try in play. See point 1 in the review body.
hckrman101 (Migrated from github.com) commented 2026-11-11 22:19:03 +00:00

This hold-back also applies to the replay thread's draw-time builds. If an in-flight compile keeps the copy waiting, a draw can stall here for up to 1 s. That's bounded and Intel-only, but it might show up as a hitch at save points.

This hold-back also applies to the replay thread's draw-time builds. If an in-flight compile keeps the copy waiting, a draw can stall here for up to 1 s. That's bounded and Intel-only, but it might show up as a hitch at save points.
Andrade2244 commented 2026-11-11 22:45:59 +00:00 (Migrated from github.com)

@hckrman101 Glad to help. I will attach the log.

The logs on the latest release version showed "VK_ERROR_DEVICE_LOST" crash. I had a igvk64.dll related crash on the latest drivers (32.0.101.9175) but it was even before reaching the main menu. For some reason, on this setup, the only drivers that seem to work when using vulkan are the ones i have mentioned ( for other games/ports as well ).

@hckrman101 Glad to help. I will attach the log. The logs on the latest release version showed "VK_ERROR_DEVICE_LOST" crash. I had a igvk64.dll related crash on the latest drivers (32.0.101.9175) but it was even before reaching the main menu. For some reason, on this setup, the only drivers that seem to work when using vulkan are the ones i have mentioned ( for other games/ports as well ).
Andrade2244 commented 2026-11-12 00:45:49 +00:00 (Migrated from github.com)

I've tested the build and attached the log. It still crashes in the igvk64.dll. It dosent crash immediately like the latest release build tho. Its possible to run it for a while until it eventually crashes.
hookshot_log.2.txt
Hookshot 11_12_2026 12_17_01 AM

I've tested the build and attached the log. It still crashes in the igvk64.dll. It dosent crash immediately like the latest release build tho. Its possible to run it for a while until it eventually crashes. [hookshot_log.2.txt](https://github.com/user-attachments/files/34721454/hookshot_log.2.txt) <img width="1600" height="900" alt="Hookshot 11_12_2026 12_17_01 AM" src="https://github.com/user-attachments/assets/5c65f4d9-750c-48f4-b0cf-1c11d6106f49" />
Arkex-ai commented 2026-11-12 01:52:51 +00:00 (Migrated from github.com)

I'm investigating a related memory peak from #2206: pcache_file_read, play_file_write and full base-cache saves still allocate whole-cache vectors. Is anyone already covering file-backed mapped I/O for these paths?

The scope would preserve the warm cache, existing file format, play-generation policy and atomic replacement. Your bounded Intel copy/build separation would remain authoritative: prepare the file view before the copy lock, keep the lock around the driver copy, then flush/publish after release. Page faults and flush costs need measurement; mapping alone is not a speedup claim. No production edits yet.

I'm investigating a related memory peak from #2206: `pcache_file_read`, `play_file_write` and full base-cache saves still allocate whole-cache vectors. Is anyone already covering file-backed mapped I/O for these paths? The scope would preserve the warm cache, existing file format, play-generation policy and atomic replacement. Your bounded Intel copy/build separation would remain authoritative: prepare the file view before the copy lock, keep the lock around the driver copy, then flush/publish after release. Page faults and flush costs need measurement; mapping alone is not a speedup claim. No production edits yet.
Owner

@dankman42 commented on GitHub · 2026-11-12 13:20 UTC · original

Test request T-4RXC: mixed (the crash is gone; rendering on this iGPU is still unreliable)

Hardware: Intel UHD Graphics 770 (the i9-12900K's iGPU, RX_VK_DEVICE=1; mesh shaders no), Intel driver 32.0.101.7088 (101.7088 in the log), 64 GB RAM, Windows 11. An RTX 3080 is device 0 and drives the display. Built ef1ec66c (the PR head) and main 51da0464, both standalone from source with llvm-mingw, default options, 1280x720 window.

What I checked: whether the igvk64.dll crash goes away, and the foliage with and without the alpha-to-coverage fix. Each run: load the same save (adult, Kakariko), press A into play, teleport to Kokiri Forest, wait 60 s, take three hookshot_ctl.py shots 10 s apart, then hookshot_ctl.py quit. Runs alternated main and PR.

run result
main 1 the teleport was refused (a cutscene was playing), stayed in Kakariko; crashed 23 s later
main 2, 3, 4 crashed during or right after the teleport's load
PR 1 the teleport was refused, stayed in Kakariko; 2 min in play, quit cleanly
PR 2, 3 in Kokiri Forest 60 s+, quit cleanly
PR with RX_VK_DYN_A2C=1 in Kokiri Forest 60 s+, quit cleanly

All four main crashes are the same in the Windows event log:

Faulting module name: igvk64.dll, version: 32.0.101.7088
Exception code: 0xc0000005
Fault offset: 0x000000000014d102

The game's log just stops, with no message.

On the PR the log names the fix, and each run put off 2 to 4 saves at exactly the moments that would have overlapped builds:

vk: vendor fixes for Intel Corporation (101.7088): pipeline cache saves apart from builds 1, static alpha to coverage 1, out-of-bounds texel fetches 0 1, NaN tests by bits 0, gather offset 1
vk: pipeline cache save put off: pipelines were being built (tried again at the next save; 1 so far)
vk: pipeline cache save put off: pipelines were being built (tried again at the next save; 2 so far)

With RX_VK_DYN_A2C=1 the line reads static alpha to coverage 0. Main's crashes all came in the minutes when pipelines were being built for this GPU (first visits), which fits the description's cause. I did not catch a crash inside a save itself.

Pictures (from shot; I can't attach images from here, so these are descriptions; ask if you want the PNGs):

  • Kakariko, 10 s into play: normal on both main and the PR.

  • Kokiri Forest, PR (static alpha to coverage), two runs:

    • no coloured noise;
    • the grass and bushes are drawn as dense, coarse, blocky clumps that cover the ground and the roots.
  • Kokiri Forest, PR with RX_VK_DYN_A2C=1, one run:

    • no coloured noise either;
    • the grass is thin and the roots and moss look smoother;
    • a large white shape is drawn above Link's head.

    So on this UHD 770 and driver, in the one place I looked, I could not reproduce the noise the static setting is meant to clear, and the static setting looked coarser. One run each, so that is weak evidence.

  • In 2 of the 4 PR runs (the first two after building), the picture was badly wrong for the whole minute:

    • PR 1 in Kakariko: sky and ground in false colours (purple, yellow and magenta blocks), with Link and the houses nearly black;
    • PR 2 in Kokiri: almost all black, with only neon-coloured outlines of branches.

    PR 3 and the RX_VK_DYN_A2C=1 run in the same places looked normal. Main crashed before it got that far, so I can't say whether this comes from the PR. It is more likely the Intel driver's first pipeline builds on this GPU, or the worklist's "Entire world is broken" Intel report, but that is a guess.

Speed, for scale: 6.9-17.5 fps in Kokiri at 1280x720.

Not tested: Arc (discrete), Iris Xe, a forced save at window close while a build is stuck, and long play. Worklist: the igvk64.dll access violation row (0.11, an i3-1115G4 UHD report) now has a reproduction with a log on a UHD 770, 4 of 4 on main.

> [@dankman42](https://github.com/dankman42) commented on GitHub · 2026-11-12 13:20 UTC · [original](https://github.com/NotRexed/Hookshot/pull/2456#issuecomment-6824750417) Test request T-4RXC: mixed (the crash is gone; rendering on this iGPU is still unreliable) Hardware: Intel UHD Graphics 770 (the i9-12900K's iGPU, `RX_VK_DEVICE=1`; mesh shaders no), Intel driver 32.0.101.7088 (`101.7088` in the log), 64 GB RAM, Windows 11. An RTX 3080 is device 0 and drives the display. Built ef1ec66c (the PR head) and main 51da0464, both standalone from source with llvm-mingw, default options, 1280x720 window. **What I checked:** whether the `igvk64.dll` crash goes away, and the foliage with and without the alpha-to-coverage fix. Each run: load the same save (adult, Kakariko), press A into play, teleport to Kokiri Forest, wait 60 s, take three `hookshot_ctl.py shot`s 10 s apart, then `hookshot_ctl.py quit`. Runs alternated main and PR. | run | result | |---|---| | main 1 | the teleport was refused (a cutscene was playing), stayed in Kakariko; crashed 23 s later | | main 2, 3, 4 | crashed during or right after the teleport's load | | PR 1 | the teleport was refused, stayed in Kakariko; 2 min in play, quit cleanly | | PR 2, 3 | in Kokiri Forest 60 s+, quit cleanly | | PR with `RX_VK_DYN_A2C=1` | in Kokiri Forest 60 s+, quit cleanly | All four main crashes are the same in the Windows event log: ``` Faulting module name: igvk64.dll, version: 32.0.101.7088 Exception code: 0xc0000005 Fault offset: 0x000000000014d102 ``` The game's log just stops, with no message. On the PR the log names the fix, and each run put off 2 to 4 saves at exactly the moments that would have overlapped builds: ``` vk: vendor fixes for Intel Corporation (101.7088): pipeline cache saves apart from builds 1, static alpha to coverage 1, out-of-bounds texel fetches 0 1, NaN tests by bits 0, gather offset 1 vk: pipeline cache save put off: pipelines were being built (tried again at the next save; 1 so far) vk: pipeline cache save put off: pipelines were being built (tried again at the next save; 2 so far) ``` With `RX_VK_DYN_A2C=1` the line reads `static alpha to coverage 0`. Main's crashes all came in the minutes when pipelines were being built for this GPU (first visits), which fits the description's cause. I did not catch a crash inside a save itself. **Pictures** (from `shot`; I can't attach images from here, so these are descriptions; ask if you want the PNGs): - **Kakariko, 10 s into play:** normal on both main and the PR. - **Kokiri Forest, PR (static alpha to coverage), two runs:** - no coloured noise; - the grass and bushes are drawn as dense, coarse, blocky clumps that cover the ground and the roots. - **Kokiri Forest, PR with `RX_VK_DYN_A2C=1`, one run:** - no coloured noise either; - the grass is thin and the roots and moss look smoother; - a large white shape is drawn above Link's head. So on this UHD 770 and driver, in the one place I looked, I could not reproduce the noise the static setting is meant to clear, and the static setting looked coarser. One run each, so that is weak evidence. - **In 2 of the 4 PR runs (the first two after building), the picture was badly wrong for the whole minute:** - PR 1 in Kakariko: sky and ground in false colours (purple, yellow and magenta blocks), with Link and the houses nearly black; - PR 2 in Kokiri: almost all black, with only neon-coloured outlines of branches. PR 3 and the `RX_VK_DYN_A2C=1` run in the same places looked normal. Main crashed before it got that far, so I can't say whether this comes from the PR. It is more likely the Intel driver's first pipeline builds on this GPU, or the worklist's "Entire world is broken" Intel report, but that is a guess. Speed, for scale: 6.9-17.5 fps in Kokiri at 1280x720. **Not tested:** Arc (discrete), Iris Xe, a forced save at window close while a build is stuck, and long play. Worklist: the `igvk64.dll` access violation row (0.11, an i3-1115G4 UHD report) now has a reproduction with a log on a UHD 770, 4 of 4 on main. <!-- github-sync:c:6824750417 -->
Owner

@dankman42 commented on GitHub · 2026-11-12 13:41 UTC · original

Follow-up to T-4RXC above: six more runs of the PR head ef1ec66c on the same UHD 770, the same route (Kakariko save, teleport to Kokiri Forest, three shots, quit).

  • Crash: none in the six, so the PR is at 0 of 10 runs, against main's 4 of 4 at igvk64.dll+0x14d102. Each run still logs 2 put-off saves.
  • The broken picture did not come back. Four runs with the caches as the earlier runs left them, and two with every cache file moved aside first (hookshot_programs.bin, hookshot_pipelines.bin, hookshot_pipeline_states.bin, hookshot_computes.bin, mkw_vk_pipelines*.bin; the log shows 0 program keys kept and pipeline cache ... (0 KB)). All six drew Kakariko and Kokiri normally, the same as the third run above.
  • So the false colours and the black-with-neon frames were in 2 of 10 runs, the first two after building. They are not explained by empty caches, and I found nothing in the logs that sets those two apart: the same 11 not translated: a network left out on this card lines are in every run. Main can't be compared, because it crashes first. I'd treat it as a separate, intermittent Intel problem, not as something this PR causes; but it's unexplained.
> [@dankman42](https://github.com/dankman42) commented on GitHub · 2026-11-12 13:41 UTC · [original](https://github.com/NotRexed/Hookshot/pull/2456#issuecomment-6825218974) Follow-up to T-4RXC above: six more runs of the PR head ef1ec66c on the same UHD 770, the same route (Kakariko save, teleport to Kokiri Forest, three shots, quit). - **Crash:** none in the six, so the PR is at 0 of 10 runs, against main's 4 of 4 at `igvk64.dll`+0x14d102. Each run still logs 2 put-off saves. - **The broken picture did not come back.** Four runs with the caches as the earlier runs left them, and two with every cache file moved aside first (`hookshot_programs.bin`, `hookshot_pipelines.bin`, `hookshot_pipeline_states.bin`, `hookshot_computes.bin`, `mkw_vk_pipelines*.bin`; the log shows `0 program keys kept` and `pipeline cache ... (0 KB)`). All six drew Kakariko and Kokiri normally, the same as the third run above. - So the false colours and the black-with-neon frames were in 2 of 10 runs, the first two after building. They are not explained by empty caches, and I found nothing in the logs that sets those two apart: the same 11 `not translated: a network left out on this card` lines are in every run. Main can't be compared, because it crashes first. I'd treat it as a separate, intermittent Intel problem, not as something this PR causes; but it's unexplained. <!-- github-sync:c:6825218974 -->
Owner

@Joey-Magnus reviewed on GitHub · 2026-11-12 14:32 UTC · original

The pipeline-cache half now has evidence: dankman42's UHD 770 crashed in igvk64.dll 4 of 4 times on main and 0 of 10 on this head, with saves put off exactly where builds overlapped. 0edc360c also covers the play-file waits raised in review.

It conflicts with main in gpu/vk/vk_main.cpp only: main added dev.radv_gcn = drv.driverID == ... in the subgroup block, where this PR drops the drv query. Resolving it with dev.driver_id makes tests/test_fallback_size_policy.py fail, since it looks for that exact line, so the rebase needs that test updated. With that, test_vendor_fixes.py, test_pipeline_cache_save.py, test_pipeline_play_cache.py and test_env_on.py pass.

Static alpha to coverage is less clear. On the UHD 770 the noise didn't show with dynamic A2C either, and static A2C drew grass as coarse, blocky clumps, while RX_VK_DYN_A2C=1 looked finer. One GPU and one place, but the only report. I'd ship the cache fix and hold static A2C until an Iris Xe or Meteor Lake report shows the noise going away, or split it out.

> [@Joey-Magnus](https://github.com/Joey-Magnus) reviewed on GitHub · 2026-11-12 14:32 UTC · [original](https://github.com/NotRexed/Hookshot/pull/2456#pullrequestreview-5876212683) The pipeline-cache half now has evidence: dankman42's UHD 770 crashed in `igvk64.dll` 4 of 4 times on main and 0 of 10 on this head, with saves put off exactly where builds overlapped. 0edc360c also covers the play-file waits raised in review. It conflicts with main in `gpu/vk/vk_main.cpp` only: main added `dev.radv_gcn = drv.driverID == ...` in the subgroup block, where this PR drops the `drv` query. Resolving it with `dev.driver_id` makes `tests/test_fallback_size_policy.py` fail, since it looks for that exact line, so the rebase needs that test updated. With that, `test_vendor_fixes.py`, `test_pipeline_cache_save.py`, `test_pipeline_play_cache.py` and `test_env_on.py` pass. Static alpha to coverage is less clear. On the UHD 770 the noise didn't show with dynamic A2C either, and static A2C drew grass as coarse, blocky clumps, while `RX_VK_DYN_A2C=1` looked finer. One GPU and one place, but the only report. I'd ship the cache fix and hold static A2C until an Iris Xe or Meteor Lake report shows the noise going away, or split it out. <!-- github-sync:r:5876212683 -->
Commenting is not possible because the repository is archived.
No description provided.