Calculating and capping frame rate

There are many results on Google about capping frame rate with SDL_GetTicks, and using that information I can cap the frame rate, or calculate the frame rate, but not both. I’m unfortunately not good at math at all, so I’m having trouble combining the two concepts on my own.

One example of what I’ve tried is from this link: Lesson 08 - Timing: Frame Rate, Physics, Animation

EDIT: To be clear, I want to be able to cap to a desired FPS, but also be able to get the current FPS as a string later in the application. So I can’t just copy and paste code that caps frame rate and be done with it.

Here’s the code I’ve written based on these examples (this is all inside a while loop):

const Uint64 start = SDL_GetPerformanceCounter();

while (SDL_PollEvent(&e) != 0) {
    if (e.type == SDL_QUIT) {
        quit = true;
    }
}

SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_UpdateWindowSurface(window);

const Uint64 end = SDL_GetPerformanceCounter();
const float elapsed = (end - start) / (float)SDL_GetPerformanceFrequency();
printf("%f\n", 1.f / elapsed);
SDL_Delay(floor(1 / 60 - elapsed * 1000.f));

From what I understand this should be printing a value close to 60, since that’s my desired FPS, but I’m just getting random numbers every time I print to the console.

Can someone help me understand what I’m doing wrong?

PS: I’m also not interested in VSync since I require a software renderer. The above code is using a renderer created from SDL_CreateSoftwareRenderer.

This is dangerous. If processing the frame took too long and exceeded the time window for the frame (due to the lag, spiral of death or the player moved the window using mouse), the result will be a negative number and the SDL will crash (runtime error). So first check if the period to freeze the thread is non-negative and if so, call SDL_Delay.

Back to the topic. To cap framerate, you need to know how many ticks a given operation must be performed (e.g. logic update), and between them, if there is free time, freeze the thread for a certain number of milliseconds/ticks. So, before the main loop, retrieve the resolution of the tick counter and count how many ticks the interval between subsequent updates is (depending on the fixed number of updates per second). At the end of each iteration of the main loop, check whether there is still time before the next update and, if so, freeze the thread.

It should be noted here that Windows cannot freeze a thread for one millisecond — usually it is two milliseconds. In order not to lose a millisecond for the next frame, it is worth checking whether the time until the next frame is less than 2ms and if so, eat this time using a short spinlock.

I don’t know what your use case is, but in general even the Software Renderer ends up painting to your screen, so there is no advantage in having a frame rate faster than the screen refresh rate, since some of the frames will never be seen!

Also, if your frame rate is not locked to the screen refresh rate you will experience motion artefacts, such as ‘juddery’ motion rather than smooth motion. So as a rule synchronising with VSync is desirable even when using the Software Renderer.

If you are rendering purely to an internal buffer, for the purposes of recording a video file for example, then you can disregard those comments.

3 Likes