WIP: fix(vk): on Intel iGPUs a split submission's uniform updates are written by its last part #189
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 project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!189
Loading…
Reference in a new issue
No description provided.
Delete branch "Guep/Longshot:fix-split-ub-flush"
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 Intel iGPUs, Kokiri Forest shows big white glowing blocks and haze over the trees and houses, and save thumbnails come out white.
What changed
maybe_split(gpu/vk/vk_replay.cpp) no longer callsflush_ub_updatesat a part's end, nor movesub_first_of_recording, on Intel GPUs whose buffer pools have no VRAM mirror (!pools_mirrored(): the iGPUs). A long submission is cut into parts (RX_VK_CHUNK); each part's end wrote the stream's uniform updates into guest memory halfway through the submission. Now the last part writes all of them, as an unsplit submission does infinish_recording, as the parallel replay does, and asRX_VK_CHUNK=0does.ub_overlay, fromub_updates[0..lim)), the same bytes either way. It is everything else that reads guest memory after a part's end: a later part's storage, vertex, index or texture reads of an updated range, and, without mirrors, the game's own CPU reads, since the GPU then writes the memory the game sees partway through its frame. Which of those draws the white blocks is not pinned down yet (noRX_VK_DUMPof a white frame); that is why the default stays where it was seen, Intel without mirrors, rather than every GPU without mirrors.UPDATE_UBlands in memory in stream order, so for such reads the per-part write is arguably closer to the console in timing; but no Longshot path other than the split ever showed a mid-submission write, and the unsplit path, the one every GPU runs most of the time, has always deferred. This change makes the split agree with it; it does not claim the deferral matches the console.tests/test_split_ub_flush.py(source checks onmaybe_split, and the default compiled alone against a table: unset, off on Intel without mirrors, on for Intel with mirrors and elsewhere, mirrors or not; set, the switch on any GPU). No game or GPU needed.docs/development.md, a row indocs/tested-configurations.md.Flags and settings
RX_VK_SPLIT_UBFLUSH(new)1: each part of a split submission writes the uniform updates at its end (the old behaviour);0: only the last part does0on Intel without VRAM mirrors (vendor 0x8086 and!pools_mirrored(): the iGPUs),1elsewhere, Arc discrete included=0), AMD APUs and the Steam Deck, NVIDIA, LinuxMeasurements
main:
9a186f71(2026-11-13)this PR: ls/fix-split-ub-flush @
0a5d21e6Hardware: Lenovo 83DJ; Intel Arc Graphics (Core Ultra 7 155H iGPU, Meteor Lake), driver 32.0.101.9175; Core Ultra 7 155H; 32 GB; Windows 11 Pro (26300)
Scene: a save in Kokiri Forest, then the control bridge's teleport to Kakariko Village and to Death Mountain Trail, about 130 s in each; output 1920x1080, Render resolution 4, handheld profile
Method: 3 runs per side, interleaved with the other Intel PRs' builds (main, split, pcache, fadd, then again),
RX_VK_NO_PREDICT=1on every side. Per run and area: the median of thefps over the last 5 swindows (the first 4 after the teleport left out: the load) and of theGPU time ... ms a framelines inlongshot_log.txt; an area counts only with 5 windows or more. The table gives the median over the runs, n the runs that count, and the runs that ended in a device loss, with whereHow to reproduce: a save outside Link's house, the options above,
RX_VK_NO_PREDICT=1; teleport with the control bridge (cheats: teleport) to Kakariko Village, then Death Mountain Trail, about 130 s each; read the fps and GPU time lines oflongshot_log.txtper area9a186f710a5d21e6The fps and GPU-time differences are within this series' run-to-run spread (3 runs a side, fewer where the device was lost): no cost, no gain claimed.
Testing
Tested: Windows 11, Intel Arc iGPU (Meteor Lake): the route above, 3 runs per side interleaved with main and the two other Intel PRs' builds, a capture every 60 frames. White blocks (bright flat blocks per capture, the title screen left out): main 17 captures in 1 run of 3, up to 10.2 % of the picture; this PR 0 in 3 runs (the other two Intel PRs' builds 0 too: here only one run of main in three shows them, so this series alone is thin evidence; ploob-boop's Arc 140V runs and the game-free test are the rest). Device lost in Kakariko Village in 2 of 3 runs on both sides here.
The device losses of the earlier 300 s series (
docs/tested-configurations.md): 2 of 8 runs withRX_VK_SPLIT_UBFLUSH=1and 5 of 8 without, on one build that also had #190 and the 32-lane pin change. Those are the same compute programs (499dbfd0, a float add to a storage buffer; ab7699ee, likely one; aba5e6af, not classified) that lose the device with the float-add loop on main and on the other Intel builds: 12 of 18 runs in #191's series, 0 of 6 with #191's native add, and 0 in 6 route runs on 13/11 of a build with this change and #191 together. So they are most likely the loop's and not this change's, but 5 of 8 against 2 of 8 is not explained by that alone: it stays open until runs with #191 merged, on and off, say otherwise.Not tested: AMD and NVIDIA, Arc discrete (all keep the old code unless
RX_VK_SPLIT_UBFLUSH=0), the Steam Deck and AMD APUs (no mirrors, the same code path as Intel's iGPUs, but not seen there), Linux/Mesa ANV, Lunar Lake on Longshot's build.Needs other testers:
RX_VK_CHUNK=0(request to open)RX_VK_SPLIT_UBFLUSH=0: the same spot, expecting the same picture and fps as without it, before the default can widen (request to open)RX_VK_SPLIT_UBFLUSH=0and=1: the same spot, expecting the same picture, before the default covers every GPU without mirrors (request to open)Screenshots
To add: main and this PR at the same spot, from this series' captures.
Risk and rollback
On Intel iGPUs, a non-uniform read in a later part (storage, vertex, index, texture) of a range an earlier part's
UPDATE_UBwrote now sees the value before the update, as an unsplit submission has always given it; none was seen to need the newer one. Uniform bindings are unchanged (the overlay).RX_VK_SPLIT_UBFLUSH=1restores the old behaviour; reverting the commit is enough.Reviewer notes
The device losses: see Testing. No textual conflict with #222 (
vk_draw.cppagainstvk_replay.cpp); 222's snapshot path is reached only for ranges no update overlaps and its reuse map is cleared per recording, so per part: the two do not interact in the code, though both gate on GPUs without mirrors.Issues
See NotRexed/Hookshot#999
Checklist
For everyone
type(scope): description).main. (onfbd42024; measured on9a186f71before the rebase)python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above). (run on1c0e220a: 449 passed, 9 failed, 72 skipped; mainfbd42024fails 9 on this Windows PC the same way: test_bake_portability, test_bug_report, test_check_third_party, test_fpx_sticky, test_portable_builder_home, test_portable_builder_startup, test_prepare_at_build, test_release, test_spawn_emit (all but test_prepare_at_build fail here too); plus test_pipeline_cache_save, whose compile ran out of its 60 s while a 12-job game build ran beside it, in code this PR does not touch: to run again on an idle PC before ticking)third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested-configurations.mdfor each measured run. (the row there is the earlier 300 s series; the route series above still needs one)mainand passing here.tests/that reads changed source updated in this PR, not weakened.The change itself looks right to me. With it, a split submission writes its uniform updates to guest memory the same way an unsplit one does (
finish_recording), the same way the parallel replay does ("the uniform updates are written to guest memory at the submission's end"), and the same wayRX_VK_CHUNK=0does. I traced the deferral end to end and found no stale or out-of-order reads:ub_overlayandub_readbuild every overlapping range fromub_updates[0..lim). They don't start atub_first_of_recording(except withRX_VK_UB_CUR_ONLY=1, where keeping the index unmoved is the correct choice). So a draw in a later part that binds an updated range still gets its overlay copy, with the same bytes as before.UPDATE_UBwrote. They now see the pre-update value, which is what an unsplit submission has always given them.finish_recordingflushes from the unmovedub_first_of_recording. A burst keeps one window.ub_prunecan't drop the open submission's entries, because no part signals the timeline.device_lost()is[[noreturn]], so nothing after it runs either way.The existing checks that cut
maybe_split(test_parallel_small_cb.py) only read up toend_pass(cmd);, so the reshape doesn't break them. Main has moved on (it's 16 commits ahead, including #197 invk_replay.cpp), but none of those commits touchesmaybe_split.There's no textual conflict with #222: it touches
vk_draw.cppand this PR touchesvk_replay.cpp. 222's snapshot path is only reached for ranges no update overlaps (the overlay path runs first), and its reuse map is cleared per recording, which means per part. So the two don't interact in the code. They do overlap in what they gate, though (below).Must change
NotRexed/Hookshot#999appears in thedocs/development.mdrow, in thedocs/tested-configurations.mdrow (along withNotRexed/Hookshot#2564) and in themaybe_splitcomment. On Forgejo,owner/repo#Nlinks to a repo on git.magicbean.dev, not to GitHub. Please use https://github.com/NotRexed/Hookshot/issues/999 (and the full URL for 2564).tested-configurationsrow says the device was lost in 2 of 8 old runs and 5 of 8 new runs, but the PR body only mentions the route series (2 of 3 each side). Either show that 5/8 is noise (more interleaved runs, or plain main's rate on the same build), or say plainly that it is open. Don't leave it only in the docs row.pr ready:run_all.py;tested-configurationsrow for the route series;Should change
Gate on what the bug depends on, not on the vendor. The flag table says the change "should help on any GPU whose buffer pools have no VRAM mirror".
RX_VK_UB_SNAPSHOT(and 222's widened version of it) keys on!pools_mirrored(). This PR keys onvendorID == 0x8086, which has two effects:mirror_on()is on for discrete cards. There,gpu_writegoes to the mirror, and the write-back happens atmemory_end_submissionof a different part than before.Suggestion:
!pools_mirrored() && vendor == Intelfor now, or!pools_mirrored()once a Deck run is in. Either way, extend the test's table to cover both cases.Say which reader actually changed. The comment says later parts' draws "read those ranges from guest memory". But a uniform-buffer binding that overlaps an update never binds guest memory: it gets an overlay copy built from the whole list. So the reader that saw the mid-submission write is not a uniform binding. It's a storage, vertex or texture read, or the game itself on a GPU without mirrors, whose memory the GPU overwrites partway through the frame. Naming it (for example from a capture or
RX_VK_DUMPof a white-block frame) matters for two reasons:UPDATE_UBlands in memory in stream order, so the deferral may be hiding the real hazard rather than fixing it.Take the opposite default to NVIDIA and AMD as a follow-up. Since the unsplit and parallel paths already defer, there's an argument for making
0the default everywhere. The PR's "Needs other testers" item for AMD and NVIDIA is the right way to get there. Please open that test request.@ -209,6 +209,7 @@ Pipeline-cache file ownership, temporary storage and failure behavior are descri| `RX_VK_FETCH_BOUNDS=0` or `1`, `RX_VK_NAN_BITS=0` or `1`, `RX_VK_GATHER_OFFSET=0` or `1` | The translation's vendor and driver workarounds (`gpu/vk/vk_vendor.h`) off or on for one run, whatever the GPU; the log's `vk: vendor fixes` line says which are on. By default: out-of-bounds texel fetches answered with 0 on every GPU but NVIDIA's; NaN tests on a value's bits on AMD's older Windows shader compiler (RX 5000 and RX 6000); gathers nudged by 1/512 of a texel on AMD's and Intel's drivers. They change the shaders' translation (one preparation of the shaders) || `RX_VK_NATIVE_FADD=0` or `1` | The shaders' float adds to storage buffers: 1 the GPU's own atomic where it has `VK_EXT_shader_atomic_float`'s `shaderBufferFloat32AtomicAdd`, 0 a compare-exchange loop on every GPU, the extension not enabled. By default the GPU's own on NVIDIA's driver only, the one it was tried on in the game; on AMD and Intel the loop until runs there show the native add works (the log's `vk: float atomic add on storage buffers:` line says which, and why). The loop gives up after 1024 attempts, and an add that gives up is lost || `RX_VK_UB_WORD_HASH=0` | A/B test: use the old low-address-bit index for cached uniform words (default: mix upper address bits to reduce aligned-buffer collisions) || `RX_VK_SPLIT_UBFLUSH=0` or `1` | A submission cut into parts (`RX_VK_CHUNK`): 1 each part writes the uniform updates recorded so far into game memory at its end, as before; 0 only the last part writes them all, as an unsplit submission does. Default 0 on Intel (white blocks and haze in Kokiri Forest otherwise, NotRexed/Hookshot#999), 1 elsewhere, where it was not measured |Full URL for the issue, please (https://github.com/NotRexed/Hookshot/issues/999). Also, "Default 0 on Intel" covers Arc discrete, which has mirrors and wasn't measured.
@ -22,6 +22,7 @@ otherwise.| 2026-11-12 | main 4dd972a8 + this change, `HOS_VIDEO_INPUT_LIMIT=0` (as main) against the default (16) | Linux (CachyOS, kernel 7.3.3), a private headless sway, scripted input, no sound device (`HOS_AUDIO=0`) | RTX 3090 24 GB, 620.70.06 | Ryzen 9 7900X, 30 GB (the PC was swapping in every run) | 2048x1152, default options, cap 60 | A new game from an empty data folder: the first movie (A after 11 s, about 820 pictures of it), then the second (9,254 pictures) to its end | Three runs each, interleaved. Pictures skipped, first movie: 244, 247, 251 without the limit; 8, 198, 1 with it. Second movie: 123, 700, 98 without; 0, 502, 0 with. In the second run of each side the PC swapped hard and frames were late (177 and 146 frames over 33 ms; 0 to 2 in the others): those skips are the late frames'. Waits of over 90 ms between two pictures in a movie's first 5 s: 44, 43, 43 and 20, 21, 18 without; 1, 0, 0 and 0, 9, 0 with. The second movie ends within 12 ms of its clock on both sides || 2026-11-13 | Hookshot fix/commit-limit 905cb5e1 (NotRexed/Hookshot#2972, ported here as fix/commit-limit), against Hookshot main e0e60920, alternated | Windows | RTX 4060 Ti, - | -, 31 GB (115 GB commit limit) | 3440x1440, muted, the commit rule idle (default `RX_VK_COMMIT_RESERVE_MB`) | Route run: Kokiri, Hyrule Field, Kakariko, 2 runs each | This change: 53 and 57 fps median, p99 40.5 and 36.1 ms, private commit at end 28.9 and 28.6 GB, no `commit limit near` line (the rule never fired). Main: 51 and 50 fps, p99 43.2 and 42.1 ms, 33.4 and 34.8 GB. Run-to-run variation, not the change: it costs nothing when idle || 2026-11-13 | as above, this change only | as above | as above | as above | as above, `RX_VK_COMMIT_RESERVE_MB=38397` (the rule forced, about 25 GB of the game's commit before it kicks in) | as above, 1 run | 54 fps median, p99 38.7 ms, max 881 ms (the run before, rule not firing: 58, 35.6, 881). 52 `commit limit near` lines, texture budget down by the shortfall each time (e.g. 3661 to 2812 MB), headroom 37.4 to 38.4 GB; private commit peak 26.7 GB (30.3 without the rule), VRAM blocks peak 9.0 GB (12.9). The 5 s wait at the limit itself not reached || 2026-11-13 | v2.1.0-rc.3-313-g9b6072c + this PR and two other Intel changes for NotRexed/Hookshot#999 (the pipeline cache fetch lock or the split-submission fix, and compute stages let go of the 32-lane pin as NotRexed/Hookshot#2564 does), the same patch rebased on main e0e6092 for the PR, built from source (llvm-mingw) | Windows 11 Pro (26300), 1920x1080, scripted input | Intel Arc Graphics (Core Ultra 7 155H iGPU, Meteor Lake), 32.0.101.9175 | Core Ultra 7 155H, 32 GB | Render resolution 4, handheld profile; `RX_VK_PASS_TIMING=2`, a screenshot every 60 frames; old/new alternated, the game closed normally; old: `RX_VK_SPLIT_UBFLUSH=1` | Kokiri Forest outside Link's house, standing, 300 s | White blocks over the forest in 9, 7 and 11 frames of the old runs that ran on, 0 in every new run (an earlier series of this change alone: 7, 1, 1 against 0, 0, 0); fps 4.7-5.7 old, 5.7-6.0 new. Device lost in compute programs (ab7699ee, aba5e6af, 499dbfd0) in 2 of 8 old and 5 of 8 new runs over both series; plain main loses it in the same programs |Two things here:
NotRexed/Hookshot#999and#2564should be full URLs.@ -1396,1 +1396,3 @@flush_ub_updates(cmd);// (a part's end does not write the stream's uniform updates recorded so far into guest memory, nor start a new window// of them: the submission's last part writes them all, as an unsplit submission does (finish_recording). Written at// each part's end, the draws of the later parts that read those ranges from guest memory saw a state an unsplit"the draws of the later parts that read those ranges from guest memory": a uniform binding that overlaps an update never reads guest memory.
ub_overlaybuilds a copy fromub_updates[0..lim), not fromub_first_of_recording, so its bytes are the same with or without the per-part flush. The reader that changed must be a non-uniform one (storage, vertex, texture), or the game's own memory on a GPU without mirrors. Could you name it here? It decides the gate, and whether deferring matches the console (whereUPDATE_UBlands in stream order) or only matches the unsplit path.@ -1397,0 +1397,4 @@// of them: the submission's last part writes them all, as an unsplit submission does (finish_recording). Written at// each part's end, the draws of the later parts that read those ranges from guest memory saw a state an unsplit// submission never shows: on Intel, white blocks and haze at Kokiri, and a whole-screen white flash every 8 frames on// the Arc 140V (NotRexed/Hookshot#999). Measured on Intel only, so the default there; RX_VK_SPLIT_UBFLUSH=1: written at each part'sNotRexed/Hookshot#999: please use the full URL, https://github.com/NotRexed/Hookshot/issues/999. On Forgejo,owner/repo#Nresolves to git.magicbean.dev.@ -1397,0 +1401,4 @@// end, as before, =0: at the last part's on any GPU)static const bool part_flush = [] {const char* e = getenv("RX_VK_SPLIT_UBFLUSH");return e ? env_on("RX_VK_SPLIT_UBFLUSH") : dev.props.vendorID != 0x8086;This keys on the vendor. The bug as described (later parts reading guest memory the per-part flush wrote) depends on the pools having no VRAM mirror, as
RX_VK_UB_SNAPSHOTdoes (!pools_mirrored()), and 222 widens that to integrated GPUs.As written:
Suggest
dev.props.vendorID == 0x8086 && !pools_mirrored()(the flush on the default branch inverted), and add mirror cases to the test's table.0a5d21e6611c0e220aa5WIP: fix(vk): on Intel a split submission's uniform updates are written by its last partto WIP: fix(vk): on Intel iGPUs a split submission's uniform updates are written by its last partThank you for tracing it end to end. Rebased on
fbd42024; the changes are in1c0e220a.Must change
docs/development.mdanddocs/tested-configurations.md.run_all.pybelow; the test requests, screenshots, the route row, a Linux build and a second Death Mountain Trail run are still to do beforepr ready.Should change
dev.props.vendorID == 0x8086 && !pools_mirrored()(the per-part flush on everything else, Arc discrete included). The test's table covers mirrors and none on each vendor, 54 cases.RX_VK_DUMPof a white frame so far. That is why the default stays on Intel without mirrors, where it was seen, and the description no longer claims the deferral matches the console, only that it makes the split agree with the unsplit path.tests/run_all.pyon1c0e220a: the same failures as main on this PC, plustest_pipeline_cache_save, whose compile timed out beside a game build (named in the checklist), to run again on an idle PC.Re-review at
1c0e220a. Code only: I didn't build it, run the tests or run the game.Earlier points
Must change:
maybe_splitcomment, the test's docstring,docs/development.mdanddocs/tested-configurations.mdall use https://github.com/NotRexed/Hookshot/issues/999 and https://github.com/NotRexed/Hookshot/pull/2564 now.pr ready: partly done.fbd42024) and therun_all.pyrun.tested-configurationsrow for the route series, a Linux build, and a second Death Mountain Trail run (or drop that row).Should change:
vendorID != 0x8086 || pools_mirrored(), which matchesRX_VK_UB_SNAPSHOTinvk_draw.cpp.pools_mirrored()is declared invk_internal.h, whichvk_replay.cppincludes. It's fixed for the session (mirror_oncaches it), so thestatic constis safe. The test's table covers mirrors and no mirrors for each vendor. The case count is right (54).ub_overlay. They list the readers that do change, say no dump has pinned down which one draws the white blocks, and drop the claim that the deferral matches the console.New since the last review
maybe_splitis unchanged apart from the gate and the comment. On the Meteor Lake iGPU (no mirrors) the new gate gives the same decision as the old one. So the9a186f71/0a5d21e6numbers still hold for that PC. Please say so under Measurements, becausepr statuswarns about the old base.d9648863sincefbd42024. #260 and #234 touchvk_replay.cpp, but neither touchesmaybe_split,flush_ub_updates,finish_recordingorub_first_of_recording. I expect no conflict. Rebase beforepr readyso the box stays true.run_all.pynote reads oddly. "main fails 9 ... (all but test_prepare_at_build fail here too)", plustest_pipeline_cache_save, adds up to 9 on the PR only iftest_prepare_at_buildpasses here. Please list the PR's 9 failures exactly when you run it again on an idle PC.Verdict
Comment, not request changes. The code is right and every earlier must-change point is addressed. Before
pr ready, these are left:run_all.pyon an idle PC, withtest_pipeline_cache_savepassing.tested-configurationsrow for the route series.9a186f71numbers still hold.@ -33,6 +33,7 @@ otherwise.| 2026-11-12 | main 4dd972a8 + this change, `HOS_VIDEO_INPUT_LIMIT=0` (as main) against the default (16) | Linux (CachyOS, kernel 7.3.3), a private headless sway, scripted input, no sound device (`HOS_AUDIO=0`) | RTX 3090 24 GB, 620.70.06 | Ryzen 9 7900X, 30 GB (the PC was swapping in every run) | 2048x1152, default options, cap 60 | A new game from an empty data folder: the first movie (A after 11 s, about 820 pictures of it), then the second (9,254 pictures) to its end | Three runs each, interleaved. Pictures skipped, first movie: 244, 247, 251 without the limit; 8, 198, 1 with it. Second movie: 123, 700, 98 without; 0, 502, 0 with. In the second run of each side the PC swapped hard and frames were late (177 and 146 frames over 33 ms; 0 to 2 in the others): those skips are the late frames'. Waits of over 90 ms between two pictures in a movie's first 5 s: 44, 43, 43 and 20, 21, 18 without; 1, 0, 0 and 0, 9, 0 with. The second movie ends within 12 ms of its clock on both sides || 2026-11-13 | Hookshot fix/commit-limit 905cb5e1 (NotRexed/Hookshot#2972, ported here as fix/commit-limit), against Hookshot main e0e60920, alternated | Windows | RTX 4060 Ti, - | -, 31 GB (115 GB commit limit) | 3440x1440, muted, the commit rule idle (default `RX_VK_COMMIT_RESERVE_MB`) | Route run: Kokiri, Hyrule Field, Kakariko, 2 runs each | This change: 53 and 57 fps median, p99 40.5 and 36.1 ms, private commit at end 28.9 and 28.6 GB, no `commit limit near` line (the rule never fired). Main: 51 and 50 fps, p99 43.2 and 42.1 ms, 33.4 and 34.8 GB. Run-to-run variation, not the change: it costs nothing when idle || 2026-11-13 | as above, this change only | as above | as above | as above | as above, `RX_VK_COMMIT_RESERVE_MB=38397` (the rule forced, about 25 GB of the game's commit before it kicks in) | as above, 1 run | 54 fps median, p99 38.7 ms, max 881 ms (the run before, rule not firing: 58, 35.6, 881). 52 `commit limit near` lines, texture budget down by the shortfall each time (e.g. 3661 to 2812 MB), headroom 37.4 to 38.4 GB; private commit peak 26.7 GB (30.3 without the rule), VRAM blocks peak 9.0 GB (12.9). The 5 s wait at the limit itself not reached || 2026-11-13 | v2.1.0-rc.3-313-g9b6072c + this PR, the pipeline cache fetch lock (#190) and compute stages let go of the 32-lane pin as https://github.com/NotRexed/Hookshot/pull/2564 does, one build for every run, for https://github.com/NotRexed/Hookshot/issues/999; the same patch rebased on main e0e6092 for the PR, built from source (llvm-mingw) | Windows 11 Pro (26300), 1920x1080, scripted input | Intel Arc Graphics (Core Ultra 7 155H iGPU, Meteor Lake), 32.0.101.9175 | Core Ultra 7 155H, 32 GB | Render resolution 4, handheld profile; `RX_VK_PASS_TIMING=2`, a screenshot every 60 frames; old/new alternated, the game closed normally; old: the same build with `RX_VK_SPLIT_UBFLUSH=1` | Kokiri Forest outside Link's house, standing, 300 s | White blocks over the forest in 9, 7 and 11 frames of the old runs that ran on, 0 in every new run (an earlier series of this change alone: 7, 1, 1 against 0, 0, 0); fps 4.7-5.7 old, 5.7-6.0 new. Device lost in compute programs (ab7699ee, aba5e6af, 499dbfd0) in 2 of 8 old and 5 of 8 new runs over both series. The same programs lose it with the float-add loop on main and the other Intel builds (12 of 18 runs in #191's series; 499dbfd0 is a float add to a storage buffer, ab7699ee likely one), none with #191's native add (0 of 6), and none in 6 route runs of a build with this change and #191 together (13/11): most likely the loop's, not this change's, though 5 of 8 against 2 of 8 is not explained |Nit: in a docs file, #190 and #191 don't link anywhere, and on GitHub they would point at Hookshot. Like the PsychoV35 row's link to pulls/108, use #190 and .../pulls/191.
@ -1595,0 +1600,4 @@// through its frame. Written at each part's end, on Intel without mirrors: white blocks and haze at Kokiri, and a// whole-screen white flash every 8 frames on the Arc 140V (https://github.com/NotRexed/Hookshot/issues/999).// Measured on an Intel iGPU only (no mirrors), so the default there; with mirrors (Arc discrete) the write goes to the// mirror and nothing was seen: left as before. RX_VK_SPLIT_UBFLUSH=1: written at each part's end, as before, =0: at theNit: "with mirrors (Arc discrete) the write goes to the mirror and nothing was seen". Nobody ran Arc discrete, so nothing could be seen. Suggest "... goes to the mirror, and it was not tested there: left as before", to match the docs row ("where it was not measured").
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.