AMD/RADV (Linux): ~10 fps because each vkQueueSubmit2 costs ~13 ms – batching the replay's submits gives 30-50 fps (patch attached) #413

Closed
opened 2026-11-08 00:02:14 +00:00 by myylkn · 10 comments
myylkn commented 2026-11-08 00:02:14 +00:00 (Migrated from github.com)

Builder version

foliage-linux-updater release (commit 170ce53)

How you built

Hookshot Builder app (Windows)

Game files given to it

A .nup

The error

Hardware: GPD WIN 5 – Ryzen AI Max+ 395, Radeon 8060S (RDNA 3.5 iGPU), RADV STRIX_HALO, Vulkan 1.4, Bazzite (Linux)
Version: foliage-linux-updater (170ce53), game built from my own dump (build e0f3ccfa)

Credit / disclosure: the analysis, the patch and this report were made by Claude (Anthropic's AI
assistant), working with me. I ran every test on my device; all numbers come from the attached logs.

## Problem
~10 fps in gameplay. The GPU is not the limit ("GPU time" ~13 ms a frame), but "queue submit" in
"a frame's replay time" is ~70-80 ms a frame, with ~6 submits a frame (~13 ms each).
The cost grows with the imported guest memory (RX_VK_IMPORT_CHUNK_MB, same scene):
128 MB: 4-8 fps, queue submit 100-208 ms / 16 MB (default): 10 fps, ~80 ms / 4 MB: 11.5 fps, ~69 ms.
Likely cause (not verified in the kernel): on amdgpu every command submission re-validates all
imported host-pointer (userptr) memory, so each vkQueueSubmit2 pays for all of it.

## Patch (attached: amd-batched-submits.patch.txt, 3 commits, applies and builds on ba594da)
Opt-in with RX_VK_BATCH=1 (off = unchanged behaviour):
- submit_recording holds the replay's command buffers and sends them as one vkQueueSubmit2
  (signalling the timeline's highest value plus a second timeline for the recording slots).
- Held work is sent first at every point that needs the GPU or the queue order: waits, readbacks,
  presents, sparse binds, other submits, device-idle waits.
- RX_VK_BATCH_POLL_US: a progress poll (get_replayed) only sends work older than this (2000 used).
- RX_VK_BATCH_MAX: cap on held command buffers (default 32; 8 was worse: more submits).
- kRecordings 24 -> 48, so the ring does not reach held work mid-frame (removed ~10 ms "slot wait").
- The log shows the sends per 120 presents and why ("by reason: poll, wait, slot, present, cap...").

## Results (same places, RX_VK_IMPORT_CHUNK_MB=4)
- ~1300 draws: 11.5 -> ~40 fps
- ~500 draws: -> ~49-50 fps
- heavy, ~2700-2900 draws: -> ~28-31 fps
- queue submit: ~69 ms -> ~5-7 ms a frame; ~1 submit a frame; GPU time ~6-9 ms
- No new errors in the log, no visual problems noticed.

## Not tested
NVIDIA / Windows with RX_VK_BATCH=1, and long play sessions. Built with clang 18 for testing,
not your LLVM 23 toolchain.

## Logs (username and save id removed; no game files)
1_before_default, 2_before_chunk4, 3_after_batched

Visual Studio or Build Tools version, and Windows SDK version

No response

Operating system and free space on the output drive

Bazzite (Linux), RADV / Mesa 26.2.6 933.7 Free

Before you send it

  • I'm on the newest release, or it still fails on it.
  • I searched the open issues for this error.
  • I'm not attaching game files or anything built from them.
### Builder version foliage-linux-updater release (commit 170ce53) ### How you built Hookshot Builder app (Windows) ### Game files given to it A .nup ### The error ```text Hardware: GPD WIN 5 – Ryzen AI Max+ 395, Radeon 8060S (RDNA 3.5 iGPU), RADV STRIX_HALO, Vulkan 1.4, Bazzite (Linux) Version: foliage-linux-updater (170ce53), game built from my own dump (build e0f3ccfa) Credit / disclosure: the analysis, the patch and this report were made by Claude (Anthropic's AI assistant), working with me. I ran every test on my device; all numbers come from the attached logs. ## Problem ~10 fps in gameplay. The GPU is not the limit ("GPU time" ~13 ms a frame), but "queue submit" in "a frame's replay time" is ~70-80 ms a frame, with ~6 submits a frame (~13 ms each). The cost grows with the imported guest memory (RX_VK_IMPORT_CHUNK_MB, same scene): 128 MB: 4-8 fps, queue submit 100-208 ms / 16 MB (default): 10 fps, ~80 ms / 4 MB: 11.5 fps, ~69 ms. Likely cause (not verified in the kernel): on amdgpu every command submission re-validates all imported host-pointer (userptr) memory, so each vkQueueSubmit2 pays for all of it. ## Patch (attached: amd-batched-submits.patch.txt, 3 commits, applies and builds on ba594da) Opt-in with RX_VK_BATCH=1 (off = unchanged behaviour): - submit_recording holds the replay's command buffers and sends them as one vkQueueSubmit2 (signalling the timeline's highest value plus a second timeline for the recording slots). - Held work is sent first at every point that needs the GPU or the queue order: waits, readbacks, presents, sparse binds, other submits, device-idle waits. - RX_VK_BATCH_POLL_US: a progress poll (get_replayed) only sends work older than this (2000 used). - RX_VK_BATCH_MAX: cap on held command buffers (default 32; 8 was worse: more submits). - kRecordings 24 -> 48, so the ring does not reach held work mid-frame (removed ~10 ms "slot wait"). - The log shows the sends per 120 presents and why ("by reason: poll, wait, slot, present, cap..."). ## Results (same places, RX_VK_IMPORT_CHUNK_MB=4) - ~1300 draws: 11.5 -> ~40 fps - ~500 draws: -> ~49-50 fps - heavy, ~2700-2900 draws: -> ~28-31 fps - queue submit: ~69 ms -> ~5-7 ms a frame; ~1 submit a frame; GPU time ~6-9 ms - No new errors in the log, no visual problems noticed. ## Not tested NVIDIA / Windows with RX_VK_BATCH=1, and long play sessions. Built with clang 18 for testing, not your LLVM 23 toolchain. ## Logs (username and save id removed; no game files) 1_before_default, 2_before_chunk4, 3_after_batched ``` ### Visual Studio or Build Tools version, and Windows SDK version _No response_ ### Operating system and free space on the output drive Bazzite (Linux), RADV / Mesa 26.2.6 933.7 Free ### Before you send it - [x] I'm on the newest release, or it still fails on it. - [x] I searched the open issues for this error. - [x] I'm not attaching game files or anything built from them.
myylkn commented 2026-11-08 00:03:17 +00:00 (Migrated from github.com)
[amd-batched-submits.patch.txt](https://github.com/user-attachments/files/34530972/amd-batched-submits.patch.txt) [hookshot_amd_1_before_default.txt](https://github.com/user-attachments/files/34530973/hookshot_amd_1_before_default.txt) [hookshot_amd_2_before_chunk4.txt](https://github.com/user-attachments/files/34530970/hookshot_amd_2_before_chunk4.txt) [hookshot_amd_3_after_batched.txt](https://github.com/user-attachments/files/34530971/hookshot_amd_3_after_batched.txt)
Azazel0671 commented 2026-11-08 00:13:10 +00:00 (Migrated from github.com)

I have found similar performance issues on cachy os with my sapphire pure 9070. I average somewhere around 13-18 FPS in Kokiri Forrest when not looking at a wall. I built via the app image instead of windows. I have noticed occasionally getting one frame of solid green but im not sure if that is related to the performance issues.

I have found similar performance issues on cachy os with my sapphire pure 9070. I average somewhere around 13-18 FPS in Kokiri Forrest when not looking at a wall. I built via the app image instead of windows. I have noticed occasionally getting one frame of solid green but im not sure if that is related to the performance issues.
NotRexed commented 2026-11-08 00:27:28 +00:00 (Migrated from github.com)

Thank you, this is excellent work and exactly the kind of report that makes a fix easy. The three commits are on main now (2d8b180, b1b7b6a, afac079, authorship kept), and batching is switched on by default when the driver is RADV (aa1a4ce); RX_VK_BATCH=0/1 still overrides. I checked the other side here: on an RTX 4060 Ti forcing it on costs fps (25 -> 16), so it stays off on NVIDIA. It ships in the next release, which is close; if you can, please confirm the numbers with it then.

Thank you, this is excellent work and exactly the kind of report that makes a fix easy. The three commits are on main now (2d8b180, b1b7b6a, afac079, authorship kept), and batching is switched on by default when the driver is RADV (aa1a4ce); RX_VK_BATCH=0/1 still overrides. I checked the other side here: on an RTX 4060 Ti forcing it on costs fps (25 -> 16), so it stays off on NVIDIA. It ships in the next release, which is close; if you can, please confirm the numbers with it then.
myylkn commented 2026-11-08 00:57:41 +00:00 (Migrated from github.com)

Thank you! One more data point for the RADV default: RX_VK_BATCH_POLL_US mattered as much as batching itself here.
With RX_VK_BATCH=1 alone, get_replayed() polls flushed 8-16 times a frame (~27 fps at ~1300 draws, queue submit ~25 ms);
with RX_VK_BATCH_POLL_US=2000 it dropped to ~1-2 flushes a frame (~40 fps, queue submit ~5-7 ms) - see the "by reason"
lines in 3_after_batched. It may be worth defaulting it to ~2000 with RADV too. RX_VK_IMPORT_CHUNK_MB=4 also helped
slightly (10 -> 11.5 fps before batching). I'll confirm the numbers with the next release.

(Written with help from Claude, Anthropic's AI assistant.)

Thank you! One more data point for the RADV default: RX_VK_BATCH_POLL_US mattered as much as batching itself here. With RX_VK_BATCH=1 alone, get_replayed() polls flushed 8-16 times a frame (~27 fps at ~1300 draws, queue submit ~25 ms); with RX_VK_BATCH_POLL_US=2000 it dropped to ~1-2 flushes a frame (~40 fps, queue submit ~5-7 ms) - see the "by reason" lines in 3_after_batched. It may be worth defaulting it to ~2000 with RADV too. RX_VK_IMPORT_CHUNK_MB=4 also helped slightly (10 -> 11.5 fps before batching). I'll confirm the numbers with the next release. (Written with help from Claude, Anthropic's AI assistant.)
NotRexed commented 2026-11-08 01:02:07 +00:00 (Migrated from github.com)

The new release is out: https://github.com/NotRexed/Hookshot/releases/tag/no-visual-studio. Please rebuild with it and tell me here whether it's fixed for you (attach hookshot_log.txt if not).

The new release is out: https://github.com/NotRexed/Hookshot/releases/tag/no-visual-studio. Please rebuild with it and tell me here whether it's fixed for you (attach hookshot_log.txt if not).
myylkn commented 2026-11-08 01:45:26 +00:00 (Migrated from github.com)

Confirmed with the no-visual-studio release on the GPD WIN 5 (Radeon 8060S, RADV, Bazzite):
"batched submits on (RX_VK_BATCH, on with RADV)", ~1 submit a frame, queue submit ~4 ms a frame.
Same route as before: ~470 draws ~51 fps, ~800 draws 45-48, ~1600 draws 38-40, ~2800 draws ~35
(was ~10 fps everywhere before the fix; the new release's CPU work helps most in the heavy scenes).

One thing that matters on RADV: with the default RX_VK_BATCH_POLL_US=0, the progress polls flushed
~750 times per 120 presents ("by reason: poll 750") and fps dropped noticeably; with
RX_VK_BATCH_POLL_US=2000 it is "poll 0", one flush per present. It may be worth defaulting it to
~2000 with RADV as well. Also used RX_VK_IMPORT_CHUNK_MB=4.

(Written with help from Claude, Anthropic's AI assistant.)

Confirmed with the no-visual-studio release on the GPD WIN 5 (Radeon 8060S, RADV, Bazzite): "batched submits on (RX_VK_BATCH, on with RADV)", ~1 submit a frame, queue submit ~4 ms a frame. Same route as before: ~470 draws ~51 fps, ~800 draws 45-48, ~1600 draws 38-40, ~2800 draws ~35 (was ~10 fps everywhere before the fix; the new release's CPU work helps most in the heavy scenes). One thing that matters on RADV: with the default RX_VK_BATCH_POLL_US=0, the progress polls flushed ~750 times per 120 presents ("by reason: poll 750") and fps dropped noticeably; with RX_VK_BATCH_POLL_US=2000 it is "poll 0", one flush per present. It may be worth defaulting it to ~2000 with RADV as well. Also used RX_VK_IMPORT_CHUNK_MB=4. (Written with help from Claude, Anthropic's AI assistant.)
myylkn commented 2026-11-08 02:05:09 +00:00 (Migrated from github.com)

Profile of the remaining limit on RADV (no-visual-studio release, Radeon 8060S, Bazzite), in case it helps
with the next step. With batching, Presentation Thread is the busiest thread (HOS_PROFILE: ~73-84% of a core;
sead::MainThread ~20%). HOS_SAMPLE on it during gameplay (summary + full samples attached, names from the
release's hookshot_vk.so):

  • draw ~35% inclusive (build_descriptors ~13%, program_for ~8%)
  • RADV ~23%: present_image ~14% (its own vkQueueSubmit2 + present each frame), queue_flush_locked ~8%
  • ~22% the thread waiting in the host (libc under hookshot+1bfc99eb)
    Idea, untested: the present's submit is a second driver submission every frame on RADV; folding the held
    batch into it (or the present's command buffer into the batch) might save part of that ~14%.
    Current fps on the same route: ~35 (heavy) to ~51 (light), with RX_VK_BATCH_POLL_US=2000.

(Profile analysis written with help from Claude, Anthropic's AI assistant.)

hookshot_presentation_samples_radv.txt.gz
presentation_thread_profile_summary.txt

Profile of the remaining limit on RADV (no-visual-studio release, Radeon 8060S, Bazzite), in case it helps with the next step. With batching, Presentation Thread is the busiest thread (HOS_PROFILE: ~73-84% of a core; sead::MainThread ~20%). HOS_SAMPLE on it during gameplay (summary + full samples attached, names from the release's hookshot_vk.so): - draw ~35% inclusive (build_descriptors ~13%, program_for ~8%) - RADV ~23%: present_image ~14% (its own vkQueueSubmit2 + present each frame), queue_flush_locked ~8% - ~22% the thread waiting in the host (libc under hookshot+1bfc99eb) Idea, untested: the present's submit is a second driver submission every frame on RADV; folding the held batch into it (or the present's command buffer into the batch) might save part of that ~14%. Current fps on the same route: ~35 (heavy) to ~51 (light), with RX_VK_BATCH_POLL_US=2000. (Profile analysis written with help from Claude, Anthropic's AI assistant.) [hookshot_presentation_samples_radv.txt.gz](https://github.com/user-attachments/files/34535669/hookshot_presentation_samples_radv.txt.gz) [presentation_thread_profile_summary.txt](https://github.com/user-attachments/files/34535668/presentation_thread_profile_summary.txt)
Azazel0671 commented 2026-11-08 02:26:26 +00:00 (Migrated from github.com)

On the new release I experience a performance bump to about 20-23 FPS under the same circumstances but now have a lot of things flickering fairly frequently such as the grass and other parts of the environment.

hookshot_log.txt

On the new release I experience a performance bump to about 20-23 FPS under the same circumstances but now have a lot of things flickering fairly frequently such as the grass and other parts of the environment. [hookshot_log.txt](https://github.com/user-attachments/files/34535939/hookshot_log.txt)
Azazel0671 commented 2026-11-08 02:52:47 +00:00 (Migrated from github.com)

Follow up: The fps seems to have dipped back down to the initial levels after I beat the first dungeon, not sure why this happened.

Follow up: The fps seems to have dipped back down to the initial levels after I beat the first dungeon, not sure why this happened.
NotRexed commented 2026-11-08 09:56:29 +00:00 (Migrated from github.com)

The replay's submits were batched (PRs merged since), and release faster-fps adds per-queue fences (about 33 to 47 fps here). Please update and open a new issue with your fps and log if RADV is still slow.

The replay's submits were batched (PRs merged since), and release faster-fps adds per-queue fences (about 33 to 47 fps here). Please update and open a new issue with your fps and log if RADV is still slow.
Commenting is not possible because the repository is archived.
No milestone
No assignees
1 participant
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/Hookshot#413
No description provided.