Schizophrenic renderer when in fullscreen mode?


#1

When trying to render stuff fullscreen using desktop resolution (1920x1080) I encountered a weird issue. When I create the window fullscreen, every 2nd time SDK_renderPresent is called it swaps to a content buffer that has already been overridden but seems for some weird reason still be stored in the renderer. Needless to say Im using only one renderer, and in windowed mode the program shows no such issue.

Im using a loop like this
while(isRunning){
updateScreen();
handleEvents();
}

In handleEvents() mouse and keyboard clicks are processed from the queue to allow me to draw stuff on the screen, in updateScreen() only SDK_renderPresent is called. So when I first tried out fullscreen the screen was flipping madly between the black screen that was created on start by SDK_renderClean and the initial content I created with my own code using only SDK_setRenderDrawColor and SDK_renderDrawPoint.

Im now using a hasChanged flag in order to only call renderPresent when stuff on the screen has actually changed, so at least as long as Im not drawing stuff the picture remains stable and fine. But as soon as I start drawing stuff and renderPresent is called repeatedly to update the screen in short order to get smooth changes, the picture permanently flips between the actual content and an old content. When I draw a rectangle by pressing the mouse button and dragging the opposite corner over the screen I can very clearly see that renderer alternates between two completely different pictures and even my drawing affects both buffers alternatingly so that half the rectangles appear on the new stuff and the other half on the old buffer.

Is there anything important I need to know about how the internal buffer works when in fullscreen mode? Is there some trick I can use to avoid this issue?


#2

I just found that this issue does not occur when I just create the window in desktop resolution without activating the fullscreen flag.


#3

I wonder if you are taking this into account: “The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames. You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame’s drawing, even if you plan to overwrite every pixel”.


#4

Ah. So I have to do a renderClear() and recreate the backbuffer completely for every frame, even if just one pixel has changed? I already considered trying this but it seemed such a wasteful way of doing it and I would have expected a major performance drop.

Thanks for the hint, this is exactly what I needed to know.


#5

You can create a ‘target texture’ (separate from the backbuffer) to which all your rendering is done. Then, once a frame, you copy that texture to the backbuffer. So your updateScreen function becomes:

	SDL_SetRenderTarget(renderer, NULL);
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
	SDL_RenderClear(renderer);
	SDL_RenderCopy(renderer, texture, NULL, NULL);
	SDL_RenderPresent(renderer);
	SDL_SetRenderTarget(renderer, texture);

Now you can change just one pixel (or none) each frame.


#6

If you are using a “target texture”, can’t you skip the “clear” each frame, assuming the texture is the size of the screen/window? It seems wasteful to do a “clear” and then do a “blit” of the fullscreen texture copy too…


#7

I would refer you to the extract from the SDL docs that I quoted earlier: "You are strongly encouraged to call SDL_RenderClear)() … even if you plan to overwrite every pixel*. I don’t like the phrase “strongly encouraged to” in formal documentation, but I assume it means “must”.


#8

About SDL_renderCopy() the doc says “Use this function to copy a portion of the texture to the current rendering target.” I guess it means “copy a portion of the texture to the backbuffer”, right?


#9

No, if you have set a target texture it copies to there, not to the backbuffer. To copy to the backbuffer you must ensure that it is selected as the target:

SDL_SetRenderTarget(renderer, NULL); // select backbuffer as target

If SDL_RenderCopy() always copied to the backbuffer you couldn’t use it to copy from one texture to another:

SDL_SetRenderTarget(renderer, destination_texture);
SDL_RenderCopy(renderer, source_texture, NULL, NULL);

#10

Got it :slight_smile: Many thanks!