perf(vk): the Arc B-series compiles shaders side by side by default: a new area no longer freezes the picture for minutes #500
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
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/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!500
Loading…
Reference in a new issue
No description provided.
Delete branch "nyannoying/Longshot:perf/battlemage-compiles-side-by-side"
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?
Type: perf · Risk: medium · Tested on: Windows 11, Intel Arc B580 (driver 32.0.101.9154) · Needs: an Arc B570 or a B580 on a newer driver, and any other Intel GPU on Windows (test requests T-DFNY and T-WW92, both still open)
Why
On an Intel Arc B580 the picture freezes for four to seven minutes the first time an area is entered, while its shaders are compiled one at a time. Compiled side by side, the same card does not freeze at all.
See #407 (the same contrast on an Arc iGPU in the preparation).
What changed
On the Arc B-series (Battlemage) with Intel's Windows driver 101.9154 or newer, shaders are now compiled side by side by default. The Debug tab's Intel shader compiles row gets a new default value, Auto, which means side by side on that family and one at a time on every other Intel GPU, as before. Side by side and One at a time can still be chosen by hand.
gpu/vk/intel_compiles.h(new) says where Auto is side by side: the Arc B-series (Battlemage, PCI device 0xE2xx) from Intel's Windows driver 101.9154, the family and driver it was run on. On every other Intel GPU Auto is one at a time, as before.intel_compiles_side_by_side()ingpu/vk/vk_menu.cppasks it with the row, the GPU and its driver;IntelDriverGate(gpu/vk/vk_internal.h) is unchanged but for a log line that says when the compiler is entered side by side.RX_VK_NO_INTEL_SERIAL=1is side by side for a run and=0one at a time.2b1d38c6: conflicts next to main's new Intel quick compute builds row and weak laptop button (docs/development.md,gpu/vk/vk_menu.cpp,gpu/vk/vk_menu.h), both sides kept. One change beyond the conflicts:weak_laptop_apply()setsopts.intel_compiles = 2(One at a time) instead of 0, because 0 now means Auto;tests/test_intel_quick_compute.pyreads that line.tests/test_intel_compiles_auto.py(new) compiles the rule alone against 39 cases (B580 and B570 from 101.9154, an older driver, Arc A-series, Meteor Lake, Arrow Lake, Lunar Lake, Iris Xe, UHD, and the row's three values) and checks the row in the source; it fails onmain.tests/test_intel_compiler_gate.pyreads the gate's new question.RX_VK_NO_INTEL_SERIALrow indocs/development.md; seven files indocs/tested/, one for each launch below.Measurements
Verdict: it helped. On the B580, in the two launches of one build, the picture was under 5 fps for 0 s with the new default (side by side) against 181 s one at a time. Over all the areas the median time until the frame rate is steady fell from 154 s (one at a time) to 27 s (side by side). No device loss and no fault line either way.
main:
9c9d69ed(2026-11-14)this PR: perf/battlemage-compiles-side-by-side @
dc47a621Since then the PR was rebased onto main
2b1d38c6. The game was not run again after the rebase: every number here is from the commits named in this section. Beyond the conflicts the rebase changed one line, in the weak laptop button (weak_laptop_apply()), and these launches used the default and the environment switch.Hardware: Intel Arc B580 12 GB (PCI device 0xE20B), driver 32.0.101.9154; Core i5-13600K (20 threads, 6 background workers); 64 GB; Windows 11 Pro (26100-series Insider, 10.0.29704)
Scene: areas entered by the debug teleport for the first time on this PC, in a game folder never prepared (
RX_VK_PRECOMPILE=0), frame generation offMethod: an area can be new only once (the driver keeps what it compiled), so no area was run twice: each launch teleports to areas not visited before and stands there. New programs are the log's
vk: in play:lines; "under 5 fps" is the sum of the log'svi: ... frames presented (... fps over the last ... s)windows below 5 fps; "steady after" is the time from the teleport until the control bridge's status reads 25 fps or more four times in a row. The last two launches are one build, the default againstRX_VK_NO_INTEL_SERIAL=0.How to reproduce: on a B-series card, with a game folder not prepared, enter an area for the first time with the row on One at a time and another with it on Side by side; the log's
vi:lines show the freeze.Baseline: this PR @
dc47a621,RX_VK_NO_INTEL_SERIAL=0(One at a time, main's default). main itself was not the comparison because on the B580 it loses the device entering Kokiri Forest (#444). The build that ran is this PR's change applied to maincf605c85with four changes not merged yet (#444, #446, #443, #459), since a main-based build has another shader stamp than this card's caches. The change touchesvk_menu.cpp,vk_menu.h,vk_internal.hand the new header only, and applies to both bases unchanged.RX_VK_NO_INTEL_SERIAL=0(One at a time, main's default): this PR @dc47a621dc47a621Before the change, with the switch on the same base (main
cf605c85with the four changes;RX_VK_NO_INTEL_SERIAL=1is what Auto now chooses on this card):RX_VK_TRANSLATE_WAIT_MS=8RX_VK_TRANSLATE_WAIT_MS=8Over all the areas, the median time until steady is 154 s one at a time (five areas in three launches: 250, 410, 134, 73, 154) and 27 s side by side (thirteen areas in four launches); the launches of the two settings were alternated over the afternoon, not paired area by area, for the reason under Method.
The usual figures of a
perfchange (average fps, 1% low, frame time) do not describe this one: what it moves is how long a first visit stops the picture, so that and the time until the frame rate is back are what is measured. The frame rate once an area's shaders exist is the same either way. Both timers in the log start before the gate, so with one thread in the compiler most of "translation" is queueing at the lock.Flags and settings
One menu row with its options file key changes its values and its default, and one switch gets a second value.
intel_shader_compiles=inlongshot_options.ini)RX_VK_NO_INTEL_SERIAL=0/1Testing
Tested:
docs/tested/; the Kokiri, Hyrule Field and Market fixes of #443, #444 and #446 in the build). Side by side in four launches through thirteen areas: 1,484 programs first compiled, noVK_ERROR_DEVICE_LOST, no "driver faulted" line, no exit; Kakariko Village, Zora's Domain and Dodongo's Cavern looked at and drawn right. With the default the log says side by side; withRX_VK_NO_INTEL_SERIAL=0it says one thread. These runs were on the build the Baseline line names, before the rebase.python -I -B tests/run_all.py: 496 passed, 5 failed, 70 skipped; the 5 weretest_fpx_sticky,test_walk_key,test_spawn_emit,test_tested_configurationsandtest_oot_state_tap, which failed the same way on main9c9d69edhere.2b1d38c6:python -I -B tests/run_all.py: 15 checks fail on this Windows PC and fail the same on main2b1d38c6alone (test_fpx_sticky,test_appimage_player_build,test_cpm_discovery,test_crash_dialog,test_env_on,test_lift_cleanup_error,test_make_game_cache,test_linux_preflight,test_oot_state_tap,test_readback_late,test_spawn_emit,test_tested_configurations,test_vk_pgo,test_vram_budget_row,test_walk_key).414f56e2,longshot.exe --prepare-shaders --compile-shaders most. Side by side (RX_VK_NO_INTEL_SERIAL=1): 24,456 pipelines in 1,476 s, none not made, noigvk64.dllfault. One at a time: 10,833 of 24,450 after 3,512 s, when it was stopped. About 30 minutes of play side by side with no driver fault. On that GPU this PR's Auto is One at a time (not 0xE2xx, and the driver is older than 101.9154), so this measures the switch there, not this PR's default.Not tested:
RX_VK_COMPUTE_SERIAL=0(left at its default: compute pipelines stay one at a time).Must be tested:
igvk64.dll, say so and which driver (by hand, test request T-DFNY, still open: look at the log line and for a freeze or a crash)Risks
What could break: only Arc B-series cards on driver 101.9154 or newer change by default: their shaders are compiled side by side. One at a time has a net that side by side has not: a shader Intel's compiler faults on is left out there, and side by side such a fault closes the game. None came in 1,484 first compiles on the B580, but that is one card and one driver.
Turning it off: set the Debug tab's Intel shader compiles row to One at a time, or start with
RX_VK_NO_INTEL_SERIAL=0. Reverting the commit is enough; a saved 2 then reads as Side by side under the old row's clamp, so a revert should say so.Compatibility:
longshot_options.ini: the keyintel_shader_compileschanges meaning. 0 was One at a time and is Auto now; 1 stays Side by side; 2 is One at a time. A player with an existing options file has 0 or 1. With 0 they get Auto: side by side on an Arc B-series card from driver 101.9154, one at a time on every other Intel GPU, as before. With 1 they keep Side by side. A B-series owner who had chosen One at a time on purpose must choose it again, since the old value 0 now reads as Auto. The shader and pipeline caches are kept: the diff touches none of the files the shader stamp is made of (nx2/translator_files.py:gpu/vk/eden,sirit,compat,vk_shader.cpp,vk_bank.cpp,vk_state.h). The vk ABI is unchanged:gpu/vk/vk_api.his not touched andMKWVK_API_VERSIONstays 22. Saves and the builder's tools are not touched.Reviewer notes
RX_VK_TRANSLATE_WAIT_MS=8alone took a third off a first visit's freeze and left draws out in only six reports; it is not part of this.Issues
See #407
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named): 15 checks fail on this Windows PC and fail the same on main2b1d38c6alone (test_fpx_sticky,test_appimage_player_build,test_cpm_discovery,test_crash_dialog,test_env_on,test_lift_cleanup_error,test_make_game_cache,test_linux_preflight,test_oot_state_tap,test_readback_late,test_spawn_emit,test_tested_configurations,test_vk_pgo,test_vram_budget_row,test_walk_key).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.docs/tested/for each new measured run (format indocs/tested-configurations.md).mainand passing here.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
The two test requests are open (T-DFNY: an Arc B570, or a B580 on a newer driver; T-WW92: any other Intel GPU on Windows, expecting no change) and named in the description; they wait for a maintainer's testing wanted label.
WIP: perf(vk): the Arc B-series compiles shaders side by side by default: a new area no longer freezes the picture for minutesto perf(vk): the Arc B-series compiles shaders side by side by default: a new area no longer freezes the picture for minutesArc B390 (Panther Lake iGPU): one at a time makes the shader preparation about 2.8x slower, and side by side ran with no driver fault. Worth adding to Auto.
On this laptop
intel_compiles.h's rule gives One at a time: the device is0xB080, not0xE2xx, and the driver is 101.9150, older than 101.9154. I prepared the same build's shaders both ways.Hardware: Intel Arc B390 (Panther Lake iGPU, PCI
VEN_8086&DEV_B080, no VRAM mirror), driver 32.0.101.9150, Core Ultra X7 358H (16 threads), 32 GB, Windows 11 Pro Insider Preview build 26220.Build: main
414f56e2(v3.0.0-rc.3-82-g414f56e2, with #252), ascripts/dev_packs.pybase. This PR isn't in it: on this GPU Auto would give One at a time, the same as main's default.Command:
longshot.exe --prepare-shaders --compile-shaders mostin the base's game folder, once with the default (One at a time) and once withRX_VK_NO_INTEL_SERIAL=1(Side by side).RX_VK_NO_INTEL_SERIAL=1)igvk64.dllfaults, device loss,longshot_driver_faults.txtf647a072, before #252, so the cache was nearly cold) tracked it closely: 5146, 9782, 13193 and 15727 pipelines at 60, 300, 600 and 900 s. That run stopped at 16002 when the laptop went into Modern Standby (System log, Kernel-Power 506/507, although the log blamed the driver), and a second side-by-side run finished the rest with no fault.f647a072andfbd42024builds (#189's A/B) had no fault inigvk64.dll. The two hangs on main there were GPU hangs at a compute dispatch, the split-submission problem #189 fixed.Suggestion: Auto side by side on Panther Lake too:
0xB080, its sibling IDs if Intel's list has them, from driver 101.9150. On this laptop One at a time doesn't buy safety: Side by side ran without a single fault. And it costs a lot: a preparation of about 3.5 hours instead of 25 minutes.Not tested yet: the freeze in play that this PR measures on the B580, i.e. new areas entered for the first time in an unprepared folder with each mode. Glad to run it if that's needed to widen the rule.
Logs on request: the three preparations'
longshot_log.txt.9a3fee81f719bdc53b96Rebased onto main
2b1d38c6(head19bdc53b); it conflicted with the Intel quick compute builds row and the weak laptop button.docs/development.md,gpu/vk/vk_menu.cppandgpu/vk/vk_menu.h, each next to the newintel_quicklines. Both sides kept.weak_laptop_apply()setopts.intel_compiles = 0, which meant one at a time on main and means Auto here. It sets 2 (One at a time) now, so the button still does what its help says on every GPU;tests/test_intel_quick_compute.pyreads that line.tests/run_all.py: 494 passed, 15 failed, 70 skipped. The same 15 fail on main2b1d38c6alone on this PC (run one by one there:test_env_on,test_vk_pgo,test_vram_budget_row,test_tested_configurations,test_make_game_cache,test_linux_preflightand nine more), none of them reads a file this PR changes except through main's own lines.cf605c85with the open Arc fixes); the gate and the row's reading are the same lines after the rebase.@ertomas thank you, that is a clear result: 24,456 pipelines in 25 minutes side by side against under half of them in 58 minutes one at a time, and no fault. The rule here is "side by side where it was run", and your B390 (
0xB080, 101.9150) now has a preparation and 30 minutes of play behind it. I would add it to Auto on that evidence. Two things first, so the rule says exactly what was run:vi:lines, and whetherlongshot_driver_faults.txtappears). The description's Tested section has the steps.0xB080, or do you know the B390's siblings from Intel's list? I can only test the B580 here, so I would name just the ID that was run.Without the play run I would still add
0xB080from 101.9150 with your comment as its source, if a maintainer prefers that in this PR instead of a follow-up.19bdc53b96a1682c6e02Rebased onto main
ced37d40(heada1682c6e). The only conflict was ingpu/vk/vk_menu.cpp'sweak_laptop_apply(): main changed the comment onopts.preset = 0;("Minimum's memory budgets kept" became "Minimum's mip trimming kept"). I kept this PR'sopts.intel_compiles = 2, ...line and main's comment. Nothing else changed. No tests were run here. The test and run boxes are still yours to settle.The code is right, and the default is picked from the hardware. I'm leaving a comment review rather than approving: the side-by-side default has one cost the description doesn't give, which is memory. Code review only: no tests were run here.
Rebase: the PR conflicted with main, so I rebased it onto main
ced37d40and pushed it (heada1682c6e, see the comment above). The conflict was one comment inweak_laptop_apply(). I kept youropts.intel_compiles = 2line and main's new comment onopts.preset = 0;.Detection: exact, and no other GPU changes.
intel_side_by_side_measured()is(device & 0xFF00) == 0xE200, with driver>= 101 << 14 | 9154. That is Intel's Windows encoding of 32.0.101.9154.intel_gate_on(), checks0x8086and is_WIN32only, so AMD, NVIDIA and Linux can't reach it.env_override(..., env_value_off(e) ? 2 : 1), the 0..2 row range, the hints table and the weak-laptop button's2all read right.Memory: what's missing. Compiling side by side costs host RAM in the driver's compiler, not VRAM. The card's 10 GB (B570) or 12 GB (B580) doesn't come into it: the pipelines it receives are small. RAM is what grows.
igvk64. With Auto on a B-series, every background compile worker can be in it at once. That was six workers on your i5-13600K, and the count follows the CPU (half_cpus), not the RAM.gpu/vk/prepare_workers.h: 0.4 to 0.5 GB more at the peak for each worker in AMD's compiler. That is why the preparation adds workers only as free memory allows.vk: memory: working set ... (peak ...), private ... MBlines from U1 (Auto) and U2 (=0) to the Measurements.prepare_workers::countdoes. If it's small, one line in Risks saying so settles it.Other points, none blocking:
Before merge: a run in the game is still needed, by hand.
igvk64.dllcrash.Both are open. Neither the rebased head nor the pre-rebase head was run in the game. The measured build was this change on
cf605c85, as the Baseline says.@ -0,0 +14,4 @@/// Whether the row's Auto means side by side on this Intel GPU and Windows driver (deviceID, driverVersion as Vulkan/// reports them: Intel's Windows driverVersion is major << 14 | minor, 101 << 14 | 9154 for 32.0.101.9154)inline bool intel_side_by_side_measured(uint32_t device, uint32_t version) {return (device & 0xFF00u) == 0xE200u && version >= (101u << 14 | 9154u);This matches every Battlemage ID I know of, the Arc Pro B50/B60 workstation cards (0xE211/0xE212) included, and no other Intel GPU. The rule has no vendor check of its own: it is safe only because
intel_gate_on(), its one caller, checks0x8086. That's fine as it is, but a// (Intel only: the caller checks the vendor)here would keep a later caller from asking it about an AMD or NVIDIA ID that happens to be in 0xE2xx.