Game: on a 4 GB laptop GPU, readbacks wait ~6.5 ms for the whole submission (38 fps; 47.5 with RX_VK_NO_READBACK_WAIT=1) #241

Open
opened 2026-11-13 16:45:50 +00:00 by mage_92 · 1 comment

Longshot version

v3.0.0-rc.3

Channel

Release candidate

What kind of problem

Low fps or stutter

What happened

On a laptop with a 4 GB RTX 3050 Ti, Longshot v3.0.0-rc.3 runs at about 38 fps where Hookshot v2.1.0 ran at about 47 fps, at the same spot and settings. The GPU sits at ~78% (94% on Hookshot) and the replay itself got faster (submit ~9 ms against ~16 ms on Hookshot), so the frames are lost waiting, not working.

The log shows the game's job threads waiting on GPU readbacks for the whole submission:

[hos ModuleSystemWorker2] vk: readbacks of GPU results: 265 of 3000 waited for their write-back, 6.48 ms each; 0 looked at the stopped queues first, 261 waited for their submission's last part (guest memory read in place after theirs)

Hookshot v2.1.0 on the same machine: 978 of 3000 waited for their write-back, 0.00 ms each.

As far as I can read vk_replay.cpp, the by-part wait (RX_VK_READBACK_PART) is skipped here because not every pool fits in the mirrors on a 4 GB card (in_place_after), so every waited readback waits for the submission's last part. The log at the default budget:

vk: pool 0x... (20 MB) stays in system memory: the mirrors have 248 MB of 256
vk: 23 pools mirrored in VRAM (256 MB)

With 512 MB of mirrors 8 pools (~450 MB) still stay out. With RX_VK_MIRROR_MB=1024 or 1280 two pools still stay out, the waits stay at ~7.7 ms, and it gets slower (35.7 / 36.5 fps, VRAM pressure).

RX_VK_NO_READBACK_WAIT=1 brings it back to Hookshot's speed: 47.5 fps, GPU at 94%. I watched for the exposure flashes the wait was added for and saw none, and a run with a screenshot every 7 frames (about 500 pictures each, with and without the wait, standing still) showed no flash pattern either. That is one spot and a few minutes, so it is no proof they can't happen.

All measurements: Kokiri Forest path outside Link's house (same save, standing still), 30 s settle then 60 s measured, handheld profile, render 75%, frame generation Auto, CPU power limit held at 35 W, sound on, frame rate cap 60 with pacing on.

Run Game fps (median) GPU busy
rc.3, defaults above 37.8 / 38.2 (two runs) 78-79%
rc.3, RX_VK_NO_READBACK_WAIT=1 47.5 / 47.6 (two runs) 94%
Hookshot v2.1.0, same settings 47.0 91%
rc.3, VRAM budget 3.6 GB, no preset caps (512 MB mirrors) 38.3 78%
rc.3, RX_VK_MIRROR_MB=1024, VRAM budget 2.2 GB 35.7 78%
rc.3, RX_VK_WB_MAX_KB=1024 (the readme asks for laptop results) 38.2, no change 78%
rc.3, RX_VK_PRESENT_THREAD=1 38.2 (steadier: worst 36.9 against 27) 79%
rc.3, HOS_NATIVE_ZSTD=1 38.4 (worst 37.4) 78%
rc.3, LONGSHOT_OCCLUSION_OFF=1 39.2 80%
rc.3, Auto (this PC) as the first start chose it (docked, 50%) 35.8 70%

Two smaller things from the same runs, in case they help:

  • HOS_NO_PACING=1 (useful on Hookshot against the 33/50/67 ms steps) makes the opening movie and menus run fast on Longshot. Probably expected now that pacing changed, but older guides still suggest it.
  • The shader preparation logged 5 driver faults on NVIDIA 580.178.04 (longshot_driver_faults.txt); the run carried on.

Where in the game

Kokiri Forest, the path outside Link's house

How often

Every time

Graphics card and driver version

NVIDIA GeForce RTX 3050 Ti Laptop GPU (4 GB), NVIDIA 580.178.04

CPU, RAM and operating system

Intel Core i9-12900HK (laptop, PL1 held at 35 W), 15 GB RAM, Fedora 43 KDE (Wayland), kernel 7.2

Changes from the defaults

Options: handheld profile, render 75%, frame generation Auto, VRAM budget 2.2 GB (from the Auto preset). Environment: RX_VK_TEX_MAX_DIM=1024 RX_VK_COMPACT=1 RX_VK_AUTO_TUNE=0 RX_VK_MOVIE_UPSCALE=linear RX_VK_BC_IDLE_S=0, plus the switch named in each row.

longshot_log.txt

Attached below: one run with the defaults and one with RX_VK_NO_READBACK_WAIT=1 (home paths removed). No game files.

### Longshot version v3.0.0-rc.3 ### Channel Release candidate ### What kind of problem Low fps or stutter ### What happened On a laptop with a 4 GB RTX 3050 Ti, Longshot v3.0.0-rc.3 runs at about **38 fps** where Hookshot v2.1.0 ran at about **47 fps**, at the same spot and settings. The GPU sits at ~78% (94% on Hookshot) and the replay itself got faster (submit ~9 ms against ~16 ms on Hookshot), so the frames are lost waiting, not working. The log shows the game's job threads waiting on GPU readbacks for the whole submission: ``` [hos ModuleSystemWorker2] vk: readbacks of GPU results: 265 of 3000 waited for their write-back, 6.48 ms each; 0 looked at the stopped queues first, 261 waited for their submission's last part (guest memory read in place after theirs) ``` Hookshot v2.1.0 on the same machine: `978 of 3000 waited for their write-back, 0.00 ms each`. As far as I can read `vk_replay.cpp`, the by-part wait (`RX_VK_READBACK_PART`) is skipped here because not every pool fits in the mirrors on a 4 GB card (`in_place_after`), so every waited readback waits for the submission's last part. The log at the default budget: ``` vk: pool 0x... (20 MB) stays in system memory: the mirrors have 248 MB of 256 vk: 23 pools mirrored in VRAM (256 MB) ``` With 512 MB of mirrors 8 pools (~450 MB) still stay out. With `RX_VK_MIRROR_MB=1024` or `1280` two pools still stay out, the waits stay at ~7.7 ms, and it gets slower (35.7 / 36.5 fps, VRAM pressure). `RX_VK_NO_READBACK_WAIT=1` brings it back to Hookshot's speed: **47.5 fps**, GPU at 94%. I watched for the exposure flashes the wait was added for and saw none, and a run with a screenshot every 7 frames (about 500 pictures each, with and without the wait, standing still) showed no flash pattern either. That is one spot and a few minutes, so it is no proof they can't happen. All measurements: Kokiri Forest path outside Link's house (same save, standing still), 30 s settle then 60 s measured, handheld profile, render 75%, frame generation Auto, CPU power limit held at 35 W, sound on, frame rate cap 60 with pacing on. | Run | Game fps (median) | GPU busy | |---|---|---| | rc.3, defaults above | 37.8 / 38.2 (two runs) | 78-79% | | rc.3, `RX_VK_NO_READBACK_WAIT=1` | 47.5 / 47.6 (two runs) | 94% | | Hookshot v2.1.0, same settings | 47.0 | 91% | | rc.3, VRAM budget 3.6 GB, no preset caps (512 MB mirrors) | 38.3 | 78% | | rc.3, `RX_VK_MIRROR_MB=1024`, VRAM budget 2.2 GB | 35.7 | 78% | | rc.3, `RX_VK_WB_MAX_KB=1024` (the readme asks for laptop results) | 38.2, no change | 78% | | rc.3, `RX_VK_PRESENT_THREAD=1` | 38.2 (steadier: worst 36.9 against 27) | 79% | | rc.3, `HOS_NATIVE_ZSTD=1` | 38.4 (worst 37.4) | 78% | | rc.3, `LONGSHOT_OCCLUSION_OFF=1` | 39.2 | 80% | | rc.3, Auto (this PC) as the first start chose it (docked, 50%) | 35.8 | 70% | Two smaller things from the same runs, in case they help: - `HOS_NO_PACING=1` (useful on Hookshot against the 33/50/67 ms steps) makes the opening movie and menus run fast on Longshot. Probably expected now that pacing changed, but older guides still suggest it. - The shader preparation logged 5 driver faults on NVIDIA 580.178.04 (`longshot_driver_faults.txt`); the run carried on. ### Where in the game Kokiri Forest, the path outside Link's house ### How often Every time ### Graphics card and driver version NVIDIA GeForce RTX 3050 Ti Laptop GPU (4 GB), NVIDIA 580.178.04 ### CPU, RAM and operating system Intel Core i9-12900HK (laptop, PL1 held at 35 W), 15 GB RAM, Fedora 43 KDE (Wayland), kernel 7.2 ### Changes from the defaults Options: handheld profile, render 75%, frame generation Auto, VRAM budget 2.2 GB (from the Auto preset). Environment: `RX_VK_TEX_MAX_DIM=1024 RX_VK_COMPACT=1 RX_VK_AUTO_TUNE=0 RX_VK_MOVIE_UPSCALE=linear RX_VK_BC_IDLE_S=0`, plus the switch named in each row. ### longshot_log.txt Attached below: one run with the defaults and one with `RX_VK_NO_READBACK_WAIT=1` (home paths removed). No game files.
Author

Update on nightly-143-9c9d69ed and nightly-144-f804b7b8 (same laptop: RTX 3050 Ti Laptop 4 GB, driver 580.178, i9-12900HK, Fedora 43), with RX_VK_NO_READBACK_WAIT=1 as before. Kokiri Forest path, 75 % render scale, no frame generation, V-Sync On; 60 s each after 30 s. "Standing" is the same spot each run; "walking" is a scripted walk with the camera turning (more draws, ~1,500 against ~1,110).

1. Sparse mirrors (#250, on by default) double the replay's CPU time on this card. Related: #585 (RX 5600 XT 6 GB, GPU side). Here it is the CPU side: every part of the submit (draws, descriptors, commands) takes about twice as long.

nightly-143, standing fps (median) replay submit a frame
defaults 46.5 15.9 ms
RX_VK_MIRROR_SPARSE=0 54.1 8.6 ms
RX_VK_MIRROR_SPARSE=0, second run 53.9 8.3 ms

2. The replay's reserved core on Linux (#445). replays run on logical processors 0xc00 pins the replay to one P-core of this hybrid CPU (6 P-cores, 8 E-cores), while the game was started on the P-cores. I turn it off with RX_VK_REPLAY_PIN=0 HOS_RESERVE_CORE=0. I measured it only together with sparse mirrors on, so I have no number of its own on Longshot; on Hookshot v2.0.12 the reserved core cost this machine about 20 % (30.5 against 38.1 fps).

3. The VRAM budget row's 4 GB step caps the mirrors at 256 MB, half of Auto's 512 on this card. With vram_budget=1 the log says the mirrors have 256 MB of 256, and the two pools the GPU reads most (160 MB and 132 MB, ~26 GB of bound ranges every 600 submits) stay in system memory. RX_VK_MIRROR_MB on nightly-144 gives the following (several runs each, the GPU time from the renderer's log). These builds carry a local patch that changes which pools get the room once the mirrors are full, so the rows give the budget's effect, not stock main's exact numbers:

mirrors standing: fps standing: GPU a frame walking: fps (3 runs) walking: GPU a frame
256 MB (the row's 4 GB step) 54.2-55.0 15.2-15.4 ms 47.1 / 47.7 / 46.6 16.8-17.1 ms
512 MB (Auto on 4 GB) 54.7-58.8, most ~57 13.6-15.0 ms 48.0 / 46.9 / 47.6 16.1-16.6 ms
640 MB 51-60, unsteady 12.3-16.2 ms 48.3 / 47.8 / 42.2 16.1-19.3 ms
768 MB 51.5 16.0 ms — —

On a 4 GB card, 512 MB looks like the right size; past it, the textures and the mirrors no longer fit together. Which of the big pools gets a mirror changes from run to run (first come, first served), and that explains most of the spread at 512 and 640 MB.

4. MIRROR_REFUSED for good after one failed allocation. I saw it here too: the 132 MB pool once went to state 3 and stayed in system memory for the rest of the run. +1 for the retry in ea6dc5f5 (#288).

On this laptop, standing, the CPU sets the frame rate (the replay ~8.5 ms, the game's threads on 6 P-cores at 89-93 °C). Walking, the GPU does: 16.5 ms a frame, of which, with RX_VK_PASS_TIMING=1, render passes take 8.5 ms, dispatches 5.5 ms, barriers 1.1 ms and write-backs 0.9 ms.

Update on nightly-143-9c9d69ed and nightly-144-f804b7b8 (same laptop: RTX 3050 Ti Laptop 4 GB, driver 580.178, i9-12900HK, Fedora 43), with `RX_VK_NO_READBACK_WAIT=1` as before. Kokiri Forest path, 75 % render scale, no frame generation, V-Sync On; 60 s each after 30 s. "Standing" is the same spot each run; "walking" is a scripted walk with the camera turning (more draws, ~1,500 against ~1,110). **1. Sparse mirrors (#250, on by default) double the replay's CPU time on this card.** Related: #585 (RX 5600 XT 6 GB, GPU side). Here it is the CPU side: every part of the submit (draws, descriptors, commands) takes about twice as long. | nightly-143, standing | fps (median) | replay submit a frame | |---|---|---| | defaults | 46.5 | 15.9 ms | | `RX_VK_MIRROR_SPARSE=0` | **54.1** | **8.6 ms** | | `RX_VK_MIRROR_SPARSE=0`, second run | 53.9 | 8.3 ms | **2. The replay's reserved core on Linux (#445).** `replays run on logical processors 0xc00` pins the replay to one P-core of this hybrid CPU (6 P-cores, 8 E-cores), while the game was started on the P-cores. I turn it off with `RX_VK_REPLAY_PIN=0 HOS_RESERVE_CORE=0`. I measured it only together with sparse mirrors on, so I have no number of its own on Longshot; on Hookshot v2.0.12 the reserved core cost this machine about 20 % (30.5 against 38.1 fps). **3. The VRAM budget row's 4 GB step caps the mirrors at 256 MB, half of Auto's 512 on this card.** With `vram_budget=1` the log says `the mirrors have 256 MB of 256`, and the two pools the GPU reads most (160 MB and 132 MB, ~26 GB of bound ranges every 600 submits) stay in system memory. `RX_VK_MIRROR_MB` on nightly-144 gives the following (several runs each, the GPU time from the renderer's log). These builds carry a local patch that changes which pools get the room once the mirrors are full, so the rows give the budget's effect, not stock main's exact numbers: | mirrors | standing: fps | standing: GPU a frame | walking: fps (3 runs) | walking: GPU a frame | |---|---|---|---|---| | 256 MB (the row's 4 GB step) | 54.2-55.0 | 15.2-15.4 ms | 47.1 / 47.7 / 46.6 | 16.8-17.1 ms | | 512 MB (Auto on 4 GB) | 54.7-58.8, most ~57 | 13.6-15.0 ms | 48.0 / 46.9 / 47.6 | 16.1-16.6 ms | | 640 MB | 51-60, unsteady | 12.3-16.2 ms | 48.3 / 47.8 / 42.2 | 16.1-19.3 ms | | 768 MB | 51.5 | 16.0 ms | — | — | On a 4 GB card, 512 MB looks like the right size; past it, the textures and the mirrors no longer fit together. Which of the big pools gets a mirror changes from run to run (first come, first served), and that explains most of the spread at 512 and 640 MB. **4. `MIRROR_REFUSED` for good after one failed allocation.** I saw it here too: the 132 MB pool once went to state 3 and stayed in system memory for the rest of the run. +1 for the retry in ea6dc5f5 (#288). On this laptop, standing, the CPU sets the frame rate (the replay ~8.5 ms, the game's threads on 6 P-cores at 89-93 °C). Walking, the GPU does: 16.5 ms a frame, of which, with `RX_VK_PASS_TIMING=1`, render passes take 8.5 ms, dispatches 5.5 ms, barriers 1.1 ms and write-backs 0.9 ms.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#241
No description provided.