SDL_RenderPresent() not waiting for vsync - how to wait?

5.4k views Asked by At

I initialize SDL with this code:

SDL_Init(SDL_INIT_VIDEO);

SDL_Window* win = SDL_CreateWindow(
    "SDL Window",
    SDL_WINDOWPOS_UNDEFINED,
    SDL_WINDOWPOS_UNDEFINED,
    WIDTH,
    HEIGHT,
    SDL_WINDOW_SHOWN
);

SDL_Renderer* ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
SDL_GL_SetSwapInterval(1); // probably has no effect since it's not using GL

I then render with a non-SDL software renderer and present it to the window with this code:

SDL_UpdateTexture(screenBuffer, NULL, screenData, WIDTH*4);

SDL_RenderClear(ren);
SDL_RenderCopy(ren, screenBuffer, NULL, NULL);
SDL_RenderPresent(ren);

The framerate is completely uncapped, and I have no idea why.

Adding | SDL_RENDERER_PRESENTVSYNC to the SDL_CreateRenderer flags simply makes the window a blank white screen. Though I need to use the SDL_RENDERER_SOFTWARE flag (even though I'm not using SDL's software renderer other than to present the screen) or else will SDL_RenderPresent() will stall for a very, very long time resulting in about 1 frame per second.

How can I make SDL_RenderPresent() wait for vsync, or wait for it (accurately) myself?

1

There are 1 answers

3
Mr. Hell On

VSync is a hardware feature. When VSync is enabled, the video card stops the renderer from presenting a frame until a signal from the monitor indicating vertical syncronism arrives (which means it finished displaying the last frame).

If you are using a software renderer there's no way to detect this signal since you're not using the video card to render. It's up to you to set a framerate and wait for the next frame.

An example for 60 frames per second:

#define TICKS_FOR_NEXT_FRAME (1000 / 60)

int lastTime = 0;

void update() {
    while (lastTime - SDL_GetTicks() < TICKS_FOR_NEXT_FRAME) {
        SDL_Delay(1);
    }

    ... // SDL_RenderCopy...

    SDL_RenderPresent(renderer);
    lastTime = SDL_GetTicks();
}

A call to update will only present the frame if at least 15 ms have passed. 15 ms is the time needed for a framerate of 60 FPS.

I know this question is old, but i decided to post the answer for other people who might need it.

EDIT

As stated in the comments, this will not prevent tearing since you are not syncing to the vblank signal. This code only helps on capping the framerate. As far as I know there is no way to prevent tearing when using a software renderer (because you can't detect the vblank signal).