High-Resolution Timers

Frame Rate Limiting with High-Res Timers

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

Abstract art representing computer programming

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.

This Question is from the Lesson:

High-Resolution Timers

Learn to measure time intervals with high accuracy in your games

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

High-Resolution Timers

Learn to measure time intervals with high accuracy in your games

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 71 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved