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.
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.
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).
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.
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.
CC @flightlessmango
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.
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.
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
So I doubt many users are using the DXVK_FRAME_RATE variable alone. Especially if it's "broken" like I observed.
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.
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.
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.
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.
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.
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.
@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
@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?
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.
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.
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).
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.
I've made a proper issue to discuss this - please use it. Thanks.
ge-proton10-25x1 2025-11DXVK_FRAME_RATEx5 2025-11MANGOHUDx1 2025-11DXVK_FRAME_PACE="low-latency-vrr-230"x1 2025-11DXVK_FRAME_RATE=225x1 2025-11VKD3D_FRAME_RATEx1 2025-11DXVK_FRAME_RATE=232`:x1 2025-11
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=232andfps_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=232andfps_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_RATEand is much worse in reality)In-game FPS limiter is disabled. In-game VSYNC is disabled. VSYNC set externally to Mailbox with
dxvk.tearFree = Trueindxvk.confandvsync=2inmangohud.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
dxvk.conf
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