FPS Capping
I recently started implementing FPS capping in GeDoSaTo. For those not familiar with the term, basically you want to achieve a consistent framerate in a given game, and in order to do that you cap the framerate at a given maximum.
In practice, this is usually done by simply inserting waiting periods after you are done with a given frame. E.g. if you want to cap to 30 FPS, you would wait until you reach a frametime of 33.3 ms.
There are multiple external tools which already do this (e.g. NVidia drivers have an option, RTSS can do it, some games have a built-in cap, …) so up to now I wasn’t interested in doing the same in GeDoSaTo — though I was sometimes frustrated by the lack of fine-grained control in external tools. However, I recently had an idea on how to improve upon the commonly employed method for doing this, in order to perhaps slightly improve input lag in a capped scenario.
The image above shows 3 use cases: uncapped framerate, a traditional 30 FPS limit implementation (“Capped”) and my new method (“Predictive”). As you can see, the traditional method simply inserts a waiting period after each frame. However, this means that you are potentially losing a few milliseconds of input latency for no good reason.
Instead, with predictive FPS capping, GeDoSaTo keeps track of the frame times for previous frames, and takes a set fraction (configurable) of that as a predictive waiting period before each frame. The result (for games which do synchronous input sampling on the rendering thread or at least on another thread synchronized with it) is that the input after waiting is used for the new frame, reducing input lag by some fraction of the frame time.
The only dangerous aspect of this method is if there is a sudden spike in frame rendering times. For example, in F2 in the picture you can see that the frame almost doesn’t get done in time. If it were to cross the threshold, predictive FPS capping would result in a framedrop which would not happen in a traditional FPS limiting scheme. For this reason, the ratio of how much waiting time should be moved to the start of the frame is configurable — you can use a low value like 0.25 for a game with very erratic frametimes and something like 0.9 for one with extremely consistent performance.
Here are the new configuration options (which can be configured as per-game user profiles, like always)
1 2 3 4 5 6 7 8 9 10 11 12 |
# Framerate Limiter # 0 = no limit, N = limit to N FPS; e.g. 125.5 = 125.5 FPS limit fpsLimit 0 # How much of the FPS limiting to perform predictively at the start of a frame # higher values decrease input latency when the framerate limiter is running, # but might lead to framedrops. The maximum useful value is probably around 0.9 # for games with very stable framerates. I'd suggest something like 0.7 for general use # 0.0 = default, no prediction fpsPredictiveLimitRatio 0.0 # Whether to use busy waiting or sleeping to enforce FPS limit # (busy is more exact and reliable but less CPU/energy efficient) fpsLimitBusy true |
The busy waiting or sleeping option is there for completeness, but outside of running on a laptop battery I don’t really see why you would not use busy waiting. In my tests it’s a lot more exact.
Note that you can use floating point numbers as the frame limit, I find it often useful to go with e.g. 30.5 FPS if I want a solid 30 in order to overcome unmeasured overheads.
Modding Controversies
Since my last blog post there have been two pretty large controversies about modding. The first was regarding paid mods for Skyrim. I was asked to provide a comment for PCGamesN, which was used in this article. My full comment, which is provided on the second page of the article, sums up my feelings on the issue. I have to admit that I was most disappointed by the level of vitriol some (purported) members of the community stooped to.
The other issue was once again the old friction between modding and multiplayer. Both in DS2 and GTAV, people who claimed to be using only mods which do not affect gameplay in an unfair way were relegated to the cheater pool in online multiplayer. This is a very delicate issue. It is extremely hard or even impossible for a game to assess whether a in-memory modification is benevolent or not, so I can certainly understand “no online modding” policies in principle. in the end, that is just another instance which shows why developer-supported modding is the way to go: in such a setup, it’s easy to control which modding functionality is available in what game mode.
Thanks for this update, might have to try that on Witcher 3 in case they butcher the AMD GPU compatibility because the whole pro-Nvidia thing.
On that note, if you ever get the game, will you consider doing some benchmarking analysis regarding that ?
Great article durante, thanks for taking the time to write up. I always love in-depth articles like these. Keep it up! Just one thing though:
“Instead, with predictive FPS capping, GeDoSaTo leeps track of the frame times”
You wrote “leeps” instead of “keeps”.
Thanks, fixed.