fix(linux): make the folder __GL_SHADER_DISK_CACHE_PATH names, or NVIDIA keeps no shader cache #2363

Merged
hckrman101 merged 2 commits from fix/keep-driver-cache into main 2026-11-11 16:42:13 +00:00
hckrman101 commented 2026-11-11 16:04:48 +00:00 (Migrated from github.com)

Title: fix(linux): make the folder __GL_SHADER_DISK_CACHE_PATH names, or NVIDIA keeps no shader cache

When a player or a launcher points NVIDIA's shader cache at a folder that does not exist yet, the Linux driver keeps no cache at all, so every start compiles every pipeline again. The game now creates that folder before Vulkan loads.

What changed

  • host/hos_main.c: driver_cache_folder(), called right after driver_cache_room() in the Linux main and before the window. If __GL_SHADER_DISK_CACHE_PATH is set, it creates the folder and any missing parent folders. If it can't, it prints one line saying the driver will keep no shader cache. A value the player set is never changed, only created.
  • tests/test_driver_cache_folder.py: compiles the function out of hos_main.c and runs it on a missing nested path, an existing one, a trailing slash, a double slash, a path under a regular file (it reports the error and doesn't crash) and an empty value. It also checks that main calls it before the window, and that the Linux game file is still named hookshot (see below).
  • tests/display_startup_failure_test.cpp: an empty stub for the new call, next to the driver_cache_room one.

Mesa needs nothing: it creates MESA_SHADER_CACHE_DIR itself, including missing parents (checked with lavapipe and Mesa 26.2.6).

Why updates don't lose the cache (checked while looking for this)

The question was whether players lose the driver's compiled pipelines when they update Hookshot or move the game folder. On Linux with NVIDIA they don't:

  • NVIDIA files its cache by the program's file name alone. On disk that is GLCache/<id>/<driver>/<hash of the name>.toc/.bin. For hookshot the file is the same one in every Hookshot folder on the PC.
  • Test program, 300 graphics pipelines and 300 compute pipelines, private cache folder, driver 620.70.06, RTX 3090. Cold: 7.3 ms per pipeline (graphics). After a first run filled the cache: 0.06 ms. These all still hit at 0.06-0.07 ms:
    • the program replaced in place (new bytes, same file or a new file renamed over it, which is how a rebuild writes it)
    • a changed date
    • a copy at another path
    • another path with new bytes
    • a different VkApplicationInfo application name or version, or an added engine name and version
  • Only renaming the program misses (hookshot-v2: 7.1 ms, a second cache file). Setting __GL_SHADER_DISK_CACHE_APP_NAME would get around that, but it would also rename the cache file every player has now. So it isn't set. The new check keeps the Linux game named hookshot instead.
  • The game itself, on a prepared folder with an empty private driver cache (RX_VK_PREPARE_AGAIN=1):
    • first run: 830.7 s. The predicted pipelines took 429.5 s and the precompile 373 s.
    • the same folder copied to another path, with bin/hookshot replaced by a file with different bytes, as an update does: 51.0 s. Predicted 14.2 s, precompile 14.6 s.
    • Both runs used one driver cache file, 1.9 GB.
  • Hookshot's own pipeline cache (mkw_vk_pipelines.bin) is checked against the vendor, the device and the driver's pipelineCacheUUID. It is not checked against Hookshot's version or path, so it stays valid across updates: 300 of 300 pipelines were found in it with the program replaced and moved. A cache from another driver or GPU is still dropped.

What does start the driver cache over: a driver update (expected: the driver drops its own cache), the cache's size limit (raised to 10 GiB on Linux already) and the case this PR fixes.

Tested

  • Linux, RTX 3090, driver 620.70.06. Without the fix (test program), with the cache path set to a missing folder: 7.9 ms per pipeline at the first start and again at the second, and nothing written anywhere. With the fix, the game (--prepare-shaders, __GL_SHADER_DISK_CACHE_PATH set to a missing two-level-deep folder) created the folder, and NVIDIA's cache filled it (35 MB within seconds). Nothing went to ~/.cache.
  • tests/test_driver_cache_folder.py, tests/test_driver_cache_room.py and tests/test_display_startup_failure.py pass. tests/run_all.py on Linux: 358 passed and 4 failed, none of them from this change. Two need zstandard and one needs Tk, which this PC's Python doesn't have. The fourth is test_wayland_libdecor_hint.py, where a newer clang's -Wunused-but-set-global fires on that test's own harness.

Not tested: Windows. Its NVIDIA cache (DXCache/GLCache under LocalAppData) wasn't checked, and this change is Linux-only.

Title: fix(linux): make the folder __GL_SHADER_DISK_CACHE_PATH names, or NVIDIA keeps no shader cache When a player or a launcher points NVIDIA's shader cache at a folder that does not exist yet, the Linux driver keeps no cache at all, so every start compiles every pipeline again. The game now creates that folder before Vulkan loads. ## What changed - `host/hos_main.c`: `driver_cache_folder()`, called right after `driver_cache_room()` in the Linux main and before the window. If `__GL_SHADER_DISK_CACHE_PATH` is set, it creates the folder and any missing parent folders. If it can't, it prints one line saying the driver will keep no shader cache. A value the player set is never changed, only created. - `tests/test_driver_cache_folder.py`: compiles the function out of `hos_main.c` and runs it on a missing nested path, an existing one, a trailing slash, a double slash, a path under a regular file (it reports the error and doesn't crash) and an empty value. It also checks that main calls it before the window, and that the Linux game file is still named `hookshot` (see below). - `tests/display_startup_failure_test.cpp`: an empty stub for the new call, next to the `driver_cache_room` one. Mesa needs nothing: it creates `MESA_SHADER_CACHE_DIR` itself, including missing parents (checked with lavapipe and Mesa 26.2.6). ## Why updates don't lose the cache (checked while looking for this) The question was whether players lose the driver's compiled pipelines when they update Hookshot or move the game folder. On Linux with NVIDIA they don't: - NVIDIA files its cache by the program's file name alone. On disk that is `GLCache/<id>/<driver>/<hash of the name>.toc/.bin`. For `hookshot` the file is the same one in every Hookshot folder on the PC. - Test program, 300 graphics pipelines and 300 compute pipelines, private cache folder, driver 620.70.06, RTX 3090. Cold: 7.3 ms per pipeline (graphics). After a first run filled the cache: 0.06 ms. These all still hit at 0.06-0.07 ms: - the program replaced in place (new bytes, same file or a new file renamed over it, which is how a rebuild writes it) - a changed date - a copy at another path - another path with new bytes - a different `VkApplicationInfo` application name or version, or an added engine name and version - Only renaming the program misses (`hookshot-v2`: 7.1 ms, a second cache file). Setting `__GL_SHADER_DISK_CACHE_APP_NAME` would get around that, but it would also rename the cache file every player has now. So it isn't set. The new check keeps the Linux game named `hookshot` instead. - The game itself, on a prepared folder with an empty private driver cache (`RX_VK_PREPARE_AGAIN=1`): - first run: 830.7 s. The predicted pipelines took 429.5 s and the precompile 373 s. - the same folder copied to another path, with `bin/hookshot` replaced by a file with different bytes, as an update does: 51.0 s. Predicted 14.2 s, precompile 14.6 s. - Both runs used one driver cache file, 1.9 GB. - Hookshot's own pipeline cache (`mkw_vk_pipelines.bin`) is checked against the vendor, the device and the driver's `pipelineCacheUUID`. It is not checked against Hookshot's version or path, so it stays valid across updates: 300 of 300 pipelines were found in it with the program replaced and moved. A cache from another driver or GPU is still dropped. What does start the driver cache over: a driver update (expected: the driver drops its own cache), the cache's size limit (raised to 10 GiB on Linux already) and the case this PR fixes. ## Tested - Linux, RTX 3090, driver 620.70.06. Without the fix (test program), with the cache path set to a missing folder: 7.9 ms per pipeline at the first start and again at the second, and nothing written anywhere. With the fix, the game (`--prepare-shaders`, `__GL_SHADER_DISK_CACHE_PATH` set to a missing two-level-deep folder) created the folder, and NVIDIA's cache filled it (35 MB within seconds). Nothing went to `~/.cache`. - `tests/test_driver_cache_folder.py`, `tests/test_driver_cache_room.py` and `tests/test_display_startup_failure.py` pass. `tests/run_all.py` on Linux: 358 passed and 4 failed, none of them from this change. Two need zstandard and one needs Tk, which this PC's Python doesn't have. The fourth is `test_wayland_libdecor_hint.py`, where a newer clang's `-Wunused-but-set-global` fires on that test's own harness. Not tested: Windows. Its NVIDIA cache (DXCache/GLCache under LocalAppData) wasn't checked, and this change is Linux-only.
Commenting is not possible because the repository is archived.
No description provided.