Game Loop getting 58-62 FPS. Why not exactly 60FPS?

Here’s my game loop:

  uint64 target_fps = 60;
  uint64 ticks_per_s = SDL_GetPerformanceFrequency();
  uint64 target_ticks_per_f = ticks_per_s/target_fps - (ticks_per_s/1000); //aim for (target - 1ms) to err on side of > 60fps

  uint64 ticks_per_cur_f = 0;
  uint64 t_last_render = 0;
  uint64 t_last_update = SDL_GetPerformanceCounter()-target_ticks_per_f;
  int max_updates = 3;
  int updates = max_updates-1;

  while(!done)
  {
    while(
      t_last_update > SDL_GetPerformanceCounter() - target_ticks_per_f &&
      t_last_render > SDL_GetPerformanceCounter() - target_ticks_per_f
    )
    {
      SDL_Delay(1);
    }

    //update
    updates = 0;
    while(updates < max_updates && t_last_update < SDL_GetPerformanceCounter() - target_ticks_per_f)
    {
      t_last_update += target_ticks_per_f;
      updates++;
      pollEvents(); //possibly sets done = true
      simData();
    }
    if(updates >= max_updates) t_last_update = SDL_GetPerformanceCounter();

    if(t_last_render < SDL_GetPerformanceCounter() - target_ticks_per_f)
    {
      ticks_per_cur_f = SDL_GetPerformanceCounter()-t_last_render;
      t_last_render = SDL_GetPerformanceCounter();
      render();
      SDL_GL_SwapWindow(window);
      glFinish();
    }
  }

It’s a fixed timestep (to simplify/make consistent any updates).

It essentially just does this:

  • Wait (SDL_Delay()) until enough time has passed requiring either an update or a render
  • While “last update” was > 16ms ago, update() and add 16ms to when “last update” was (maxing out at 3 updates assuming it got really far behind)
  • If “last render” was > 16ms ago, render (and set “last render” to “now”)
  • Repeat

Even when I do nothing in update() or render(), it fluctuates anywhere between 58FPS and 62FPS. Why would this be?
I understand that SDL_Delay only has a fidelity of 1ms, but I even set “target ticks” to be 1ms less than necessary to try to account for this.

Any ideas?

Thanks!

There’s no good way to force your render loop to a strict FPS count and it’s considered not a good idea to even try. The best approach is to render everything based on time and and enable VSync if you want to control the FPS.