2
\$\begingroup\$

My attempt at a fixed framerate using SDL2 without using VSync. Just using SDL_Delay left the fps a bit slower or faster due to the fact SDL_Delay only works with milliseconds. So the solution I came up with is after using SDL_Delay the remainder of the "extra" time is elapsed through a loop. The solution seems a little bit cluttered to me and my experience with programming in general is very limited so any pointers would be much appreciated.

float frame_cap{ 60 };
float ms_per_frame{ 1000.0f / frame_cap };
float fps{ 0 };
uint64_t start_counter;
uint64_t end_counter;

bool quit{ false };
while( quit != true )
{
    start_counter = SDL_GetPerformanceCounter();

    //HANDLE INPUT
    //UPDATE
    //RENDER

    end_counter = SDL_GetPerformanceCounter();
    //multiplying by 1000.0f to convert to ms
    float elapsed_ms = ((end_counter - start_counter) / (float)SDL_GetPerformanceFrequency()) * 1000.0f;
    if( elapsed_ms < ms_per_frame )
    {
        float ms_left = ms_per_frame - elapsed_ms;
        SDL_Delay( floor(ms_left) );

        //loop for the amount of time that could not be delayed with SDL_Delay
        float missed_ms = ms_left - floor(ms_left);
        start_counter = SDL_GetPerformanceCounter();
        float delayed_ms { 0 };
        while(delayed_ms < missed_ms)
        {
            end_counter = SDL_GetPerformanceCounter();
            delayed_ms = ((end_counter - start_counter) / (float)SDL_GetPerformanceFrequency()) * 1000.0f;
        }
        //adding time delayed to elapsed time of frame for fps calculation
        elapsed_ms += floor(ms_left) + delayed_ms;
        /*floor(ms_left) is time delayed using SDL_Delay
        this has a chance to be inaccurate if SDL_Delay 
        delays more then floor(ms_left) due to OS scheduling*/
    }
    //dividing by 1000.0f to convert to seconds
    fps = 1.0f / (elapsed_ms / 1000.0f);
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Why you exactly need the framerate to be constant?

You can use SDL_GetTicks() this way:

const int ms_frame = 1000 / 60;
Uint32 initial_ticks, elapsed_ms;
while(true){
      initial_ticks = SDL_GetTicks();

      //do things

      elapsed_ms = SDL_GetTicks() - elapsed_ms;
      if(elapsed_ms < ms_frame) SDL_Delay(ms_frame - elapsed_ms);
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ elapsed_ms = SDL_GetTicks() - initial_ticks;? \$\endgroup\$
    – xbelanch
    Aug 12, 2021 at 9:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.