Say I have a game running at some number of frames per second on a 60 Hz monitor. I would like to display my frames correctly in the sense that the in-game time difference between two consecutive displayed frames remains constant (e.g. 1/60 seconds). Now the allowed frame rates are 30, 60, 120 etc., and an obvious solution would be to enable vsync. However, with vsync enabled, the delta times are not exact multiples of 1/60 seconds, which means that I can't technically use them if I want the correct frame sequence. Instead, I would need to make the code explicitly dependent on the refresh rate. Is this even something to worry about, or should I just trust that the delta times are close enough? What if I use uncapped fps and the fps is high enough, should I then worry about fluctuations in elapsed in-game times between monitor refreshes?
-
\$\begingroup\$ "should I then worry" - try a quick test and observe whether it causes problems for your game. Some games are more sensitive to the juddering or tearing that can result from this than others, so the person best positioned to determine whether it's an acceptable solution for your game is someone who has access to your game's source: you. Is it safe to assume you're using a separate fixed timestep for simulation updates, so fluctuations in display framerate do not affect the behaviour of the game systems, only their display appearance? \$\endgroup\$– DMGregory ♦Commented Aug 22, 2022 at 18:43
-
1\$\begingroup\$ Are you familiar with this classic Glenn FIelder article? It details how to handle fixed timesteps of arbitrary length using interpolation: gafferongames.com/post/fix_your_timestep \$\endgroup\$– the_DemongodCommented Aug 22, 2022 at 18:47
-
\$\begingroup\$ @DMGregory Yes I'm using a fixed timestep for the updates, although without any kind of interpolation/extrapolation, so I'm frame rate dependent in that sense. I'm just gonna see and feel how the game plays and adjust if necessary \$\endgroup\$– bananab0yCommented Aug 22, 2022 at 19:28
-
1\$\begingroup\$ @the_Demongod Yes I'm familiar with it, but as I understand it, it's about mismatch between update rate and display framerate, whereas here I'm worried about the mismatch between display framerate and monitor refresh rate. \$\endgroup\$– bananab0yCommented Aug 22, 2022 at 19:30
-
\$\begingroup\$ @bananab0y aha, this is a much more difficult problem, one that does not actually have a clean solution in general since there is no way to know exactly when the frame is presented to the monitor. Here is a more relevant (but much more advanced) article about the difficulties of the issue: raphlinus.github.io/ui/graphics/gpu/2021/10/22/… \$\endgroup\$– the_DemongodCommented Aug 25, 2022 at 19:53
2 Answers
However, with vsync enabled, the delta times are not exact multiples of 1/60 seconds, which means that I can't technically use them if I want the correct frame sequence.
It's not entirely clear what your concern is here. Generally, we don't care what the monitor refresh rate is - we care how many frames per second are actually getting rendered. This could be higher or lower than the monitor refresh rate depending on the game's graphics settings, the player's hardware, and the player's driver settings.
There are two ways to approach the speed/timing of motion and other gameplay mechanics:
Frame updates: Using this approach, we update the game state once each time a frame is rendered. To ensure that the motion remains smooth even when the gamplay is changing, we scale the motion for each frame based on how much real time has elapsed since the previous frame. Motion will generally look smoother on a wider range of devices. CPU usage will be lower on low-end devices (because fewer frames are rendered per second, we perform fewer updates) and higher on high-end devices (the inverse). Things can sometimes break if the framerate gets extremely low and you are performing so few updates per second that motion is extremely imprecise.
Fixed updates: With fixed updates, we update the game state at a constant interval (such as 60hz) regardless of how many frames per second are being rendered. Although we could used fixed hardcoded values for things like speed and timing, it's best to scale the motion based on the fixed update rate (number of updates per second) so that we can easily change the fixed update rate in the future without having to change all of the speed/timing values in our game. CPU usage will be more consistent/less dependent on framerate. Motion will likely be more precise on low-end hardware where the framerate is low. However, you might get complaints from users with high-end hardware - for example, a user with a 240hz monitor might complain if they notice the camera is rendering at 240hz but objects are only moving at 60 hz.
Update @bananab0y, in response to your comments on this answer: you are thinking about this the wrong way. It is not "incorrect" to render 90 fps while the user only sees 60fps. You are thinking about rendered frames as if they are units of time, but that is not the case. The timing of our important gameplay mechanics should be independent of framerate. In other words, we don't say that the cooldown for an attack should be 30 frames or that a character should move .1 unit per frame. We say that the cooldown of an attack is a half-second or that a character should move 6 units per second. Each rendered frame simply shows the game state at a particular moment in time, just like how each frame of a movie shows what was happening in front of the camera at a particular moment in time.
Let's look at this a different way. Imagine we record 10 seconds of gameplay to a video file with a framerate of 60 frames per second. When we watch the video file, we see exactly what happened. Now, we reduce the framerate of the video file to 30fps and skip every other frame. Is this new 30fps video "incorrect"? The new video is still 10 seconds long and shows the same events over the same time period. It doesn't change what actually happened, or the speed at which it happened - it just changes how smooth the motion looks.
-
\$\begingroup\$ "we care how many frames per second are actually getting rendered." But the refresh rate determines how many frames are actually shown to the user and at what rate. The problem is that the frames rendered are not immediately shown to the user unless you have infinite refresh rate. For example, if the monitor refreshes at 60 Hz and the game renders at 90 fps, then every other monitor refresh advances the game by 2 in-game frames and the rest by 1 in-game frame, which is obviously incorrect as the user only sees increments of 1/60 secs in real time. \$\endgroup\$ Commented Aug 23, 2022 at 9:25
-
\$\begingroup\$ "Generally, we don't care what the monitor refresh rate is --" I just have a hard time believing that this is true if one wants to provide a consistent feel of the game for the player. \$\endgroup\$ Commented Aug 23, 2022 at 9:27
-
\$\begingroup\$ @bananab0y You are thinking about this in the wrong way. I've updated my answer; please see the two new paragraphs at the bottom. \$\endgroup\$– KevinCommented Aug 23, 2022 at 17:18
-
1\$\begingroup\$ @bananab0y Maybe the questions I thought you were asking are different than what you are actually asking. I think the hardcore PC gaming community generally agrees that gameplay is smoother if you're rendering more FPS than the monitor can actually display. See blurbusters.com/faq/benefits-of-frame-rate-above-refresh-rate As far as the deltas/epsilon, whether that matters probably depends on the engine, graphics API (DirectX, OpenGL, etc) GPU, driver settings, and monitor (whether the monitor supports adaptive sync). Most of that is outside your control. \$\endgroup\$– KevinCommented Aug 23, 2022 at 20:49
-
1\$\begingroup\$ Personally, I'd say not to worry about this. Unless you're only developing for a single specific console, you have no control over the hardware and drivers that the end user are using. Noticeable stuttering is usually caused by some combination of inadequate hardware and a poorly optimized game or engine. \$\endgroup\$– KevinCommented Aug 23, 2022 at 20:58
There's only two important times for developers to stress about their frame rate vs monitor refresh rate. When the assets you have are meant to render at a certain rate (16fps sprites vs 60hz monitor, or 30fps sprite vs a 144hz monitor). And when your game runs slower and non integer ratio to the refresh rate of the monitor.
Your question and further responses are confused, hinting this is an X Y problem, it doesn't appear you have the first two problems. While update rate problems are adresssed by the gaffer on games article, display rate is fixed via frame capping, vertical sync, and monitor hardware variable refresh rate. But if you expect players to not be able to run the game well within minimum requirements and settings, that's a performance bug in your game. Hitching, inconsistent frame rates, these are things for you to fix not just "work around".
If your concern are frame rates that exceed refresh rates, the typical solution is for the user to use frame rate limiting slightly below the monitors refresh rate (141 for 144hz) on combination with hardware variable refresh rate (gsync/freesync), and force vsync on top of that. The minute frame differences are eliminated, and high refresh rates appear smooth under this regime. Further latency can be mitigated with vendor specific technology (Nvidia reflex for example).
This process of figuring out the right settings is largely a process the user toys with, not you (and might be done via forced settings in their gpu vendors display settings). You just need to make sure the standard list of features are available to toggle both on and off in your game (frame cap, vsync, and possibly vendor specific latency tech). If you can't toggle these on and off, you have a bug in your game. If your game doesn't work with these features toggled on and off you have a bug in your game. If your game doesn't work with forced settings, it's a bug in your game.
Most popular engines do not have problems with these settings, and these ideas even appear inmlow level modern graphics APIs, so it's unlikely to be something the average developer needs to deal with specificically.
-
\$\begingroup\$ Wow, didn't expect anyone to stumble upon this almost a year old question. But yeah, in retrospect I successfully failed to express my actual concern here. After a while asking this I found this article that explains pretty well the problem that I was trying to ask here: medium.com/@alen.ladavac/the-elusive-frame-timing-168f899aec92. Solving this requires some extra support from the graphics API and that article mentions some Vulkan extension, but I haven't really followed the discussion regarding this and don't know what the state is now to be able to deal with this problem cleanly. \$\endgroup\$ Commented Jul 29, 2023 at 11:58