Search code examples
c#monogameframe-rate

Achieving lower frame rates without screen tearing


I'd like to achieve 24fps in a game. I am able to do this with the following code:

IsFixedTimeStep = info.fixedTimeStep;
TargetElapsedTime = TimeSpan.FromSeconds(1f / 24f);

However this produces either a stuttering frame rate or screen tearing, depending on whether vsync is enabled or not. I would expect this to be the case because of the mismatch between 24fps and the 60fps of the monitor.

I decided to try instead to achieve 30fps:

IsFixedTimeStep = info.fixedTimeStep;
TargetElapsedTime = TimeSpan.FromSeconds(1f / 30f);

However this also produces either a stuttering image or screen tearing. I can't understand why this happens when 30fps is a nice half of the 60fp monitor refresh. Perhaps this is because the frame rates involved are not precise?

A bit of Googling caused me to discover that I can get a far better result by telling Monogame to sync every other screen refresh:

graphics = new GraphicsDeviceManager(game);
graphics.PreparingDeviceSettings += (sender, e) =>
{
    e.GraphicsDeviceInformation.PresentationParameters.PresentationInterval = PresentInterval.Two;
};

[EDIT 1: It has been brought to my attention that this is a bad idea because it assumes a monitor refresh rate of 60, so I need a better method even more!]

[EDIT 1.1: I discovered that this line specifies 60fps as a basis for then using the above technique of hitting 30fps:

game.TargetElapsedTime = TimeSpan.FromTicks(166666);

]

This gives me something around 30fps but with a smooth result. This is an acceptable result for me, but I wondered if anyone knows of any way at all of achieving something closer to 24fps? Or is this just impossible without the jittering/tearing?

Many thanks!

[EDIT 2: I get the same results whether in exlusive fullscreen or borderless window mode.]


Solution

  • Well I figured out what I think is the best achievable solution. This gives me 24fps with a pretty smooth (as smooth as 24 fps is likely to give) result.

    IsFixedTimeStep = true;
    
    TargetElapsedTime = TimeSpan.FromTicks(208333); // 48fps (will be halved to 24fps).
    
    // The following effectively halves the frame rate to 24fps by syncing every other refresh.
    graphics.PreparingDeviceSettings += (sender, e) =>
    {
        e.GraphicsDeviceInformation.PresentationParameters.PresentationInterval = PresentInterval.Two;
    };
    

    It gives a better result than just using TimeSpan.FromTicks(416666) to set it at 24fps. I'm not sure why this is.

    30fps can be achieved by adjusting the FromTicks value to give 60fps, which then gets halved to 30fps. Again, it produces a better result for me than just aiming for 30fps in the first place.