Techniques for uncapped framerates

I was thinking of adding uncapped framerate support to Mocha Doom, and I was wondering which approaches/algorithms are currently used.

My current understanding of the matter is as follows:

  • The actual gameplay still runs at 35 tics
  • "Uncapped" framerate essentially means attempting to render extra frames, if possible, between tics, by interpolating player view position and angle and/or visual monster and platform positions, but not actually modifying them in the gameplay code.
  • Rendering extra frames is a "best effort" and opportunistic approach: sometimes it might be possible, sometimes not, and since a-priori knowledge of how long a frame will take to render is not available, some heuristics are needed.
  • Rendering extra frames should NOT occur at the expense of gameplay speed, so if not possible to spare time for extra renderin, don't do it.
  • I imagine the algorithm to be more or less like this: e.g. render a frame normally, time how long it took to render, and if enough time is left in the current tic to render more, try to render them.
  • I can only imagine that uncapped framerate can occur at multiples of the base framerate (35, 70, 105, etc.) and not at any arbitrary rate (e.g. you can't have a 60 Hz refresh rate), since you can only decide whether to render one or more full frames between tics, not a fractional number. Trying to delay rendering in order to achieve non-multiple-of-35 refresh rates must look fugly and jerky :-S
  • Non-multiple-of-35 framerates may be achievable on average over a longer period, but not as instant tic rate: during a tic you can either NOT be able to render a frame (skip it), be able to render one, or be able to render more than one, so necessarily at 0x (skip), 1x (normal), 2x, 3x... etc. speed of the base ticrate.
  • I presume that multithreading at the tic level is possible: if based on the previous tic you conclude that rendering more frames is possible, you could start e.g. one or more extra threads per tic to prepare several position-shifted renderings of the current gamestate.
Any suggestions/comments are welcome.

Share this post


Link to post

ZDoom works as follows:

It uses a base ticker with sub-frame accuracy. Sub-frame value is 0 at precisely the point where the frame SHOULD start, there is no guarantee, that it will eventually render this precise moment.

When the renderer starts it takes the sub-frame counter and interpolates everything in the playsim according to it. This means that with 60 fps it'd render


frame 0.0
frame 0.58
frame 1.16
frame 1.75
frame 2.33
frame 2.91
frame 3.5

and so on. That way a quasi stable distance between frames is achieved.

Do not try to synchronize the render timer with the playsim timer, it will inevitably result in a very choppy effect.

Share this post


Link to post

BUt what you're describing is a higher -but still finite- target framerate, thus not "uncapped" in the sense of "as fast as possible at any given moment", which is -I think- the usual meaning. E.g. in some places it may go 15 fps, in others it may be able to reach 300, if the rendering is lightweight enough.

OTOH it doesn't have any physical sense to go beyond 60 or 70 Hz with modern displays....

Then again ZDoom's approach does simplify some things -it sets a precise target framerate for which to strive, eliminates variable-speed/load uncertainty, and solves the problems deriving from a multiples-of-35 approach. I wonder if other ports use different approaches.

Share this post


Link to post

Odamex decouples the rendering frame-rate from the gameplay frame-rate so that they can be completely independent. The net result is that renderer frame-rates can be capped at arbitrary rates, such as 60.0fps or anything that the user wants. When Odamex is rendered at 35fps, there is no game-world interpolation, but with any other frame-rate, interpolation is used determine the position and angle of all actors, lifts, etc.

Odamex's code is very much built on the info in this article: http://gafferongames.com/game-physics/fix-your-timestep/

Share this post


Link to post
Maes said:

BUt what you're describing is a higher -but still finite- target framerate, thus not "uncapped" in the sense of "as fast as possible at any given moment", which is -I think- the usual meaning. E.g. in some places it may go 15 fps, in others it may be able to reach 300, if the rendering is lightweight enough.

OTOH it doesn't have any physical sense to go beyond 60 or 70 Hz with modern displays....

Then again ZDoom's approach does simplify some things -it sets a precise target framerate for which to strive, eliminates variable-speed/load uncertainty, and solves the problems deriving from a multiples-of-35 approach. I wonder if other ports use different approaches.



I used 60fps as an example. What ZDoom really does is run the renderer, check the time, if a real tic expired, run the playsim, run the renderer again, rinse and repeat. There are no real delays and it will achieve uncapped frame rate.

Share this post


Link to post
Maes said:

OTOH it doesn't have any physical sense to go beyond 60 or 70 Hz with modern displays....

That depends. Higher than refresh rate frame rates can reduce temporal lag. Some people are able to notice this more than others.

One thing I will note is that ZDoom samples pitch and yaw from the mouse for each frame. The accumulated result is then seamlessly proceed at the tic.

The uncapped frame rate is also the main reason ZDoom ports feel like the player is on ice skates. Since the game can't properly respond to all input on a per frame basis there is an inherent input lag to uncapped frame rates. (Not necessarily related to the vsync temporal lag.) One fun thing to do to experiment with ZDoom's uncapped frame rate code is to set the TICRATE to some low value.

Share this post


Link to post
Blzut3 said:

That depends. Higher than refresh rate frame rates can reduce temporal lag. Some people are able to notice this more than others.


This is further complicated by modern displays (especially cheap "TFTs") cheating and actually buffering several frames before rendering anything, in order to overdrive their crappy TN panels properly, so trying to solve any perceived lag problems at the software level is kinda moot, if you have the final display device working against you.

Share this post


Link to post

There's a common misconception that Doom comes out of the box so to speak rendering 35 frames per second. This is false. It runs 35 tics per second. The renderer, which executes in the while(1) loop in D_DoomMain, runs as fast as it can.

In vanilla Doom under DOS, this was controlled by a routine called I_WaitVBL which would stop the renderer from drawing again until the next vertical refresh interrupt.

That mechanism was removed during the porting to Linux, by Dave Taylor.

What is missing is any form of interpolation, so, the extra frames being drawn between gametics are all identical. It DOES still make a visual difference. Try to limit the actual drawn framerate to 35 Hz and you will find it visually painful compared to drawing, ie. 300 fps even with duplicated frames.

Share this post


Link to post
Quasar said:

Try to limit the actual drawn framerate to 35 Hz and you will find it visually painful compared to drawing, ie. 300 fps even with duplicated frames.


That's very dependent on how the refresh mechanism works, the type of display etc.

On a CRT monitor running at a multiple of 35 Hz (e.g. 70 Hz VGA) the raster might be able to "catch" a partial update of the screen even if you normally duplicate frames (e.g. Frame 1 and 2 will be identical, but the transition from 2 to 3 and 4 will be "caught").

On a TFT with an onboard framebuffer and inter-frame processing however, all bets are off, as are most forms of video recording, as well as CRT monitors running at "odious" frequencies (non-multiples of 35 Hz).

Inflating the framerate to be closer to a multiple of 35 (but not matching it exactly) may be more or less painful, depending on the exact frequency difference, but the ideal will always be a multiple of 35 Hz. In PC land, this boils down to 70 Hz for modern TFT (some of them), or 70 Hz and maaaaaybe 100 Hz or 140 Hz. The worst update frequencies are those "farthest" from multiples of 35 Hz -50 Hz and 60 Hz come to mind, among those commonly used.

Quasar said:

There's a common misconception that Doom comes out of the box so to speak rendering 35 frames per second. This is false. It runs 35 tics per second. The renderer, which executes in the while(1) loop in D_DoomMain, runs as fast as it can.


Well, I can't imagine it having carefully-placed delays all along the rendering process so that it barely finishes rendering the very last pixel at the end of a tic, plus allowing just the stricly necessary amount of time for transferring to the video RAM, if applicable ;-)

The question is what you do with the spare time you have left after it has ran "as fast as it can". Normally, that is nothing, but you can always complicate things with interpolations etc. :-p

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now