WIP: fix(vk): Mesa's Intel driver finishes the shader preparation on an Iris Xe #426
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!426
Loading…
Reference in a new issue
No description provided.
Delete branch "thomas-montano/Longshot:fix/intel-xe-shader-preparation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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
brwback 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_benefitunderra_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.gpu/vk/compute_pin.h,compute_pin_neededandpin_computeingpu/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 throughcompute_pipeline_info, so they all ask the caches for the same pipeline. The rule reads the program's record, never its SPIR-V.gpu/vk/compute_gate.h,ComputeTurnandcached_computeinvk_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 beforeIntelDriverGate, 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.create_instanceingpu/vk/vk_main.cpp): on Linux, Mesa's driconfshader_spilling_rateis set to 2 before the driver loads, unless the player set it. Only Mesa's Intel drivers read it.abccf81b45c5eb50is a program play dispatches. It went from not built after 20 minutes and 13 GB to 32 s and 1.7 GB.precompile_computes_which,warm_computes_apartinvk_draw.cpp,program_cache_borrow_allingpu/vk/vk_progcache.cpp):RX_VK_PRECOMPILE_COMPUTESdefaults tolisted. 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 withlistedon 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.compute_refusedinvk_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.045df6f2e27d05e6,184791cd4644065f) are left out. Neither is in the shipped list or in any recorded play.spirv_calls, kept beside the phis inStage).MeshFallbackEpilogueingpu/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 oneDontUnrollloop, the threads side by side. The loop index is a function variable declared in the entry block. On the Iris Xe,6fcc901fbc8b73c7went from 207 s and 3.8 GB to build to 37 s and 1.55 GB. All 376 unique mesh fallback stages passspirv-val.prepare_watchdoginvk_main.cpp,precompile_runinvk_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_runleaves an active compile to the watchdog instead of abandoning it.shared_compute_pipelineinvk_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/development.mdlists every new switch and the new defaults.docs/tested/has three runs.Flags and settings
RX_VK_COMPUTE_PIN=allorlaneslaneson Mesa's Intel,allelsewhereRX_VK_COMPUTE_AT_ONCE=<n>0for no limitshader_spilling_rate=<n>(Mesa's driconf)2, set by the renderer on Linux unless already set2:3and4were slowerRX_VK_PRECOMPILE_COMPUTESlistedon Mesa's Intel; unchanged elsewhereRX_VK_COMPUTE_WARM_APART=0or11on Mesa's Intel,0elsewhere1RX_VK_COMPUTE_PHI_LIMIT=<n>RX_VK_FALLBACK_PHI_LIMIT=<n>RX_VK_FALLBACK_CALL_LIMIT=<n>(new)LONGSHOT_PREPARE_ONLY(not new, not a player's switch)--prepare-shadersitself (host/hos_main.c). Now also read byprecompile_run: in that process an active compile is left to the watchdog, not abandoned after 30 s--prepare-shadersrunRX_VK_COMPUTE_LOG_MS=<ms>Measurements
main:
000f19fb(2026-11-13)this PR: fix/intel-xe-shader-preparation @
8e14adea(the branch head is nowec1c2561; 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:
longshot_vk.sobuilt alone from8e14adeain a game folder of that same nightly, then--prepare-shaderswith process memory sampled every second; one run.fps over the last 5 slines; 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 emptycache/folder.000f19fb8e14adeaWhy 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, to5e072fc8(merged in here), and the branch has three commits since8e14adea: 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):8e14adeaabccf81b45c5eb50(dispatched in play, 2190 phis, pinned)shader_spilling_rate=2)7a548525c239b91b(2534 phis, pinned)6fcc901fbc8b73c7(mesh fallback, 58 phis)1cd6ed71bb3f651e(mesh fallback)045df6f2e27d05e6(12,400 phis, pinned)2b152050cd96ce1d(mesh fallback, 251 calls)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).
8e14adea8e14adea, the old unrolled epilogue8e14adea,RX_VK_NO_MESH=1Testing
Tested:
test_compute_gate,test_compute_pin,test_compute_warm_apart,test_fallback_size_policy,test_mesh_fallback,test_pipeline_state_computesandtest_prepare_stall;test_utf8_paths,test_check_pr_description,test_quick_pipelines,test_vk_occlusion_queries,test_mesh_mode_switch,test_tested_configurations, andscripts/check_third_party.py.test_precompile_compute_guardis Windows-only (RUN_ALL_SKIPon Linux) and was not run here.python -I -B tests/run_all.pywhole, atec1c2561in 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(nozstandardhere),test_lift_cache(nonumpyhere),test_menu_keys,test_module_idsandtest_pad_layout.spirv-val.Not tested:
process_cpu_ms,memory_available_mb) has Windows branches, built by nobody yet.--prepare-shaders(the driver's cache was warm).--prepare-shadersrun differs.Needs other testers:
--prepare-shadersruns to@@done shadersas on main, the watchdog's longer limit during an active compile included (T-EXRV)--prepare-shadersfinishes without an OOM kill, expecting acompute pipelines: as many compiled at once as ... MB holdline 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 @000f19fbpicture, because main's preparation never finishes on this PC.Risk and rollback
RX_VK_FALLBACK_PHI_LIMIT=0,RX_VK_FALLBACK_CALL_LIMIT=0andRX_VK_COMPUTE_PHI_LIMIT=0build them anyway; each took the compiler past 14 GB here.RX_VK_PRECOMPILE_COMPUTES=allfor the old behaviour).RX_VK_COMPUTE_PIN=allpins every one, as before.3b3309f9undoes it.RX_VK_COMPUTE_AT_ONCE=0,RX_VK_COMPUTE_WARM_APART=0andshader_spilling_rate=1(Mesa's default) turn the rest off.Reviewer notes
Where to look first:
ComputeTurnandcached_computeingpu/vk/vk_draw.cpp,gpu/vk/compute_gate.handgpu/vk/compute_pin.h, thenMeshFallbackEpilogue.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-treeof this branch with 404 @af5f7657).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 sincee072164e.compute_pipeline_infoandcached_compute. That includes its quick builds,compute_optimizeandprecompile_compute_quick. So on Mesa's Intel driver they get this PR's pin rule and memory gate with no change.serial_builds_ongoes 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.Left for a follow-up: the frame rate on GPUs that draw through the mesh fallback. At Hyrule Castle
RX_VK_PASS_TIMINGputs 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
type(scope): description).main. (main @5e072fc8is merged in, the current head.)python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above). Run whole atec1c2561in a clean worktree, capped at 12 GB: 477 passed, 5 failed, 82 skipped. The 5 failures fail the same on main @5e072fc8and are named under Testing.third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested/for each new measured run (format indocs/tested-configurations.md; no appended row or assembled view).mainand passing here.tests/that reads changed source updated in this PR, not weakened.You have to make the description like contributing.md/development.md says
fix(vk): Mesa's Intel driver finishes the shader preparation on an Iris Xeto WIP: fix(vk): Mesa's Intel driver finishes the shader preparation on an Iris XeBack 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).Reworded one Needs-other-testers line so it no longer reads as the measured shader preparation being untested.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.