Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to accurately throttle FPS in C#

I am working on an application that continuously polls windows for graphics drawn in video and games, takes a screen capture, and then does some processing. I am trying to implement a configurable FPS throttle to avoid using resources unnecessarily when it doesn’t need to be running at such a high frame rate.

I’ve created this loop class and use a Stopwatch with elapsed ticks to calculate how long each frame takes to process and to throttle the current frame if it’s processing too fast for the desired FPS.

Running this results in the FPS sitting around 35-40 when the target FPS is 60, and changing the target FPS results in an actual FPS in the same ratio as 35-40 / 60 actual to target. I’ve double checked the math and can’t seem to figure out what’s going wrong, as debugging it is tricky because breakpoints affect the elapsed time. Any suggestions on how to fix my loop or what’s going wrong?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    public class ProcessLoop
    {
        const int TARGET_FPS = 60;
        const long OPTIMAL_TIME = (TimeSpan.TicksPerSecond / TARGET_FPS);

        private static Stopwatch _time = new Stopwatch();
        private int _frames = 0;
        private int _fps = 0;

        public void Run(CancellationToken stoppingToken, Action process)
        {
            _time.Start();
            long lastLoopTime = _time.ElapsedTicks;
            long lastSecondUpdate = lastLoopTime;

            while (!stoppingToken.IsCancellationRequested)
            {
                lastLoopTime = _time.ElapsedTicks;

                // Process one frame here
                process();
                _frames++;

                // The time after processing work
                var now = _time.ElapsedTicks;

                // How long it took to process the work done this frame
                var deltatime = now - lastLoopTime;

                if (now - lastSecondUpdate >= TimeSpan.TicksPerSecond)
                {
                    _fps = _frames;
                    _frames = 0;
                    lastSecondUpdate = 0;
                    _time.Restart();
                    Console.WriteLine($"FPS: {_fps}");
                }

                // Sleep to approach optimal time per frame
                if (deltatime < OPTIMAL_TIME)
                {
                    Thread.Sleep(TimeSpan.FromTicks(OPTIMAL_TIME - deltatime));
                }
            }
        }
    }

>Solution :

Thread.Sleep

There’s your problem, relinquishing a thread in a protected OS like Windows offers no guaratee that you’ll get it back in the time specified. In fact, you are guaranteed to not get it back in the time you request, ever. It even says so in the official documentation.

Either busy wait until the right time (high CPU usage), or use a hybrid approach (if it’s essential to use as little CPU as possible) where you do tiny sleeps until you get "close enough" to the target time (~3ms with high precision timing enabled) then busy wait the rest of the way there.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading