protonscr

DXVK_FRAME_RATE produces unstable VRR Hz counter on monitor compared to MangoHud

dxvkclosed wontfix
doitsujin/dxvk#5330 · opened 2025-11-17 by nokia8801 · updated 2025-11-27 · 23 comments · github
10 matching comments, n / p to jump
Nnokia8801 2025-11-17 github

When playing on a VRR monitor with VSYNC set to Mailbox and FPS limited below refresh rate externally with MangoHud and/or DXVK, the DXVK_FRAME_RATE option produces worse results compared to MangoHud.

MangoHud with fps_limit=232 and fps_limit_method=early (produces the most stable VRR Hz counter and the smoothest frame times):
https://github.com/user-attachments/assets/6cfb592c-28c4-4880-95e1-a7486980202a

MangoHud with fps_limit=232 and fps_limit_method=late (1-2ms min-max frame time variance but still a very stable VRR Hz counter):
https://github.com/user-attachments/assets/265288cc-10fd-469d-9a91-d8a5843e3b3b

DXVK_FRAME_RATE=232:
https://github.com/user-attachments/assets/cbfd00a0-24bd-480d-bf00-f57a12b9ff9b

(The videos are recorded in 60 FPS so it might not really show the results accurately, but it fluctuates a lot with DXVK_FRAME_RATE and is much worse in reality)

In-game FPS limiter is disabled. In-game VSYNC is disabled. VSYNC set externally to Mailbox with dxvk.tearFree = True in dxvk.conf and vsync=2 in mangohud.conf. FPS is limited with DXVK and MangoHud to test. This is the recommended competitive setup on both Windows and Linux. You can read these to see why this is the case: 1 2.

Software information

Any game. But I'm focusing on Call of Duty games that Plutonium supports.

System Information

  • OS: Arch Linux x86_64
  • Kernel: Linux 6.17.8-arch1-1
  • Mesa: 25.2.7-arch1.1
  • Proton: GE-Proton10-25
  • DXVK: v2.7.1-207-ge9ad90562cf4f78 (commit e9ad905)
  • GPU: AMD RX 9060 XT
  • DE/WM: GNOME 49.1 on Wayland

dxvk.conf

dxgi.enableHDR = False
d3d11.maxFeatureLevel = 12_1
d3d9.shaderModel = 3
dxvk.enableMemoryDefrag = Auto
d3d9.floatEmulation = Strict
dxvk.enableDescriptorBuffer = Auto
dxvk.tearFree = True

Additional Information

Running the games natively on Wayland with Wine's Wayland driver on a Wayland session. VRR is enabled in dconf-settings and GNOME Settings. VRR range is 1-240Hz since the monitor is a native GSync monitor with the newer GSync module inside it, which means it also supports Adaptive Sync/Freesync. This also means it's not limited by the usual 48Hz lower limit, since it has the actual GSync module inside it.

VRR works with no issues on this monitor with NVIDIA, AMD and Intel cards.

The issue is that the frame rate limiter in DXVK is very unstable at high FPS, especially near refresh rate, compared to MangoHud with both late and early frame rate limiting. This means the monitor constantly goes in and out of VRR mode, which breaks player experience when playing competitively.

The reason this is important to me is that the DXVK frame limiter is said to be better for latency than MangoHud.
Link: https://docs.bazzite.gg/Gaming/Common_gaming_issues/#frame-rate-limiting-issues-and-inconsistency

Ddoitsujin maintainer 2025-11-17 github

Yes, we know it's shit, more news at 11. I will remove the env var so that people are encouraged to use external solutions that work better on their systems. There's too many different kinds of setups we need to cater to and I simply do not know how to make it work on all of them.

Keep in mind that the only thing we can influence at an app level is vkQueuePresent timing. This does not correlate with when presentation happens on screen in any meaningful way.

Using Mailbox complicates things since now you're dropping frames that arrive early at a compositor level, which, again, we have no influence over.

Ddoitsujin maintainer 2025-11-17 github

FWIW, the way the current frame rate limiter works is that after a present has finished, it will delay waking up the app thread that called Present (or, in some newer D3D11 games, delay when the frame latency event hets signaled), so if the CPU work that games do each frame varies heavily, or if present_wait doesn't work properly, or if frame latency isn't capped (which we should arguably do by default if the limiter is enabled), then this cannot produce smooth present timings.

TTiagoquix 2025-11-17 github

I am against removing such env. var. Most of the time, I personally use it to cap some heavy games to 60 fps (mostly singleplayer ones). For games that surpass 200+ FPS you generally can find in-game FPS limiters for that.

The somewhat context of this issue was a request in mangohud's repo to work together with dxvk frame rate. https://github.com/flightlessmango/MangoHud/issues/1857

Even though DXVK_FRAME_RATE/VKD3D_FRAME_RATE is not perfect, it is a quick and easy solution to limit fps (and mangohud covers the rest of the renders on Linux).

Ddoitsujin maintainer 2025-11-17 github

I don't want third-party software to interact with our env vars. Moreover limiting in two different places at the same time just creates even more problems since now we have a feedback loop between the external limiter, the app and dxvk itself, which leads to oscillating frame times in practice.

TTiagoquix 2025-11-17 github

I don't want third-party software to interact with our env vars.

That's fine, mangohud's author proposed a different solution which would avoid that.

Moreover limiting in two different places at the same time just creates even more problems since now we have a feedback loop between the external limiter, the app and dxvk itself, which leads to oscillating frame times in practice.

Yep the intention is to avoid the latency increase when using dxvk plus mangohud fps limiters (more details on that issue if you want to read it in full).

But in regards to removing the dxvk frame limiter I see no advantage in doing that. For me it has served me well. There are some games that mangohud can't work due to the game being buggy, and DXVK works so fps limit is possible.

However, I also understand your point of preferring other frame limiters (in this case, removing dxvk fps limiter and let mangohud and other 3rd-party apps do the work). I am not exactly sure which is the best, but from what I can say from personal experience is that the dxvk frame rate limiter works OK for my use case.

TTiagoquix 2025-11-17 github

CC @flightlessmango

Ddoitsujin maintainer 2025-11-17 github

You can still use our frame rate limiter via dxvk.conf, we unfortunately need to keep it around to support games that would otherwise only work on 60 Hz displays.

Yep the intention is to avoid the latency increase when using dxvk plus mangohud fps limiters

This isn't really how this works though, see above. You shouldn't be getting more than ~half an extra frame of latency anyway when using Mangohud + setting dxgi.maxFrameLatency = 1 (or the d3d9 option, depending on the game).

The only real solution that would actually work in combination with the current dxvk limiter would be to have an equivalent to VK_GOOGLE_display_timing, but that is effectively an Android-only extension.

I am really regretting adding any of these user-facing features in the first place, they have caused nothing but problems.

TTiagoquix 2025-11-17 github

Well, if we are keeping the frame limiter anyway due to other technical complications, we might as well keep the env. var. For users that want to use the frame rate limiter, removing the env. var. would only create an additional annoyance.

But I get what you want. You want users not to use such frame rate limiter, and discourage them to do so by removing the env. var.

Not that this is your problem, but if you proceed with that path, it would be nice if you recommended some alternative fps limiter since many users probably are using such env. var. for some of their games. Maybe mangohud, but mangohud is not as simple as just limiting the FPS — it is feature-complete with a bunch of other things. And that is why I prefer to keep the dxvk frame rate limiter: it does one job and does it fairly well. Other alternatives come packed with a bunch of other things that wouldn't be relevant for a user that just wants to cap the FPS.

Nnokia8801 2025-11-17 github

Not that this is your problem, but if you proceed with that path, it would be nice if you recommended some alternative fps limiter since many users probably are using such env. var. for some of their games. Maybe mangohud, but mangohud is not as simple as just limiting the FPS — it is feature-complete with a bunch of other things. And that is why I prefer to keep the dxvk frame rate limiter: it does one job and does it fairly well. Other alternatives come packed with a bunch of other things that wouldn't be relevant for a user that just wants to cap the FPS.

Most end-users are using

  • SteamOS/Bazzite/Nobara etc with the performance overlay which uses MangoHud/MangoApp/Gamescope under the hood,
  • MangoHud directly
  • in-game FPS limiter

So I doubt many users are using the DXVK_FRAME_RATE variable alone. Especially if it's "broken" like I observed.

Ddoitsujin maintainer 2025-11-17 github

FWIW I can't say I'm observing better behaviour with mangohud locally, it also leads to oscillating present timings on screen with VRR rates bouncing between 52 and 144 Hz with a 100 FPS limit (even though vkQueuePresent intervals on the CPU timeline are about as smooth as they get).

Again, not a mangohud issue either, the problems originate elsewhere and are influenced by the compositor and GPU power management, among other things.

it would be nice if you recommended some alternative fps limiter

Well, we're talking about mangohud,, but Gamescope also exists. Gamescope is currently the only thing that can actually solve both the latency and frame pacing issues at the same time, since, well, it is a compositor and controls presentation. It can still get fucked over by power management memes, but that's solvable with some amdgpu tweaking.

Ddoitsujin maintainer 2025-11-17 github

Actually, another thing that just comes to mind: Due to the way present_wait works, our limiter can only ever have latency benefits with vsync on. Forcing mailbox completely disables any sort of synchronization with the compositor that we do to try and align presentation with the monitor, on top of creating issues with dropped frames.

Nnokia8801 2025-11-17 github

Mailbox is vsync though, just with an uncapped FPS limit, which is where Freesync comes into play. It's also non-tearing like FIFO.

Unlike FIFO vsync which has an FPS limit.

That's why Mailbox is preferred in competitive spaces.

Ddoitsujin maintainer 2025-11-17 github

Mailbox isn't vsync, it's just tear-free, and we cannot get any meaningful present timing metrics from it since frames might get dropped. This only works with FIFO.

Ddoitsujin maintainer 2025-11-17 github

Just to illustrate, suppose a game renders in a way that takes 1ms of processing on the CPU, 5ms on the GPU, and user limits to 100 fps. A timeline (ignoring any potential FIFO queueing for a second) ideally looks something like this (number in parentheses are frame IDs):

Time App DXVK worker GPU DXVK limiter (100 FPS)
+0ms Render(1) vkQueueSubmit(1) Render(1)
+1ms Present(1) vkQueuePresent(1)
+2ms Render(2) vkQueueSubmit(2)
+3ms Present(2) vkQueuePresent(2)
+4ms Wait(1) Scanout(1) Notify(1)
+5ms Render(3) vkQueueSubmit(3) Render(2)
+6ms Present(3) vkQueuePresent(3)
+7ms Wait(2)
+8ms
+9ms Scanout(2) Sleep(5ms)
+10ms Render(3)
+11ms
+12ms
+13ms
+14ms Scanout(3) Notify(2); Sleep(10ms)
+15ms Render(4) vkQueueSubmit(4) Render(4)
+16ms Present(4) vkQueuePresent(4)
+17ms Wait(3)
+18ms
+19ms Scanout(4)
+19ms
+20ms
+21ms
+22ms
+23ms
+24ms Notify(3); Sleep(10ms)
+25ms Render(5) vkQueueSubmit(5) Render(5)
+26ms Present(5) vkQueuePresent(5)
+27ms Wait(4)
+28ms
+29ms Scanout(5)
+30ms
+31ms
+32ms
+33ms
+34ms Noitify(4); Sleep(10ms)

If we assume a 125 Hz VRR display with FIFO queueing, the only thing that really changes is that Scanout 2-4 move down to 12, 20 and 28ms respectively and sleep durations change, but nothing else actually moves. By scanout 5, the display will have caught up with the app.

Mailbox is useful when running above display refresh, but I fail to see what advantage it would have in this scenario even if present_wait worked. Scanout isn't going to happen any sooner if there's no queue to begin with. In this example it would just delay Scanout 2 and drop Scanout 3, and because present_wait doesn't work anymore we'd base our synchronization on GPU rendering, whiiiich has its own share of problems.

Now obviously the world isn't ideal and there's going to be some random delays (be it from app, gpu, ...) and things will move up and down, but with FIFO you at least get the guarantee that every rendered frame actually ends up on screen. With Mailbox you don't, which leads to visible judder.

Ddoitsujin maintainer 2025-11-17 github

Anyway, env var is removed, and the frame rate limiter should not be used directly anymore. The only reason the code needs to stay is because we need it to "emulate" fixed display refresh and fix games with frame rate-dependent physics. Closing.

Nnetborg-afps 2025-11-18 github

@doitsujin

Keep in mind that the only thing we can influence at an app level is vkQueuePresent timing. This does not correlate with when presentation happens on screen in any meaningful way.

Well yes and no. Yes, because vkQueuePresent() is actually the last step of the frame when dxvk is handing it over to the driver + compositor. No, because there is actually no logic in place in dxvk to delay vkQueuePresent(). The dxvk limiter delays d3d.present().

Using Mailbox complicates things since now you're dropping frames that arrive early at a compositor level, which, again, we have no influence over.

True, Mailbox shouldn't really be used. FIFO should be more consistent and actually provides feedback to dxvk.

This isn't really how this works though, see above. You shouldn't be getting more than ~half an extra frame of latency anyway when using Mangohud + setting dxgi.maxFrameLatency = 1 (or the d3d9 option, depending on the game).

Wrong. Mangohud will always create one extra frame of latency, because it can only stall vkQueuePresentKHR() and how this interacts with the dxvk logic. A limiter should best live in d3d.present() as the dxvk limiter actually does when simplified.

Well, we're talking about mangohud,, but Gamescope also exists. Gamescope is currently the only thing that can actually solve both the latency and frame pacing issues at the same time, since, well, it is a compositor and controls presentation. It can still get fucked over by power management memes, but that's solvable with some amdgpu tweaking.

Does Gamescope have access to the d3d domain? Probably not, so I don't see how it can be effective at controlling latency. Ofc. it can control the timing to the display though.

@nokia8801

The issue is that the frame rate limiter in DXVK is very unstable at high FPS, especially near refresh rate, compared to MangoHud with both late and early frame rate limiting. This means the monitor constantly goes in and out of VRR mode, which breaks player experience when playing competitively.

I have noticed issues with the dxvk fps limiter as well with VRR. The issue is that this limiter doesn't check how the previous frame is progressing and thus occasionally you get a sequence of a slow frame followed by a fast frame, which results in the frame being delivered to the compositor/display when it is still busy drawing the previous frame. The mangohud fps-limiter limits a bit closer in time to the actual present, so it's not surprising it causes less issues with VRR.

The best all around solution you get when you use the low-latency-vrr mode of my dxvk frame pacing fork. The key point here is that it is aware about all the relevant timings and takes care to schedule the frames to be started at the right time (within d3d.present()) and delivered at the right time to the display. It uses an internal model about how the game and dxvk is constructing the frame and makes a prediction of how to align the frame best to the display while also optimizing for best latency.

You even can monitor how much (single) frames go into V-Sync buffering if your driver is reporting v-blanks correctly via vkWaitForPresentKHR(), so you can optimize the best settings. For 240 Hz, I would start at
DXVK_FRAME_PACE="low-latency-vrr-230"
DXVK_FRAME_RATE=225

DDigger1955 2025-11-18 github

@doitsujin and @netborg-afps

Since @doitsujin said that DXVK FPS Limiter:

Yes, we know it's shit, more news at 11. I will remove the env var so that people are encouraged to use external solutions that work better on their systems. There's too many different kinds of setups we need to cater to and I simply do not know how to make it work on all of them.

Can @doitsujin use @netborg-afps implementation of DXVK FPS Limiter with required modifications in order to make DXVK better, espescially for use-case where DXVK FPS Limiter is needed?

Nnetborg-afps 2025-11-19 github

He is underselling his limiter. It might not be perfect, but it's still good.

The reason why I'm engaging so intensively in this discussion is to make the point clear that offloading this task to external solutions isn't that simple. An external limiter needs access to the d3d domain to have good latency properties. I don't know any external limiter that does this on Linux.

VRR is a special case where the timing to the display is important. You could handle this at the compositor level or by delaying/timing vkQueuePresent() to fire up after all rendering has been done. Only limiting at this stage of the frame will result in bad latency properties though.

The way my system works for VRR is by collecting lots of frame data to make a prediction of when frames are finished and likely be presented on the display, which goes far beyond what fps limiting usually looks like. Also, this couldn't even work externally, other than dxvk maybe exporting all the internal data required.

As given in the example above, I even recommend for the VRR use-case to have two limiters active at the same time: the VRR limiter being coupled with a normal simple limiter to help reduce the jitter introduced by prediction.

PPh42oN 2025-11-19 github

This sounds like kind of issue where using dxvk's fps limiter together with dxvk.latencySleep=true might make it smoother, and this can improve latency as well.

Also i had some situations where mangohud fps limiter didnt run smoothly and had unstable refresh rate with VRR, but dxvk fps limiter worked without issues, even before i tried latencySleep.

DDigger1955 2025-11-19 github

@netborg-afps and @Ph42oN

I agree with both of you and I find it a little bit hasty decision (literally 1 day between issue and PR) to cut both DXVK_FRAME_RATE and latency tracker solution on account of one specfic use-case - very high FPS combined with VRR display and Mailbox VSync on Wayland.

Nnetborg-afps 2025-11-19 github

The issue is also that @nokia8801 was using Mailbox, so dxvk doesn't get any feedback on the state of monitor refresh. In my VRR mode I force-enable FIFO.

On top of a broken Mailbox on Wayland?! (have checked this several months ago on Nvidia - there is a chance this got fixed or runs better on AMD) which delays the frame by one refresh cycle as soon as the monitor's refresh rate is exceeded.

Also, this can be highly game dependent, how stable the frame times are for the limiter to work with. I've only tested the dxvk limiter + VRR combination in a few games, and it was largely running smooth, but for example after a respawn it would occasionally go for more than a millisecond into v-sync buffering (on 360 Hz).

Vvictorsouzaleal 2025-11-19 github

Sadly MANGOHUD fps limit doesn't work with LSFG-VK, i use DXVK_FRAME_RATE to cap FPS and now the env is removed :(

The env was super useful for me and I configured the games accordingly, for example for I use LSFG I lock at 36 fps and set LSFG to x2 to stay close to my monitor's refresh rate. Don't underestimate your code, it's good and worked great for me.

TTiagoquix 2025-11-22 github

I've made a proper issue to discuss this - please use it. Thanks.

https://github.com/doitsujin/dxvk/issues/5340

Proton versions

Launch options

Upstream links