You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Random 20 FPS lock and Vulkan renderer slowdowns #50
I am experiencing occasional, seemingly random 20 FPS locks / severe performance slowdowns when using the Vulkan renderer.
The game can run normally at full speed, but at seemingly random times the performance suddenly drops and becomes locked around 20 FPS. The slowdown can persist even after the event that appears to trigger it has passed. It seems to happen a lot with video cutscenes.
This does not appear to be normal shader compilation stutter, as the game can be running normally and then suddenly enter this low-FPS state during gameplay.
Current behaviour
Game normally runs at full speed.
At seemingly random points during gameplay, performance suddenly drops to around 20 FPS.
Once this happens, the game appears to remain locked/limited around 20 FPS rather than briefly stuttering.
Vulkan appears to be particularly affected.
Restarting the game appears to restore normal performance.
The issue does not seem to consistently occur in the same location or during the same action.
Expected behaviour
The game should maintain a consistent frame rate during gameplay, without randomly entering a persistent ~20 FPS state.
Steps to reproduce
Launch Zelda: Wind Waker HD Recompiled using the Vulkan renderer.
Play normally for some time.
At some seemingly random point, performance may suddenly drop to approximately 20 FPS with the GPU usage not rising or CPU usage not increasing
Continue playing and observe that the low frame rate persists.
Thanks for the detailed report, @StonedEdge. v0.2.4 changes exactly the part of the Vulkan renderer that is most likely behind this: the render thread no longer waits for the GPU after every frame on desktop, which in our load tests turned 35–40 fps drops into a steady ~59 fps.
Could you try v0.2.4 and tell us whether the 20 fps lock still happens? If it does, two things would help a lot:
while it is stuck at 20 fps, open the overlay → Graphics → Copy performance report and paste it here;
your platform, GPU and driver, and whether it starts right after a video cutscene (that would point to a presentation mode that doesn't switch back after the video).
Thanks for the report, and sorry I missed your hardware at first: an RK3588 with a Mali-G610. "Drops to 20 fps, CPU and GPU usage don't go up, and only a restart fixes it" points to something sticky rather than plain load. Most likely the game's render or game thread ends up on one of the RK3588's slow Cortex-A55 cores (or a clock governor drops), often right after a low-load phase like a video cutscene, and stays there. Could you try:
Start the game pinned to the fast A76 cores: taskset -c 4-7 ./data/bin/wwhd (or prefix your usual launch command with taskset -c 4-7).
Optionally set the CPU governor to performance for the test.
If it still locks to 20 fps, post the output of cat /sys/class/devfreq/*/cur_freq and the performance report while it's stuck.
If taskset fixes it, we'll pin the game's main threads to the fast cores automatically on big.LITTLE chips. Separately, the next update cuts shader translation and pipeline creation by about 90%, which will help on this chip too.
v0.2.6 is out with the shader change mentioned above (about 90% fewer shader translations and pipelines, fewer stutters). Its performance report also starts with the version, OS, GPU and driver. Still very interested in whether taskset -c 4-7 stops the 20 fps lock.
Thanks, and the new report header is already paying off. In that room your render thread needs about 40 ms per frame (5,800 draws, 6.7 µs each), so it misses even the 33 ms of a 30 fps frame, and vsync turns that into exactly 20 fps. GPU waits are 0, so it's purely the render thread. The biggest part is copying vertex data: 14.8 ms for only 2.9 MB per frame, which is very slow and points at the Mali driver's upload memory. Of those 2.9 MB only about 0.46 MB is actually new each frame.
That is exactly what our buffer cache avoids: it keeps unchanged vertex, index and uniform data on the GPU instead of copying it every frame. It's on by default on macOS but still opt-in on Linux, because we haven't been able to test it there yet, so you'd be the first. Could you try two runs in that same room:
and paste the [vulkan buffer cache] lines from the log (especially any VERIFY MISMATCH, which should never appear, plus the page write faults / protect failures counts).
A normal run with the cache on:
WWHD_VK_BUFFER_CACHE=1 ./data/bin/wwhd
and the "Copy performance report" from the moment you enter that room.
(Use your usual launch command with the variables in front. Alternatively, put WWHD_VK_BUFFER_CACHE=1 on a line in an env.txt next to your settings if your setup uses one.) If it helps as much as we expect, we'll turn the cache on by default on Linux too.
Great news, thanks! That confirms it was the vertex copies through the Mali driver's upload memory. Before we turn the cache on by default on Linux, could you do one correctness run in that same room?
and paste the [vulkan buffer cache] lines from the log (we're looking for any VERIFY MISMATCH, which should never appear, and the page write faults / protect failures counts). A "Copy performance report" from a normal run with WWHD_VK_BUFFER_CACHE=1 in that room would also be nice, so we can see the new frame time. Until then, keep the variable set.
Activity
lschaupp commentedon Oct 7, 2026
Thanks for the detailed report, @StonedEdge. v0.2.4 changes exactly the part of the Vulkan renderer that is most likely behind this: the render thread no longer waits for the GPU after every frame on desktop, which in our load tests turned 35–40 fps drops into a steady ~59 fps.
Could you try v0.2.4 and tell us whether the 20 fps lock still happens? If it does, two things would help a lot:
StonedEdge commentedon Oct 7, 2026
Still happens - tested with v0.2.5. Log at the title when drops to exactly 20fps
lschaupp commentedon Oct 7, 2026
Thanks for the report, and sorry I missed your hardware at first: an RK3588 with a Mali-G610. "Drops to 20 fps, CPU and GPU usage don't go up, and only a restart fixes it" points to something sticky rather than plain load. Most likely the game's render or game thread ends up on one of the RK3588's slow Cortex-A55 cores (or a clock governor drops), often right after a low-load phase like a video cutscene, and stays there. Could you try:
taskset -c 4-7 ./data/bin/wwhd(or prefix your usual launch command withtaskset -c 4-7).performancefor the test.cat /sys/class/devfreq/*/cur_freqand the performance report while it's stuck.If
tasksetfixes it, we'll pin the game's main threads to the fast cores automatically on big.LITTLE chips. Separately, the next update cuts shader translation and pipeline creation by about 90%, which will help on this chip too.lschaupp commentedon Oct 7, 2026
v0.2.6 is out with the shader change mentioned above (about 90% fewer shader translations and pipelines, fewer stutters). Its performance report also starts with the version, OS, GPU and driver. Still very interested in whether
taskset -c 4-7stops the 20 fps lock.StonedEdge commentedon Oct 7, 2026
Did not help. Still dips in certain areas, for example, as soon as I enter this room:
lschaupp commentedon Oct 7, 2026
Thanks, and the new report header is already paying off. In that room your render thread needs about 40 ms per frame (5,800 draws, 6.7 µs each), so it misses even the 33 ms of a 30 fps frame, and vsync turns that into exactly 20 fps. GPU waits are 0, so it's purely the render thread. The biggest part is copying vertex data: 14.8 ms for only 2.9 MB per frame, which is very slow and points at the Mali driver's upload memory. Of those 2.9 MB only about 0.46 MB is actually new each frame.
That is exactly what our buffer cache avoids: it keeps unchanged vertex, index and uniform data on the GPU instead of copying it every frame. It's on by default on macOS but still opt-in on Linux, because we haven't been able to test it there yet, so you'd be the first. Could you try two runs in that same room:
[vulkan buffer cache]lines from the log (especially anyVERIFY MISMATCH, which should never appear, plus thepage write faults/protect failurescounts).(Use your usual launch command with the variables in front. Alternatively, put
WWHD_VK_BUFFER_CACHE=1on a line in anenv.txtnext to your settings if your setup uses one.) If it helps as much as we expect, we'll turn the cache on by default on Linux too.StonedEdge commentedon Oct 7, 2026
Ah, yes, adding that env variable has fixed everything.
lschaupp commentedon Oct 7, 2026
Great news, thanks! That confirms it was the vertex copies through the Mali driver's upload memory. Before we turn the cache on by default on Linux, could you do one correctness run in that same room?
and paste the
[vulkan buffer cache]lines from the log (we're looking for anyVERIFY MISMATCH, which should never appear, and thepage write faults/protect failurescounts). A "Copy performance report" from a normal run withWWHD_VK_BUFFER_CACHE=1in that room would also be nice, so we can see the new frame time. Until then, keep the variable set.Vulkan: guest buffer cache on by default on desktop Linux (Steam Deck…
lschaupp commentedon Oct 8, 2026
Closed for inactivity :)