Frame Rate Limiting with High-Res Timers

How can we use high-resolution timers to implement frame rate limiting?

Frame rate limiting is an important technique in game development to ensure consistent performance and reduce unnecessary resource consumption. High-resolution timers, like SDL_GetPerformanceCounter(), can be used to implement precise frame rate limiting. Here's how you can do it:

Basic Concept

The idea is to calculate how long each frame should take (target frame time) and then wait if the frame finishes early. For example, if we want 60 FPS, each frame should take approximately 1/60 seconds or about 16.67 milliseconds.

Implementation

Here's a basic implementation using SDL's high-resolution timer:

#include <SDL.h>
#include <iostream>

const int TARGET_FPS{60};
const double TARGET_FRAME_TIME
  {1.0 / TARGET_FPS};

void simulateGameLogic() {
  // Simulate some game logic
  SDL_Delay(5); // Simulate 5ms of work
}

void render() {
  // Simulate rendering
  SDL_Delay(3); // Simulate 3ms of rendering
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);

  Uint64 performanceFrequency{
    SDL_GetPerformanceFrequency()};
  Uint64 frameStart;
  double elapsedSeconds;

  for (int frame{0}; frame < 600; ++frame) {
    frameStart = SDL_GetPerformanceCounter();

    simulateGameLogic();
    render();

    elapsedSeconds = (
        SDL_GetPerformanceCounter() -
        frameStart) /
      static_cast<double>(performanceFrequency);

    if (elapsedSeconds < TARGET_FRAME_TIME) {
      SDL_Delay(
        static_cast<Uint32>((TARGET_FRAME_TIME -
          elapsedSeconds) * 1000));
    }

    if (frame % 60 == 0) {
      std::cout << "FPS: "
        << 1.0 / ((SDL_GetPerformanceCounter() -
            frameStart) /
          static_cast<double>(
            performanceFrequency))
        << '\n';
    }
  }

  SDL_Quit();
  return 0;
}
FPS: 60.0213
FPS: 59.9881
FPS: 59.9902
FPS: 60.0156
FPS: 59.9923
...

Explanation

  1. We define our target FPS and calculate the target frame time.
  2. At the start of each frame, we record the current time using SDL_GetPerformanceCounter().
  3. We run our game logic and rendering.
  4. We calculate how much time has elapsed during this frame.
  5. If we've used less time than our target frame time, we delay the remainder.
  6. We print the actual FPS every 60 frames to check our results.

Considerations

  • This method uses SDL_Delay() for simplicity, but it's not always precise. For more accuracy, you could use a busy-wait loop, though this consumes more CPU:
while (
  (SDL_GetPerformanceCounter() - frameStart) /
    static_cast<double>(performanceFrequency)
  < TARGET_FRAME_TIME) {
  // Busy wait
}
  • Frame rate limiting can lead to slightly uneven frame pacing. For smoother animation, you might want to use a fixed time step with interpolation.
  • Some displays have variable refresh rates (e.g., 144Hz). You might want to sync with the display's actual refresh rate for optimal smoothness.
  • For very high frame rates, the overhead of the timing code itself can become significant. In such cases, you might need more sophisticated approaches.

Remember, while frame rate limiting can save power and provide consistent performance, it's not always necessary. Many games run as fast as they can and use delta time for smooth animation. The best approach depends on your specific requirements.

High-Resolution Timers

Learn to measure time intervals with high accuracy in your games

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

SDL Performance Counter vs Ticks
How does using SDL_GetPerformanceCounter() differ from using SDL_GetTicks64()?
SDL vs std::chrono for Timing
What are the advantages of using std::chrono over SDL's timing functions?
SDL Performance Frequency Explained
Why do we divide by SDL_GetPerformanceFrequency() when calculating time deltas?
Simulating Lower Frame Rates
Is it possible to simulate lower frame rates using high-resolution timers for testing purposes?
Using Low-Resolution Timers in Games
Are there any situations where using lower resolution timers might be preferable?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant