WIP: fix(vk): Mesa's Intel driver finishes the shader preparation on an Iris Xe #426

Draft
thomas-montano wants to merge 12 commits from thomas-montano/Longshot:fix/intel-xe-shader-preparation into main
First-time contributor

Why

On Linux with Mesa's Intel driver (an Iris Xe laptop, 32 GB), the shader preparation is killed for memory at the end of the build, and again at every start of the game, so the game never gets to play with its shaders prepared. With this PR the preparation finishes: 2775 s, peak 15.5 GB.

What changed

The cause is Mesa's Intel compiler (ANV, the brw back end) on the game's large compute programs. Held to 32 lanes (SIMD32), an Iris Xe thread has 32 registers a lane. The compiler then spends minutes, and gigabytes, in register allocation, spilling and allocating again (ra_get_spill_benefit under ra_allocate). The preparation ran one such compile on every worker. Each change below is on by default on Mesa's Intel driver alone, unless it says otherwise.

  • compute pin (gpu/vk/compute_pin.h, compute_pin_needed and pin_compute in gpu/vk/vk_draw.cpp): only the compute programs that can tell their lanes apart are still held to 32 lanes. Those are the ones with subgroup operations, matrices, or shared memory in a workgroup of one warp. The rest compute the same at any lane count, so the driver picks SIMD8/16 and builds them in seconds. Every maker of a compute pipeline (dispatch, load, precompile, the preparation's warm) now goes through compute_pipeline_info, so they all ask the caches for the same pipeline. The rule reads the program's record, never its SPIR-V.
  • memory gate (gpu/vk/compute_gate.h, ComputeTurn and cached_compute in vk_draw.cpp): each driver compute compile is weighed by whether it is pinned, its phis, and whether it is a mesh fallback stage. A compile starts beside the others only while their weights fit in what was available, and its own weight is available now; one always runs. A compile of a second or more hands its freed memory back (malloc_trim). The turn is taken before IntelDriverGate, so the two cannot wait on each other. Compiles of 10 s or more are named in the log, as are those running 30 s or more in a preparation that stands still.
  • spilling rate (create_instance in gpu/vk/vk_main.cpp): on Linux, Mesa's driconf shader_spilling_rate is set to 2 before the driver loads, unless the player set it. Only Mesa's Intel drivers read it.
    • abccf81b45c5eb50 is a program play dispatches. It went from not built after 20 minutes and 13 GB to 32 s and 1.7 GB.
    • Programs that don't spill are built as before.
  • listed computes (precompile_computes_which, warm_computes_apart in vk_draw.cpp, program_cache_borrow_all in gpu/vk/vk_progcache.cpp): RX_VK_PRECOMPILE_COMPUTES defaults to listed. That is 220 programs and 1046 variants instead of 4058 programs and 9691 variants. A program the list misses is made at its first dispatch, as with listed on any GPU. The preparation also compiles a program's texture variants after the translation, each as its own item on every CPU, instead of one after the other on the worker that translated it.
  • size limits (compute_refused in vk_draw.cpp, gpu/vk/fallback_size_policy.h, fallback_compute_pipelines): the driver is not given what its compiler never finishes, and the draws that need those pipelines are left out, as for a pipeline the driver refuses.
    • Two pinned compute programs of about 12,400 phis (045df6f2e27d05e6, 184791cd4644065f) are left out. Neither is in the shipped list or in any recorded play.
    • Mesh fallback stages over 20,000 phis or 200 function calls are left out. The calls are counted from the SPIR-V (spirv_calls, kept beside the phis in Stage).
  • mesh fallback epilogue (MeshFallbackEpilogue in gpu/vk/shader_recompiler/backend/spirv/emit_spirv_mesh.cpp; every GPU on the mesh fallback): the epilogue wrote a workgroup's records unrolled, 348 stores a thread, each at its own address. It now writes the same words in one DontUnroll loop, the threads side by side. The loop index is a function variable declared in the entry block. On the Iris Xe, 6fcc901fbc8b73c7 went from 207 s and 3.8 GB to build to 37 s and 1.55 GB. All 376 unique mesh fallback stages pass spirv-val.
  • watchdog (prepare_watchdog in vk_main.cpp, precompile_run in vk_draw.cpp; every GPU): the preparation's 300 s watchdog stopped runs whose driver was compiling all along. Every compile that ends now restarts its clock. A compile under way gets three times the limit, and twelve times (an hour) while the process keeps half a CPU or more busy. A stuck compile uses no CPU and still stops at three times. In the preparation's own process, precompile_run leaves an active compile to the watchdog instead of abandoning it.
  • FSR pipelines (shared_compute_pipeline in vk_draw.cpp): FSR 3 and 4 build their own pipelines without the description the gate reads. Found in review: they could have been weighed, logged, or on Mesa's Intel driver refused as the game program the same thread built before them. They now come with no description.
  • docs: docs/development.md lists every new switch and the new defaults. docs/tested/ has three runs.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
RX_VK_COMPUTE_PIN=all or lanes Which compute programs are held to 32 lanes lanes on Mesa's Intel, all elsewhere Keep the default Mesa's Intel (Iris Xe) Other drivers, whose compilers didn't need it Intel Arc on Linux; Intel on Windows
RX_VK_COMPUTE_AT_ONCE=<n> At most n driver compute compiles at once; 0 for no limit By memory on Mesa's Intel; no limit elsewhere Keep the default Mesa's Intel with 32 GB or less Discrete GPUs, whose compiles hold a few hundred MB Intel with 16 GB on Linux; Arc on Linux
shader_spilling_rate=<n> (Mesa's driconf) How fast Mesa's Intel compiler spills registers 2, set by the renderer on Linux unless already set Keep 2: 3 and 4 were slower Mesa's Intel Every other driver (ignored) Mesa versions other than 26.2.4
RX_VK_PRECOMPILE_COMPUTES Which compute programs the precompile and the preparation build listed on Mesa's Intel; unchanged elsewhere Keep the default Mesa's Intel (about 230 programs, not 4058) Other GPUs (unchanged) -
RX_VK_COMPUTE_WARM_APART=0 or 1 The preparation compiles a program's variants each as its own item 1 on Mesa's Intel, 0 elsewhere Keep the default Mesa's Intel Others, whose variants build quickly Other GPUs with 1
RX_VK_COMPUTE_PHI_LIMIT=<n> Pinned compute programs over n phis are not built on Mesa's Intel 6000 Keep: the two left out are never dispatched in recorded play Mesa's Intel - -
RX_VK_FALLBACK_PHI_LIMIT=<n> Mesh fallback stages over n phis are not built 20000 on Mesa's Intel (new); 50000 on RADV GCN 1-4 (unchanged) Keep Mesa's Intel - Which scenes draw the left-out stages
RX_VK_FALLBACK_CALL_LIMIT=<n> (new) Mesh fallback stages over n calls are not built on Mesa's Intel 200 Keep Mesa's Intel - Which scenes draw the left-out stages
LONGSHOT_PREPARE_ONLY (not new, not a player's switch) Set by --prepare-shaders itself (host/hos_main.c). Now also read by precompile_run: in that process an active compile is left to the watchdog, not abandoned after 30 s Set by the game - Every GPU's --prepare-shaders run Game starts (unchanged: they go on to play after 900 s) -
RX_VK_COMPUTE_LOG_MS=<ms> Names every compute compile that long in the log (diagnosis) Unset: those of 10 s or more, 60 at most Diagnosis only - - -

Measurements

main: 000f19fb (2026-11-13)
this PR: fix/intel-xe-shader-preparation @ 8e14adea (the branch head is now ec1c2561; see below why the numbers still hold)
Hardware: Intel Iris Xe Graphics (RPL-P, integrated), Mesa 26.2.4 ANV; Intel Core i9-13900H (20 threads); 32 GB; Bazzite (Fedora 44, kernel 7.2.11)
Scene: the build's shader preparation (--prepare-shaders), then play at Hyrule Castle (Auto: Minimum, the game's own upscaler, output 2048x1152, headless)
Method:

  • main: the Longshot Launcher's nightly-64-000f19fb build, its shader preparation as the launcher runs it; the kernel log.
  • this PR: longshot_vk.so built alone from 8e14adea in a game folder of that same nightly, then --prepare-shaders with process memory sampled every second; one run.
  • Play: 40 s standing still at Hyrule Castle after loading a save, from the fps over the last 5 s lines; one run each.
    How to reproduce: on a Mesa Intel iGPU without mesh shaders, run the game's shader preparation (the launcher's build, or longshot --prepare-shaders) with an empty cache/ folder.
main @ 000f19fb this PR @ 8e14adea
Shader preparation killed for memory (anon-rss 25.0 GB, about 7 GB of swap); 3 kills in 15 minutes finished, exit 0, in 2775 s
Peak memory of the process > 24 GB (killed) 15.5 GB
Compute programs / variants the preparation builds 4058 / 9691 220 / 1042 (776 s)
Mesh fallback stages left out (their draws missing) none (never finished) 10 of 376 unique

Why the comparison is not two interleaved runs each, as CONTRIBUTING.md asks: main cannot finish the preparation on this PC at all; each of its runs ends in the kernel's OOM kill. This PR's run was made once (46 minutes); the driver's own shader cache was warm from earlier runs, so it is not a cold-start time. main has moved since 000f19fb, to 5e072fc8 (merged in here), and the branch has three commits since 8e14adea: the merge of main, 4174944d (the back end's own FSR pipelines come in with no description; it changes nothing for the game's programs measured here) and two docs commits. None of them touches how compute compiles are scheduled, pinned or sized on the game's programs, so the numbers still hold. Nothing in between changes how compute compiles are scheduled, pinned or sized on Mesa's Intel driver; the Intel changes in between (#190, #252) are for Intel's Windows driver.

The single compiles that set the defaults, built alone (one SPIR-V module, VK_KHR_pipeline_executable_properties, Mesa 26.2.4):

Program main @ 000f19fb's settings this PR @ 8e14adea
abccf81b45c5eb50 (dispatched in play, 2190 phis, pinned) not built after 20 min, 13 GB 32 s, 1.7 GB (shader_spilling_rate=2)
7a548525c239b91b (2534 phis, pinned) 531 s, 7.6 GB 87 s, 4 GB
6fcc901fbc8b73c7 (mesh fallback, 58 phis) 207 s, 3.8 GB 37 s, 1.55 GB (epilogue loop)
1cd6ed71bb3f651e (mesh fallback) 164 s, 3.3 GB 38 s, 1.5 GB (epilogue loop)
045df6f2e27d05e6 (12,400 phis, pinned) 17.6 GB, not built after 30 min not given to the driver (never dispatched in recorded play)
2b152050cd96ce1d (mesh fallback, 251 calls) 14 GB cap in 27 min, unfinished not given to the driver

Play, Hyrule Castle, the same build of this PR with one thing changed. These are single runs, to show that the epilogue loop costs nothing; the frame rate itself is the mesh fallback's cost (below).

this PR @ 8e14adea this PR @ 8e14adea, the old unrolled epilogue this PR @ 8e14adea, RX_VK_NO_MESH=1
fps, the last 30 s 7.3, 7.5, 7.1, 7.1, 6.9, 7.0 5.7, 5.4, 5.5, 5.4, 5.7, 5.4 18.4, 17.5, 18.9, 19.2, 19.0, 19.3
GPU time a frame 96-145 ms 110-176 ms 42-45 ms
draws (skipped), dispatches 1199 (0), 217 1118 (0), 203 1133 (0), 197 (no foliage)
main @ 000f19fb, kernel log:
Nov 13 12:43:24 kernel: Out of memory: Killed process 371569 (longshot) total-vm:35453580kB, anon-rss:25043200kB, file-rss:16kB, shmem-rss:0kB, UID:1000 pgtables:66076kB oom_score_adj:200
Nov 13 12:56:58 kernel: Out of memory: Killed process 378792 (longshot) total-vm:567320040kB, anon-rss:19284136kB, file-rss:16kB, shmem-rss:64kB, UID:1000 pgtables:54092kB oom_score_adj:200
Nov 13 12:58:20 kernel: oom-kill:constraint=CONSTRAINT_NONE ... task=longshot,pid=382660

this PR @ 8e14adea, longshot_log.txt:
vk: Mesa's Intel compiler spills at rate 2 (driconf shader_spilling_rate: 2 unless set)
vk: compute pipelines: as many compiled at once as 14901 MB hold (18997 MB available now, 4096 left to the PC), 2048 MB for one held to 32 lanes (8192 MB with 2000 phis or more, 3072 MB for a mesh fallback stage) and 512 MB for another, at most 16 (Mesa's Intel compiler; RX_VK_COMPUTE_AT_ONCE=<n> or 0 says otherwise)
vk: prepared 38809 shader programs (46597 new, 70 failed, 0 compute pipelines; 9691 compute variants, 775 programs with texture variants, 59 at the limit) in 48.2 s
vk: preparation: the compute pipelines of 220 compute programs compiled for the driver's cache (those the precompile keeps): 1042 variants on 20 threads in 775.9 s
vk: precompile: compute programs: those listed (233 keys listed: 233 in the shipped list, 0 dispatched in play here, 233 of the shipped not among those; 220 of the listed have a program here, 1046 variants)
vk: precompile: compute programs: 271 held to 32 lanes (0 of them for their shared memory alone), 775 at the lanes the driver chooses (RX_VK_COMPUTE_PIN=all or lanes)
vk: fallback: the compute pipeline of 93e3e999f2fb9fd8 (stage 1 of 4, 79947 phis, the most 20000) is not built: Mesa's Intel compiler would not finish it (RX_VK_FALLBACK_PHI_LIMIT); its draws are left out
vk: fallback: the compute pipeline of 2b152050cd96ce1d (stage 0 of 3, 251 calls, the most 200) is not built: Mesa's Intel compiler would not finish it (RX_VK_FALLBACK_CALL_LIMIT); its draws are left out
vk: precompile: 3279 programs, 24448 graphics and 1046 compute pipelines, 2224 mesh fallback programs in 2763658 ms (332 ms of it the caches opened, the notes and programs read)
@@done shaders
process: exit=0 after 2775 s, peak 15503 MB

Testing

Tested:

  • The game-free checks for every file this PR touches, built with g++ on Linux:
    • test_compute_gate, test_compute_pin, test_compute_warm_apart, test_fallback_size_policy, test_mesh_fallback, test_pipeline_state_computes and test_prepare_stall;
    • test_utf8_paths, test_check_pr_description, test_quick_pipelines, test_vk_occlusion_queries, test_mesh_mode_switch, test_tested_configurations, and scripts/check_third_party.py.
  • test_precompile_compute_guard is Windows-only (RUN_ALL_SKIP on Linux) and was not run here.
  • python -I -B tests/run_all.py whole, at ec1c2561 in a clean worktree capped at 12 GB: 477 passed, 5 failed, 82 skipped (the checks that need the Vulkan headers). The 5 failures also fail on main @ 5e072fc8: test_bake_portability (no zstandard here), test_lift_cache (no numpy here), test_menu_keys, test_module_ids and test_pad_layout.
  • The renderer builds on Linux (the Linux toolchain, release, x86-64-v3).
  • In the game, on the Iris Xe above: the full shader preparation, which finishes (Measurements).
  • Then headless play: the title, the load menu and Hyrule Castle all render, with no draws skipped. The mesh fallback's draws (foliage, grass, leaves) are there; on main they were skipped while their pipelines compiled in play.
  • All 376 unique mesh fallback compute stages, with the epilogue loop, pass spirv-val.

Not tested:

  • The Windows build (llvm-mingw): there is none on this PC. The new host code (process_cpu_ms, memory_available_mb) has Windows branches, built by nobody yet.
  • Which scenes draw the 10 mesh fallback stages left out on Mesa's Intel driver: their draws are missing there.
  • A cold-start time of --prepare-shaders (the driver's cache was warm).
  • Intel Arc on Linux, which has mesh shaders, so its --prepare-shaders run differs.

Needs other testers:

  • AMD on Linux (RADV, the mesh fallback by default): a few areas with foliage, expecting the same picture and the same fps as main, as the epilogue loop changes every fallback stage (T-ECYN)
  • Windows, RX 6600-6950 XT (Navi 21-23, the task + mesh fallback by default): the same, expecting the same picture and fps as main (T-5SN3)
  • Windows, any GPU: the renderer builds with llvm-mingw and --prepare-shaders runs to @@done shaders as on main, the watchdog's longer limit during an active compile included (T-EXRV)
  • Linux, another Mesa Intel iGPU, ideally with 16 GB: --prepare-shaders finishes without an OOM kill, expecting a compute pipelines: as many compiled at once as ... MB hold line and @@done shaders (T-ST63)

Screenshots

Hyrule Castle after the full preparation, this PR @ 8e14adea (Iris Xe, Mesa 26.2.4, headless, Auto's Minimum). There is no main @ 000f19fb picture, because main's preparation never finishes on this PC.

Hyrule Castle, this PR @ 8e14adea

Risk and rollback

  • On Mesa's Intel driver, 10 mesh fallback stages and two compute programs are not built, and their draws or dispatches are left out. Each one is named in the log. RX_VK_FALLBACK_PHI_LIMIT=0, RX_VK_FALLBACK_CALL_LIMIT=0 and RX_VK_COMPUTE_PHI_LIMIT=0 build them anyway; each took the compiler past 14 GB here.
  • A compute program the shipped list misses is built at its first dispatch on Mesa's Intel driver (RX_VK_PRECOMPILE_COMPUTES=all for the old behaviour).
  • A program left at the driver's lanes could compute differently if the rule misses a way it sees its lanes. RX_VK_COMPUTE_PIN=all pins every one, as before.
  • The epilogue loop runs on every GPU that uses the mesh fallback. Its output is the same words, but it was only measured on the Iris Xe; reverting 3b3309f9 undoes it.
  • The longer watchdog limits apply on every GPU: a preparation whose driver is really stuck still stops, but after 900 s instead of 300 s during a compile.
  • Everything else is limited to Mesa's Intel driver. RX_VK_COMPUTE_AT_ONCE=0, RX_VK_COMPUTE_WARM_APART=0 and shader_spilling_rate=1 (Mesa's default) turn the rest off.

Reviewer notes

Where to look first: ComputeTurn and cached_compute in gpu/vk/vk_draw.cpp, gpu/vk/compute_gate.h and gpu/vk/compute_pin.h, then MeshFallbackEpilogue.

Against #404 (Intel on Windows), which this complements. Both PRs start from the same cause: Intel's compiler takes minutes over the game's large compute programs, and the preparation's watchdog or the memory stops the run. They fix it for different drivers, and they merge without conflicts (git merge-tree of this branch with 404 @ af5f7657).

  • 404 covers Intel's Windows driver.
    • It builds there one pipeline at a time, unoptimized first, with the optimized one later on a back lane.
    • The game's dispatches go ahead of the mesh fallback's builds.
    • The pipeline cache is saved between two builds.
    • On integrated GPUs: no texture blocks at the start, smaller mips, 33% on 4-thread machines, and a "weak laptop" button.
  • Its no-optimizer flag does nothing on Linux. Measured on this PC, ANV ignores VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT: the same instructions, spills and time, and the optimized rebuild is a cache hit. 404 has kept its quick builds to Windows since e072164e.
  • This PR covers Mesa's Intel driver on Linux, where the time is register allocation at SIMD32 and the memory is what runs out. It brings the pin rule, the memory gate, the spilling rate, the listed plan and the size limits. What reaches other drivers is the mesh fallback's epilogue loop and the watchdog.
  • Where they meet:
    • Every path in 404 makes its pipelines through compute_pipeline_info and cached_compute. That includes its quick builds, compute_optimize and precompile_compute_quick. So on Mesa's Intel driver they get this PR's pin rule and memory gate with no change.
    • This PR's watchdog (any GPU) would also stop stopping the Windows preparation that 404 describes, whose compiles took up to 389.5 s with the CPU busy.
    • 404's serial_builds_on goes by vendor, so its front lane and its save between builds also run on Linux Intel, one build at a time beside this gate. Its memory and texture changes for integrated GPUs apply on the Iris Xe too.
    • These combinations have not been run together yet: one run on this PC once both are in would settle it.
  • Neither PR needs the other; whichever merges second takes main again.

Left for a follow-up: the frame rate on GPUs that draw through the mesh fallback. At Hyrule Castle RX_VK_PASS_TIMING puts 113 of 153 ms between spans: the fallback's dispatches and a full barrier per mesh draw. That is a cost of the fallback itself, not of this PR.

Issues

See #407 (the up-front preparation does not finish on Intel Arc on Windows: the same compiler cost, the other driver; this PR does not change Windows' Intel driver path)

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. (main @ 5e072fc8 is merged in, the current head.)
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). Run whole at ec1c2561 in a clean worktree, capped at 12 GB: 477 passed, 5 failed, 82 skipped. The 5 failures fail the same on main @ 5e072fc8 and are named under Testing.
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Not met: main's preparation cannot finish here, and this PR's ran once (Measurements).
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • Screenshots for a change that shows on screen.
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md; no appended row or assembled view).
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Linux only so far: no llvm-mingw on this PC (T-EXRV, under Needs other testers).
  • Docs updated.
## Why On Linux with Mesa's Intel driver (an Iris Xe laptop, 32 GB), the shader preparation is killed for memory at the end of the build, and again at every start of the game, so the game never gets to play with its shaders prepared. With this PR the preparation finishes: 2775 s, peak 15.5 GB. ## What changed The cause is Mesa's Intel compiler (ANV, the `brw` back end) on the game's large compute programs. Held to 32 lanes (SIMD32), an Iris Xe thread has 32 registers a lane. The compiler then spends minutes, and gigabytes, in register allocation, spilling and allocating again (`ra_get_spill_benefit` under `ra_allocate`). The preparation ran one such compile on every worker. Each change below is on by default on Mesa's Intel driver alone, unless it says otherwise. - **compute pin** (`gpu/vk/compute_pin.h`, `compute_pin_needed` and `pin_compute` in `gpu/vk/vk_draw.cpp`): only the compute programs that can tell their lanes apart are still held to 32 lanes. Those are the ones with subgroup operations, matrices, or shared memory in a workgroup of one warp. The rest compute the same at any lane count, so the driver picks SIMD8/16 and builds them in seconds. Every maker of a compute pipeline (dispatch, load, precompile, the preparation's warm) now goes through `compute_pipeline_info`, so they all ask the caches for the same pipeline. The rule reads the program's record, never its SPIR-V. - **memory gate** (`gpu/vk/compute_gate.h`, `ComputeTurn` and `cached_compute` in `vk_draw.cpp`): each driver compute compile is weighed by whether it is pinned, its phis, and whether it is a mesh fallback stage. A compile starts beside the others only while their weights fit in what was available, and its own weight is available now; one always runs. A compile of a second or more hands its freed memory back (`malloc_trim`). The turn is taken before `IntelDriverGate`, so the two cannot wait on each other. Compiles of 10 s or more are named in the log, as are those running 30 s or more in a preparation that stands still. - **spilling rate** (`create_instance` in `gpu/vk/vk_main.cpp`): on Linux, Mesa's driconf `shader_spilling_rate` is set to 2 before the driver loads, unless the player set it. Only Mesa's Intel drivers read it. - `abccf81b45c5eb50` is a program play dispatches. It went from not built after 20 minutes and 13 GB to 32 s and 1.7 GB. - Programs that don't spill are built as before. - **listed computes** (`precompile_computes_which`, `warm_computes_apart` in `vk_draw.cpp`, `program_cache_borrow_all` in `gpu/vk/vk_progcache.cpp`): `RX_VK_PRECOMPILE_COMPUTES` defaults to `listed`. That is 220 programs and 1046 variants instead of 4058 programs and 9691 variants. A program the list misses is made at its first dispatch, as with `listed` on any GPU. The preparation also compiles a program's texture variants after the translation, each as its own item on every CPU, instead of one after the other on the worker that translated it. - **size limits** (`compute_refused` in `vk_draw.cpp`, `gpu/vk/fallback_size_policy.h`, `fallback_compute_pipelines`): the driver is not given what its compiler never finishes, and the draws that need those pipelines are left out, as for a pipeline the driver refuses. - Two pinned compute programs of about 12,400 phis (`045df6f2e27d05e6`, `184791cd4644065f`) are left out. Neither is in the shipped list or in any recorded play. - Mesh fallback stages over 20,000 phis or 200 function calls are left out. The calls are counted from the SPIR-V (`spirv_calls`, kept beside the phis in `Stage`). - **mesh fallback epilogue** (`MeshFallbackEpilogue` in `gpu/vk/shader_recompiler/backend/spirv/emit_spirv_mesh.cpp`; **every GPU on the mesh fallback**): the epilogue wrote a workgroup's records unrolled, 348 stores a thread, each at its own address. It now writes the same words in one `DontUnroll` loop, the threads side by side. The loop index is a function variable declared in the entry block. On the Iris Xe, `6fcc901fbc8b73c7` went from 207 s and 3.8 GB to build to 37 s and 1.55 GB. All 376 unique mesh fallback stages pass `spirv-val`. - **watchdog** (`prepare_watchdog` in `vk_main.cpp`, `precompile_run` in `vk_draw.cpp`; **every GPU**): the preparation's 300 s watchdog stopped runs whose driver was compiling all along. Every compile that ends now restarts its clock. A compile under way gets three times the limit, and twelve times (an hour) while the process keeps half a CPU or more busy. A stuck compile uses no CPU and still stops at three times. In the preparation's own process, `precompile_run` leaves an active compile to the watchdog instead of abandoning it. - **FSR pipelines** (`shared_compute_pipeline` in `vk_draw.cpp`): FSR 3 and 4 build their own pipelines without the description the gate reads. Found in review: they could have been weighed, logged, or on Mesa's Intel driver refused as the game program the same thread built before them. They now come with no description. - **docs**: `docs/development.md` lists every new switch and the new defaults. `docs/tested/` has three runs. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `RX_VK_COMPUTE_PIN=all` or `lanes` | Which compute programs are held to 32 lanes | `lanes` on Mesa's Intel, `all` elsewhere | Keep the default | Mesa's Intel (Iris Xe) | Other drivers, whose compilers didn't need it | Intel Arc on Linux; Intel on Windows | | `RX_VK_COMPUTE_AT_ONCE=<n>` | At most n driver compute compiles at once; `0` for no limit | By memory on Mesa's Intel; no limit elsewhere | Keep the default | Mesa's Intel with 32 GB or less | Discrete GPUs, whose compiles hold a few hundred MB | Intel with 16 GB on Linux; Arc on Linux | | `shader_spilling_rate=<n>` (Mesa's driconf) | How fast Mesa's Intel compiler spills registers | `2`, set by the renderer on Linux unless already set | Keep `2`: `3` and `4` were slower | Mesa's Intel | Every other driver (ignored) | Mesa versions other than 26.2.4 | | `RX_VK_PRECOMPILE_COMPUTES` | Which compute programs the precompile and the preparation build | `listed` on Mesa's Intel; unchanged elsewhere | Keep the default | Mesa's Intel (about 230 programs, not 4058) | Other GPUs (unchanged) | - | | `RX_VK_COMPUTE_WARM_APART=0` or `1` | The preparation compiles a program's variants each as its own item | `1` on Mesa's Intel, `0` elsewhere | Keep the default | Mesa's Intel | Others, whose variants build quickly | Other GPUs with `1` | | `RX_VK_COMPUTE_PHI_LIMIT=<n>` | Pinned compute programs over n phis are not built on Mesa's Intel | 6000 | Keep: the two left out are never dispatched in recorded play | Mesa's Intel | - | - | | `RX_VK_FALLBACK_PHI_LIMIT=<n>` | Mesh fallback stages over n phis are not built | 20000 on Mesa's Intel (new); 50000 on RADV GCN 1-4 (unchanged) | Keep | Mesa's Intel | - | Which scenes draw the left-out stages | | `RX_VK_FALLBACK_CALL_LIMIT=<n>` (new) | Mesh fallback stages over n calls are not built on Mesa's Intel | 200 | Keep | Mesa's Intel | - | Which scenes draw the left-out stages | | `LONGSHOT_PREPARE_ONLY` (not new, not a player's switch) | Set by `--prepare-shaders` itself (`host/hos_main.c`). Now also read by `precompile_run`: in that process an active compile is left to the watchdog, not abandoned after 30 s | Set by the game | - | Every GPU's `--prepare-shaders` run | Game starts (unchanged: they go on to play after 900 s) | - | | `RX_VK_COMPUTE_LOG_MS=<ms>` | Names every compute compile that long in the log (diagnosis) | Unset: those of 10 s or more, 60 at most | Diagnosis only | - | - | - | ## Measurements main: 000f19fb (2026-11-13) this PR: fix/intel-xe-shader-preparation @ 8e14adea (the branch head is now ec1c2561; see below why the numbers still hold) Hardware: Intel Iris Xe Graphics (RPL-P, integrated), Mesa 26.2.4 ANV; Intel Core i9-13900H (20 threads); 32 GB; Bazzite (Fedora 44, kernel 7.2.11) Scene: the build's shader preparation (`--prepare-shaders`), then play at Hyrule Castle (Auto: Minimum, the game's own upscaler, output 2048x1152, headless) Method: - main: the Longshot Launcher's nightly-64-000f19fb build, its shader preparation as the launcher runs it; the kernel log. - this PR: `longshot_vk.so` built alone from 8e14adea in a game folder of that same nightly, then `--prepare-shaders` with process memory sampled every second; one run. - Play: 40 s standing still at Hyrule Castle after loading a save, from the `fps over the last 5 s` lines; one run each. How to reproduce: on a Mesa Intel iGPU without mesh shaders, run the game's shader preparation (the launcher's build, or `longshot --prepare-shaders`) with an empty `cache/` folder. | | main @ 000f19fb | this PR @ 8e14adea | |---|---|---| | Shader preparation | killed for memory (anon-rss 25.0 GB, about 7 GB of swap); 3 kills in 15 minutes | finished, exit 0, in 2775 s | | Peak memory of the process | > 24 GB (killed) | 15.5 GB | | Compute programs / variants the preparation builds | 4058 / 9691 | 220 / 1042 (776 s) | | Mesh fallback stages left out (their draws missing) | none (never finished) | 10 of 376 unique | Why the comparison is not two interleaved runs each, as CONTRIBUTING.md asks: main cannot finish the preparation on this PC at all; each of its runs ends in the kernel's OOM kill. This PR's run was made once (46 minutes); the driver's own shader cache was warm from earlier runs, so it is not a cold-start time. main has moved since 000f19fb, to 5e072fc8 (merged in here), and the branch has three commits since 8e14adea: the merge of main, 4174944d (the back end's own FSR pipelines come in with no description; it changes nothing for the game's programs measured here) and two docs commits. None of them touches how compute compiles are scheduled, pinned or sized on the game's programs, so the numbers still hold. Nothing in between changes how compute compiles are scheduled, pinned or sized on Mesa's Intel driver; the Intel changes in between (#190, #252) are for Intel's Windows driver. The single compiles that set the defaults, built alone (one SPIR-V module, `VK_KHR_pipeline_executable_properties`, Mesa 26.2.4): | Program | main @ 000f19fb's settings | this PR @ 8e14adea | |---|---|---| | `abccf81b45c5eb50` (dispatched in play, 2190 phis, pinned) | not built after 20 min, 13 GB | 32 s, 1.7 GB (`shader_spilling_rate=2`) | | `7a548525c239b91b` (2534 phis, pinned) | 531 s, 7.6 GB | 87 s, 4 GB | | `6fcc901fbc8b73c7` (mesh fallback, 58 phis) | 207 s, 3.8 GB | 37 s, 1.55 GB (epilogue loop) | | `1cd6ed71bb3f651e` (mesh fallback) | 164 s, 3.3 GB | 38 s, 1.5 GB (epilogue loop) | | `045df6f2e27d05e6` (12,400 phis, pinned) | 17.6 GB, not built after 30 min | not given to the driver (never dispatched in recorded play) | | `2b152050cd96ce1d` (mesh fallback, 251 calls) | 14 GB cap in 27 min, unfinished | not given to the driver | Play, Hyrule Castle, the same build of this PR with one thing changed. These are single runs, to show that the epilogue loop costs nothing; the frame rate itself is the mesh fallback's cost (below). | | this PR @ 8e14adea | this PR @ 8e14adea, the old unrolled epilogue | this PR @ 8e14adea, `RX_VK_NO_MESH=1` | |---|---|---|---| | fps, the last 30 s | 7.3, 7.5, 7.1, 7.1, 6.9, 7.0 | 5.7, 5.4, 5.5, 5.4, 5.7, 5.4 | 18.4, 17.5, 18.9, 19.2, 19.0, 19.3 | | GPU time a frame | 96-145 ms | 110-176 ms | 42-45 ms | | draws (skipped), dispatches | 1199 (0), 217 | 1118 (0), 203 | 1133 (0), 197 (no foliage) | ``` main @ 000f19fb, kernel log: Nov 13 12:43:24 kernel: Out of memory: Killed process 371569 (longshot) total-vm:35453580kB, anon-rss:25043200kB, file-rss:16kB, shmem-rss:0kB, UID:1000 pgtables:66076kB oom_score_adj:200 Nov 13 12:56:58 kernel: Out of memory: Killed process 378792 (longshot) total-vm:567320040kB, anon-rss:19284136kB, file-rss:16kB, shmem-rss:64kB, UID:1000 pgtables:54092kB oom_score_adj:200 Nov 13 12:58:20 kernel: oom-kill:constraint=CONSTRAINT_NONE ... task=longshot,pid=382660 this PR @ 8e14adea, longshot_log.txt: vk: Mesa's Intel compiler spills at rate 2 (driconf shader_spilling_rate: 2 unless set) vk: compute pipelines: as many compiled at once as 14901 MB hold (18997 MB available now, 4096 left to the PC), 2048 MB for one held to 32 lanes (8192 MB with 2000 phis or more, 3072 MB for a mesh fallback stage) and 512 MB for another, at most 16 (Mesa's Intel compiler; RX_VK_COMPUTE_AT_ONCE=<n> or 0 says otherwise) vk: prepared 38809 shader programs (46597 new, 70 failed, 0 compute pipelines; 9691 compute variants, 775 programs with texture variants, 59 at the limit) in 48.2 s vk: preparation: the compute pipelines of 220 compute programs compiled for the driver's cache (those the precompile keeps): 1042 variants on 20 threads in 775.9 s vk: precompile: compute programs: those listed (233 keys listed: 233 in the shipped list, 0 dispatched in play here, 233 of the shipped not among those; 220 of the listed have a program here, 1046 variants) vk: precompile: compute programs: 271 held to 32 lanes (0 of them for their shared memory alone), 775 at the lanes the driver chooses (RX_VK_COMPUTE_PIN=all or lanes) vk: fallback: the compute pipeline of 93e3e999f2fb9fd8 (stage 1 of 4, 79947 phis, the most 20000) is not built: Mesa's Intel compiler would not finish it (RX_VK_FALLBACK_PHI_LIMIT); its draws are left out vk: fallback: the compute pipeline of 2b152050cd96ce1d (stage 0 of 3, 251 calls, the most 200) is not built: Mesa's Intel compiler would not finish it (RX_VK_FALLBACK_CALL_LIMIT); its draws are left out vk: precompile: 3279 programs, 24448 graphics and 1046 compute pipelines, 2224 mesh fallback programs in 2763658 ms (332 ms of it the caches opened, the notes and programs read) @@done shaders process: exit=0 after 2775 s, peak 15503 MB ``` ## Testing **Tested:** - The game-free checks for every file this PR touches, built with g++ on Linux: - `test_compute_gate`, `test_compute_pin`, `test_compute_warm_apart`, `test_fallback_size_policy`, `test_mesh_fallback`, `test_pipeline_state_computes` and `test_prepare_stall`; - `test_utf8_paths`, `test_check_pr_description`, `test_quick_pipelines`, `test_vk_occlusion_queries`, `test_mesh_mode_switch`, `test_tested_configurations`, and `scripts/check_third_party.py`. - `test_precompile_compute_guard` is Windows-only (`RUN_ALL_SKIP` on Linux) and was not run here. - `python -I -B tests/run_all.py` whole, at ec1c2561 in a clean worktree capped at 12 GB: 477 passed, 5 failed, 82 skipped (the checks that need the Vulkan headers). The 5 failures also fail on main @ 5e072fc8: `test_bake_portability` (no `zstandard` here), `test_lift_cache` (no `numpy` here), `test_menu_keys`, `test_module_ids` and `test_pad_layout`. - The renderer builds on Linux (the Linux toolchain, release, x86-64-v3). - In the game, on the Iris Xe above: the full shader preparation, which finishes (Measurements). - Then headless play: the title, the load menu and Hyrule Castle all render, with no draws skipped. The mesh fallback's draws (foliage, grass, leaves) are there; on main they were skipped while their pipelines compiled in play. - All 376 unique mesh fallback compute stages, with the epilogue loop, pass `spirv-val`. **Not tested:** - The Windows build (llvm-mingw): there is none on this PC. The new host code (`process_cpu_ms`, `memory_available_mb`) has Windows branches, built by nobody yet. - Which scenes draw the 10 mesh fallback stages left out on Mesa's Intel driver: their draws are missing there. - A cold-start time of `--prepare-shaders` (the driver's cache was warm). - Intel Arc on Linux, which has mesh shaders, so its `--prepare-shaders` run differs. **Needs other testers:** - AMD on Linux (RADV, the mesh fallback by default): a few areas with foliage, expecting the same picture and the same fps as main, as the epilogue loop changes every fallback stage (T-ECYN) - Windows, RX 6600-6950 XT (Navi 21-23, the task + mesh fallback by default): the same, expecting the same picture and fps as main (T-5SN3) - Windows, any GPU: the renderer builds with llvm-mingw and `--prepare-shaders` runs to `@@done shaders` as on main, the watchdog's longer limit during an active compile included (T-EXRV) - Linux, another Mesa Intel iGPU, ideally with 16 GB: `--prepare-shaders` finishes without an OOM kill, expecting a `compute pipelines: as many compiled at once as ... MB hold` line and `@@done shaders` (T-ST63) ## Screenshots Hyrule Castle after the full preparation, this PR @ 8e14adea (Iris Xe, Mesa 26.2.4, headless, Auto's Minimum). There is no main @ 000f19fb picture, because main's preparation never finishes on this PC. ![Hyrule Castle, this PR @ 8e14adea](https://git.magicbean.dev/attachments/212cb702-e9c5-4a2a-aa59-ce03ba18fe4d) ## Risk and rollback - On Mesa's Intel driver, 10 mesh fallback stages and two compute programs are not built, and their draws or dispatches are left out. Each one is named in the log. `RX_VK_FALLBACK_PHI_LIMIT=0`, `RX_VK_FALLBACK_CALL_LIMIT=0` and `RX_VK_COMPUTE_PHI_LIMIT=0` build them anyway; each took the compiler past 14 GB here. - A compute program the shipped list misses is built at its first dispatch on Mesa's Intel driver (`RX_VK_PRECOMPILE_COMPUTES=all` for the old behaviour). - A program left at the driver's lanes could compute differently if the rule misses a way it sees its lanes. `RX_VK_COMPUTE_PIN=all` pins every one, as before. - The epilogue loop runs on every GPU that uses the mesh fallback. Its output is the same words, but it was only measured on the Iris Xe; reverting `3b3309f9` undoes it. - The longer watchdog limits apply on every GPU: a preparation whose driver is really stuck still stops, but after 900 s instead of 300 s during a compile. - Everything else is limited to Mesa's Intel driver. `RX_VK_COMPUTE_AT_ONCE=0`, `RX_VK_COMPUTE_WARM_APART=0` and `shader_spilling_rate=1` (Mesa's default) turn the rest off. ## Reviewer notes Where to look first: `ComputeTurn` and `cached_compute` in `gpu/vk/vk_draw.cpp`, `gpu/vk/compute_gate.h` and `gpu/vk/compute_pin.h`, then `MeshFallbackEpilogue`. **Against https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/404 (Intel on Windows), which this complements.** Both PRs start from the same cause: Intel's compiler takes minutes over the game's large compute programs, and the preparation's watchdog or the memory stops the run. They fix it for different drivers, and they merge without conflicts (`git merge-tree` of this branch with 404 @ af5f7657). - **404 covers Intel's Windows driver.** - It builds there one pipeline at a time, unoptimized first, with the optimized one later on a back lane. - The game's dispatches go ahead of the mesh fallback's builds. - The pipeline cache is saved between two builds. - On integrated GPUs: no texture blocks at the start, smaller mips, 33% on 4-thread machines, and a "weak laptop" button. - **Its no-optimizer flag does nothing on Linux.** Measured on this PC, ANV ignores `VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT`: the same instructions, spills and time, and the optimized rebuild is a cache hit. 404 has kept its quick builds to Windows since e072164e. - **This PR covers Mesa's Intel driver on Linux,** where the time is register allocation at SIMD32 and the memory is what runs out. It brings the pin rule, the memory gate, the spilling rate, the listed plan and the size limits. What reaches other drivers is the mesh fallback's epilogue loop and the watchdog. - **Where they meet:** - Every path in 404 makes its pipelines through `compute_pipeline_info` and `cached_compute`. That includes its quick builds, `compute_optimize` and `precompile_compute_quick`. So on Mesa's Intel driver they get this PR's pin rule and memory gate with no change. - This PR's watchdog (any GPU) would also stop stopping the Windows preparation that 404 describes, whose compiles took up to 389.5 s with the CPU busy. - 404's `serial_builds_on` goes by vendor, so its front lane and its save between builds also run on Linux Intel, one build at a time beside this gate. Its memory and texture changes for integrated GPUs apply on the Iris Xe too. - These combinations have not been run together yet: one run on this PC once both are in would settle it. - Neither PR needs the other; whichever merges second takes main again. Left for a follow-up: the frame rate on GPUs that draw through the mesh fallback. At Hyrule Castle `RX_VK_PASS_TIMING` puts 113 of 153 ms between spans: the fallback's dispatches and a full barrier per mesh draw. That is a cost of the fallback itself, not of this PR. ## Issues See #407 (the up-front preparation does not finish on Intel Arc on Windows: the same compiler cost, the other driver; this PR does not change Windows' Intel driver path) ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. (main @ 5e072fc8 is merged in, the current head.) - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). Run whole at ec1c2561 in a clean worktree, capped at 12 GB: 477 passed, 5 failed, 82 skipped. The 5 failures fail the same on main @ 5e072fc8 and are named under Testing. - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [ ] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Not met: main's preparation cannot finish here, and this PR's ran once (Measurements). - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] Screenshots for a change that shows on screen. - [x] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`; no appended row or assembled view). - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Linux only so far: no llvm-mingw on this PC (T-EXRV, under Needs other testers). - [x] Docs updated.
Held to 32 lanes, Mesa's Intel compiler builds the SIMD32 program alone, and its register allocation took minutes and
gigabytes over the game's large compute programs: on an Iris Xe with 32 GB the shader preparation was killed for memory
or never ended. A program that cannot tell its lanes computes the same at any lane count, so there only those that can
keep the pin: subgroup operations, matrices, or shared memory in a workgroup of one warp (gpu/vk/compute_pin.h).

Every game compute pipeline (dispatch, load, precompile, the preparation's warm) is now described by
compute_pipeline_info, which pins through pin_compute, so all of them ask the caches for the same pipeline. The rule
reads the program's record, never its SPIR-V. RX_VK_COMPUTE_PIN=all or lanes over the default; other GPUs keep every
pin. tests/test_compute_pin.py.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The shader preparation ran one driver compile on every worker, and Mesa's Intel driver holds gigabytes for each of the
game's large compute programs: on an i9-13900H with Iris Xe and 32 GB the process passed 24 GB and 7 GB of swap and
Linux killed it. Each compile is now weighed (held to 32 lanes or not, its phis) and starts beside the others only while
their weights fit in what was available, and its own is available now; one always runs (gpu/vk/compute_gate.h). A long
compile hands the memory it freed back (malloc_trim).

The turn is taken before Intel's own lock (IntelDriverGate, Windows), so a worker holding the lock never waits for a turn.
Compiles of 10 s or more are named in the log, and a preparation that stands still names those that have run 30 s.
On by default on Mesa's Intel driver alone; RX_VK_COMPUTE_AT_ONCE=<n> or 0 on any GPU, RX_VK_COMPUTE_LOG_MS=<ms>.
tests/test_compute_gate.py.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Two of MKW's compute programs, 045df6f2e27d05e6 and 184791cd4644065f, are about 12,400 phis each; every other one held
to 32 lanes has 2,650 or fewer. Alone on an Iris Xe, 045df6f2e27d05e6 was at 17.6 GB and not built after 30 minutes held
to 32 lanes. Neither is in the shipped state list or in any recorded play. A pinned stage over kIntelPhiLimit (6000) is
refused in its compile's turn, before it waits at the gate, and its dispatches are left out, as for a program the driver
refuses; the mesh fallback's stages are not judged here. RX_VK_COMPUTE_PHI_LIMIT=<n>, 0 for none.
tests/test_compute_pin.py.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every compute program on a first start was 4,058 programs and 9,691 driver compiles, hours on an Iris Xe, where the
shipped list and this PC's play name about 230. RX_VK_PRECOMPILE_COMPUTES now defaults to "listed" on Mesa's Intel
driver (precompile_computes_which, read in one place for the precompile, the load at create and the preparation's warm);
a program the list misses is made at its first dispatch, as with "listed" on any GPU.

prepare_run also compiled a program's texture variants (up to 64) one after the other on the worker that translated it:
four programs held to 32 lanes held four of the ten workers for half an hour. Where the compiles are gated, the variants
are compiled after the translation, each its own item on every CPU (warm_computes_apart, program_cache_borrow_all), for
the precompile's plan only. RX_VK_COMPUTE_WARM_APART=0 or 1 on any GPU. tests/test_compute_warm_apart.py.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The compute warm's count moves when all of a program's variants are done, and on an Iris Xe one variant held to 32
lanes can take minutes: the watchdog stopped a preparation at 300 s whose driver was compiling all along. Every compile
that ends now restarts its clock (prepare_compiled), a compile under way gets three times the limit, and twelve times
(an hour by default) while the process keeps half a CPU or more busy, the compiler at work; a stuck compile uses no CPU
and still stops at three times. precompile_run's own 30 s limit gives an active compute compile 900 s, and in the
preparation's own process (LONGSHOT_PREPARE_ONLY) leaves it to the watchdog instead of abandoning it.
tests/test_prepare_stall.py.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
When a program does not fit its registers, Mesa's Intel compiler spills some and allocates the whole program again, in
rounds of one at first and then of (spilled so far / shader_spilling_rate). Held to 32 lanes an Iris Xe has 32 registers
a lane, and MKW's large compute programs spill thousands. On Linux the renderer sets the driconf option to 2 before the
driver loads, unless the player set it: abccf81b45c5eb50, which play dispatches, went from not built after 20 minutes
and 13 GB to 32 s and 1.7 GB, 7a548525c239b91b from 531 s and 7.6 GB to 87 s and 4 GB (i9-13900H, Mesa 26.2.4). Programs
that do not spill are built as before; 3 and 4 were worse. The log names the rate in use on Mesa's Intel driver.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The fallback epilogue wrote a workgroup's records unrolled, a primitive's corners and every line of each, its own address
each: 348 stores a thread for a mesh of 126 primitives and 28 lines, which Mesa's Intel compiler (Iris Xe, 32 lanes) took
207 s and 3.8 GB to build (41 s and 1.5 GB without them). One loop over the records' words, the threads side by side,
writes the same words; the loop index is a function variable declared in the entry block by the prologue.

With the loop the largest mesh fallback stages measured peak at 1.55 GB, and their phis do not show it, so a pinned one
now weighs kMeshMB (3072 MB, twice that) in the compute gate instead of kPinnedMB.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Four mesh programs call the translator's guest-address lookup 251-263 times; the driver inlines every call, and one of
them alone took its compiler to a 14 GB cap in 27 minutes, unfinished. 93e3e999f2fb9fd8 (79,947 phis) and
ecbbff63280b68e2 (29,372) did the same in 8.5 and 10 minutes, where 5c9454152ebde335 (16,837) built in 304 s. On that
driver a fallback compute stage over kIntelPhiLimit (20,000) phis or kIntelCallLimit (200) calls is left out, with its
draws, as on RADV GCN 1-4. The calls are counted from the SPIR-V (spirv_calls) and kept beside the phis, in the program
cache too. RX_VK_FALLBACK_PHI_LIMIT and RX_VK_FALLBACK_CALL_LIMIT say otherwise.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
ComputeTurn reads the description compute_pipeline_info (or the mesh fallback) left on its thread. shared_compute_pipeline
(vk_fsr3.cpp, vk_fsr4.cpp) reaches cached_compute with none of its own, so an FSR pipeline held to 32 or 64 lanes could be
weighed, logged, or on Mesa's Intel driver refused (compute_refused), as the game program that thread made last. It now
clears the description first; tests/test_compute_gate.py checks it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
docs(tested): the shader preparation on an Iris Xe with Mesa's Intel driver, main killed for memory and this branch finished, and play at Hyrule Castle
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s
ec1c256190
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Contributor

You have to make the description like contributing.md/development.md says

You have to make the description like contributing.md/development.md says
thomas-montano changed title from fix(vk): Mesa's Intel driver finishes the shader preparation on an Iris Xe to WIP: fix(vk): Mesa's Intel driver finishes the shader preparation on an Iris Xe 2026-11-14 14:35:45 +00:00
Author
First-time contributor

Back to WIP and description brought in line with the template: opened the four test requests (T-ECYN, T-5SN3, T-EXRV, T-ST63), said why the measurements still hold at ec1c2561 (the FSR change and the main merge don't touch the measured compiles), reworded Testing, and ran tests/run_all.py whole (477 passed, 5 failed; the same 5 fail on main @ 5e072fc8). Still unticked: measured with 2 interleaved runs (main can't finish the preparation here) and the Windows build (no llvm-mingw here, T-EXRV).

Back to WIP and description brought in line with the template: opened the four test requests (T-ECYN, T-5SN3, T-EXRV, T-ST63), said why the measurements still hold at ec1c2561 (the FSR change and the main merge don't touch the measured compiles), reworded Testing, and ran tests/run_all.py whole (477 passed, 5 failed; the same 5 fail on main @ 5e072fc8). Still unticked: measured with 2 interleaved runs (main can't finish the preparation here) and the Windows build (no llvm-mingw here, T-EXRV).
Author
First-time contributor

Reworded one Needs-other-testers line so it no longer reads as the measured shader preparation being untested.

Reworded one Needs-other-testers line so it no longer reads as the measured shader preparation being untested.
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request_target) Has been skipped
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/intel-xe-shader-preparation:thomas-montano-fix/intel-xe-shader-preparation'
git switch 'thomas-montano-fix/intel-xe-shader-preparation'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!426
No description provided.