I've been working on making the TimeGetTime (TGT) version of my limiter reach the correct fps. The misconception people have is that a programmer can just use "FPS:= 60" and that it will then all work out dandy. In practice, this depends on how the engine has been made - and more importantly - which counter is being used: Windows' internal timer, or the processor counter, Query Performance Counter (QPC).
Mathematically, there is a problem when using TGT. Let me show you why:
TGT uses the millisecond internal windows counter, which is always there in the background incrementing away, without you realizing it. It starts at 0 on every boot and begins counting once Windows has loaded. Every second, that's 1000 counts. It won't be perfect, because it's not a perfect counter, but it is pretty reliable and close to ~1ms accuracy. That isn't the big problem. This is:
1000 / FPS (60) = 16.6666666
This is not a whole number. So you are forced to use either 16 or 17. In this case, you'd go for 17 because 0.6666 is closer to 1. But now look at what FPS you will get:
1000 / 17 = 58.8235.
This will be VERY choppy. It will look like 59fps in most programs that show you the fps, because some frames will be 58, and others 59. But mostly 59. Remember, there is no such thing as 0.8235 of a frame. There is a frame or there is not.
So how can we make TGT work properly with frame rates that produce a non whole number (floating point value)? We have to cheat. Since (16 + 17 + 17) / 3 = 16.6666666 we can simply alternate the target each frame. Frame 1, we force 16. Frame 2 and 3, we force 17, and then the pattern continues indefinitely. This is, as far as I have calculated and tested, the ONLY good way to do this. It is not a perfect linear frame rate, but it's so close that you won't notice.
So why doesn't QPC have this issue? Because it has thousands more ticks to play with. Far more than 1000 a second. Let's pretend that your processor increments a counter 100,000 times a second.
Now, the original calculation works well enough:
100000 / FPS (60) = 1666.6666. Which we round to 1667.
Look at the difference: 100000 / 1667 = 59.988. It's not a perfect 60, but it's damn close. And it's so close in practice that there is no need for any trickery or other correction. My PC is doing 3318408 counts a second, which leads to a frame rate of 59.9998.
TGT is limited precisely because it can only give you 1000 counts a second.
There is one further issue that I should note. The above TGT correction will break down after 120fps [when doubling up the fps]. That's the limit (with ff7) before this math stops working.
This is why:
1000 / 120 = 8.3333333333
So we need to use a pattern of 8,8,9 ( (8 + 8 + 9) / 3 = 8.3333333333).
That works. But what about 240?
1000 / 240 = 4.166666666666
There is no 3 frame combination that can create that result. You'd need to do more correction with longer pattern chains (in this case, a chain of 6 values would be needed [4,4,4,4,4,5] ).
You then start running into the limits of TGT in terms of its accuracy. I haven't bothered adding corrections past 120 fps. So you'll get 250 fps instead of 240 when using TGT. But the QPC option will work for nearly everyone anyway.
A fun note:TGT will cause crashes and issues to many programs and games (probably all of them
) if Windows is left running for (2 ^32) / 1000 seconds (49.71 days), because it will reset to 0 (overflow of 32 bit storage value). QPC uses 64 bit storage and won't suffer an issue of this nature, despite incrementing by much larger amounts.