Setting TargetElapsed time

Rather than just Vsync or unlimited frame rates i’m trying to also add the options of setting refresh rates.

I’m not hitting a limit (Am currenty sitting at about 2k FPS in the menu) I’ve also checked fps times with an outside program.

So setting Vsync with the following monitor refresh rates works fine.
IsFixedTimeStep = true
SynchronizeWithVerticalRetrace = true
On a 60HZ monitor im getting 60fps.
On a 144HZ monitor im getting 144HZ.
On a 165HZ monitor im getting 165HZ

So turning Vsync off and setting a frame rate by doing the following isn’t giving accurate timings. They are consistent, however not correct
IsFixedTimeStep = true
SynchronizeWithVerticalRetrace = false
TargetElapsedTime = TimeSpan.FromMilliseconds(1000d / targetFrameRate)

I am getting the following frame timings when setting targetFrameRate
Setting 60 gives 59
Setting 75 gives 77
Setting 100 gives 100
Setting 120 gives 125
Setting 144 gives 143
Setting 165 gives 167
Setting 240 gives 250

Any reason for the difference? The 250 one is a pretty big 10 frames difference.

Edit

It seems to be in the Timespan Conversion. 240 and 230 give the same results. Is there a better way to calculate this off a target FPS?

TimeSpan a = TimeSpan.FromMilliseconds(1000d / 240); = 00:00:00.0040000
TimeSpan b = TimeSpan.FromMilliseconds(1000d / 230); = 00:00:00.0040000
TimeSpan c = TimeSpan.FromMilliseconds(1000d / 220); = 00:00:00.0050000

Edit again

Solved
FYI to generate the time span i used the following

            double temp = (1000d / (double)targetFrameRate) * 10000d;
            game.TargetElapsedTime = new TimeSpan((long)temp);       

At 160fps this will now give the accurate frame timing off 00:00:00.0041666

Interesting, I’ll test this with some capture software.

The function internally converts to ticks and does only respect full milliseconds (rounding I guess)

I can’t tell why they made it that way and not like in your solution (maybe overflow prevention), but that is most likely the problem and why your approach actually works.

Yes it must have some kind of rounding issue.

I’m a little confused in the result though.
Lets say im using a monitor refresh rate of 65hz.

So if im running with synchronisewithverticalretrace = true (From my understand this is VSync) if i drop below 60 hz, Monogame just drops the draw and update rate to anything below 60. Draw and update both run at 50hz with no dropped frames. If it cannot keep up i thought Vsync would drop the draw rate to half the monitors refresh rate? In this case 30? Because otherwise i am getting screen tearing on a low framerate.

If i disable synhronisewithvertical retrace and use custom frame timing and cannot keep the frame rate that high i drop draw frames. I suppose i was hoping i could use this as a frame limiter. So have this as the maximum frame timings, and if it drops lower, don’t make it running slowly and drop frames, instead just do as vertical retrace is doing which is lower the update and the draw rate to what it can achieve.

The correct way to set the TargetElapsedTime is by using TimeSpan.FromTicks like:

TargetElapsedTime = TimeSpan.FromTicks((long)(TimeSpan.TicksPerSecond / targetFPS));
1 Like

Back in the old days, when we accessed GFX registers directly, VSync actually meant, that the Graphicsbuffer is only “presented” to the “screen” during a vsync (which basically back then was when the ray of the CRT was traveling back to the top).

So if you miss a vsync for a frame, you just miss the vsync for that frame and have to wait for the next one. It does not maintain a framerate.

The gameloop itself is just a loop doing update and draw calls - to maintain a framerate there is some waiting involved to pause that loop, skip draw calls etc. So to maintain a minimum framerate, you have to make sure, that your update and render functions can happen in the available time.

In my (quite cpu intense) Voxel engine I had to solve that issue by distributing several tasks into their own threads to not block the rendering pipieline - that’s a huge pile of work and I wouldn’t recommend it, when it isn’t fully neccessary :slight_smile:

Yes that works 100 percent. There’s no rounding error

Oh thanks heaps.

I suppose you could manually set target frame rate to be half if your running slowly.

So if you miss a vsync for a frame, you just miss the vsync for that frame and have to wait for the next one. It does not maintain a framerate.

Just to be clear so no one gets the wrong idea.
Turning on vsync and skipping a draw implicitly means there is a limit on the framerate.

Vsync now days with newer monitors still applies its just that the crt traveling to the top isn’t what determines the refresh rate. Its the monitors pixel dimming speed that designates the refresh rate.

To say i light up a pixel on the monitor to be white and the next frame im going to draw black on that same pixel. The little LED light on screen after brightening takes some milliseconds to dim back down to black. So there is a limit on how fast i can draw a crisp set of images in a row.

This in practice can also lead to some motion blur as most monitors don’t wait for the the full dim to occur.

1 Like

I think this is the thread that needs this: