Cannot present to a simple SDL2 windows on Ubuntu Linux

Hi,
I have a problem presenting to a plain SDL2 Window on Linux.

I’ve been developing a Vulkan game engine using SDL2 for the window creation (SDL_WINDOW_VULKAN flag), input, audio etc.
This has worked flawlessly for two years, and continues to work very well.

I decided to try and make a launcher window, so the user can pre-select the game screen resolution, windowed / full screen mode, before starting the game.
This would be integrated into the engine, so the idea is to open a basic SDL2 window and draw UI elements into it with custom UI code.
(I know there are window UI options like wxWidgets, and GTK, but I want to reduce dependencies as much as possible.)
Once the selections have been made, the window will be close, then a SDL2 Vulkan window will be created, and the game starts.

But, I cannot get a simple VSynced SDL2 window to work reliably.

First I tried creating a VSynced SDL2 window and rendering an image to it, but when the application was started it would randomly display the image.
Confused by this, I simplified it and just cleared the screen with a clear colour - same problem, either it cleared the screen or it didn’t, randomly.

Simplifying further, I created a (isolated from my engine) console test program (SDL_clear_window.cpp), that would Init SDL, create a VSynced window, create an accelerated renderer, clear it with white, then SDL_RenderPresent() 120 frames in a loop (this should take 2 seconds on my laptop’s 60Hz VSynced display), then close everything down.
A full stop is sent to the console via printf to indicate each frame iteration.

When this test application was started, again, it would randomly finish early (instantly sometimes), or present the screen as rapid white flashes, like as if it were presenting white, then black, then white, black, white…

At my wits end, I created a run.sh script to run the application ten times whilst timing each iteration time, with a 3 second delay between restarts (to give the system time to settle down). I got these timings:
Loop index 1: 1.605
Loop index 2: 0.215
Loop index 3: 1.188
Loop index 4: 0.200
Loop index 5: 0.202
Loop index 6: 0.217
Loop index 7: 0.208
Loop index 8: 2.070
Loop index 9: 0.186
Loop index 10: 0.214

As you can see, loop index 8 ran for two seconds as expected, but the the others are all over the place, some quitting instantly.

My SDL_clear_window.cpp C++ file is checking every SDL2 call for errors, there are none.

Thinking that I’m going insane, I tried these github repos: https://github.com/AlmasB/SDL2-Demo and https://github.com/spacejack/sdl2-examples (helloSDLcpp).
Both of those did not show any window contents.

All the above was compiled and executed on my DELL E6230 development laptop running Kubuntu studio 20.04.1 (X11 session) with a low-latency kernel, and SDL2.0.10 as that’s the current repo version.

I also tried my SDL_clear_window.cpp test program on a DELL E5470 laptop running a live USB Ubuntu 20.04.1 (X11 session) - same problem. Again SDL2.0.10.

Finally I created a VS2019 solution using my SDL_clear_window.cpp test program, and lo and behold, I had a window appear, with a white background, no flickering, which closed two seconds later. This project used SDL2.0.12.

All cases use the intel integrated GPU, including the Win 10 project.

Which brings me to my question…
Does anyone have any ideas, something else I can try to figure out why this simple SDL2 window code doesn’t run on my Linux machines?

Using SDL_RENDERER_SOFTWARE resulted in the error ‘Couldn’t find matching render driver’.

Since the Vulkan flagged SDL2 window works perfectly, I’m seriously considering creating a Vulkan accelerated launch window, closing that after the options are selected, then creating a new Vulkan window for the main game (with the selected options), only because it works so reliably.

Or I could look into wxWidgets / GTK and see how much work that is to integrate it into my engine, (I’d rather not go down this route as previously mentioned).

I have the SDL_clear_window.cpp based Linux project with build info as a zip file, available below from my GDrive as I don’t know where else to put it, sorry.
https://drive.google.com/file/d/1vCmIqVRsqkb4s5qxsZvCh0p0yVRuPikn/view?usp=sharing

A video of the effect is available here:
https://drive.google.com/file/d/1wydqHHNSqPmSf4-f4tM0EmtRKNiLIApo/view?usp=sharing

Any help would be appreciated. :slight_smile:

INFO:
Development Laptop Kubuntu studio 20.04.1 (X11 session)
*OS: Ubuntu 20.04.1 LTS x86_64 *
*Host: Latitude E6230 01 *
*Kernel: 5.4.0-45-lowlatency *
*Shell: bash 5.0.17 *
*Resolution: 1366x768 *
*DE: Plasma *
*WM: KWin *
*Theme: Breeze [Plasma], Breeze [GTK2/3] *
*Icons: breeze [Plasma], breeze [GTK2/3] *
*Terminal: konsole *
*CPU: Intel i5-3340M (4) @ 3.400GHz *
*GPU: Intel 3rd Gen Core processor Graphics Controller *
*Memory: 1457MiB / 7865MiB *
VGA compatible controller: Intel Corporation 3rd Gen Core processor Graphics Controller (rev 09)

Alternative Test Laptop running a live USB Ubuntu 20.04.1 (X11 session) - same problem
*OS: Ubuntu 20.04.1 LTS x86_64 *
*Host: Latitude E5470 *
*Kernel: 5.4.0-42-generic *
*Resolution: 1920x1080 *
*DE: GNOME *
*WM: Mutter *
*WM Theme: Adwaita *
*Theme: Yaru [GTK2/3] *
*Icons: Yaru [GTK2/3] *
*Terminal: gnome-terminal *
*CPU: Intel i5-6300U (4) @ 3.000GHz *
*GPU: Intel Skylake GT2 [HD Graphics 520] *
*Memory: 990MiB / 7629MiB *
VGA compatible controller: Intel Corporation Skylake GT2 [HD Graphics 520] (rev 07)

Don’t forget that you still have to clear the screen and poll for events every frame. Your sample code didn’t work on my system (finished instantly), until I moved the screen clearing inside the render loop and added an empty event poll while loop.

Something like (with a hardware accelerated renderer):

for(int r = 0; r < 120; r++) {
    SDL_Event event;
    while(SDL_PollEvent(&event)) {}
    SDL_RenderClear(pRenderer);
    SDL_RenderPresent(pRenderer);
}

After changing it, it showed a blank white screen for 2 seconds.

Depending on the backend driver, SDL_Renderer is probably needing to reset some internal state for each new frame and doing that in the call to SDL_RenderClear()

Hi sjr,
Thanks for the feedback.

It’s interesting that the test code (original - without the modifications you suggested) also didn’t work on your system, yet on Windows 10 it works perfectly, approx 2.1 seconds every time when measured with the PowerShell ‘Measure-Command’.

I added the code you suggested in two steps. Here’s the results as tested on my development Laptop (Kubuntu studio 20.04.1 (X11 session)):

Added ‘SDL_RenderClear(pRenderer)’ inside the for loop:
Loop index 1: 1.961
Loop index 2: 0.901
Loop index 3: 0.707
Loop index 4: 1.447
Loop index 5: 0.974
Loop index 6: 1.074
Loop index 7: 1.109
Loop index 8: 1.076
Loop index 9: 1.931
Loop index 10: 1.442

Added both ‘SDL_RenderClear(pRenderer)’ and ‘while(SDL_PollEvent(&event)) {}’ inside the for loop:
Loop index 1: 1.723
Loop index 2: 1.658
Loop index 3: 1.841
Loop index 4: 1.025
Loop index 5: 2.098
Loop index 6: 1.656
Loop index 7: 2.115
Loop index 8: 1.630
Loop index 9: 1.290
Loop index 10: 1.355

As you can see, adding the SDL_PollEvent() made the rendering more stable, but it’s not yet locking to two seconds of frames. It still finished early on index 4 (1.025s) on the second example above.

In the meantime, I have created a new launcher window. This is again an SDL2 window but this time using the SDL_WINDOW_VULKAN flag. This window works perfectly, and I can render my UI text to it no problem using the Vulkan API.

I can only conclude that there’s something wrong with the built-in SDL2 accelerated renderer back-end on my system.

As I have bypassed the problem using Vulkan for the launcher, this issue can now be closed down, but, I’m happy to continue testing if anyone feels that it should be resolved.

For the record, here is the final test code (SDL_clear_window.cpp):

#include"SDL.h"

SDL_Window* pWindow = NULL;
SDL_Renderer *pRenderer = NULL;
SDL_Surface* pBMPimage = NULL;
SDL_Texture* pTexture = NULL;

int main(int argc, char *argv[])
{
	// Init SDL
	printf("Init SDL...");
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		printf("Error!: %s\n", SDL_GetError());
		return 0;
	}
	printf("OK.\n");

	// Create the SDL window      
	printf("Creating Window...");
	pWindow = SDL_CreateWindow("SDL Multiple Window Clear Test",
			               SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
			               640, 480,
			               SDL_WINDOW_RESIZABLE);
	if (pWindow == NULL) {
		printf("Error!: %s\n", SDL_GetError());
		return 0;
	}
	printf("OK. ");

	// Create the renderer
	printf("Creating accelerated renderer with wait on Vsync...");
	pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
	if (pRenderer == NULL) {
		printf("Error!: %s\n", SDL_GetError());
		return 0;
	}
	printf("OK. ");

	// Select the clear colour to white
	printf("Set clear colour to white...");
	if(SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255) < 0) {
		printf("Error!: %s\n", SDL_GetError());
		return 0;
	}
	else printf("OK. ");

	// Clear the entire screen to white
	printf("Set render colour: ");
	if(SDL_RenderClear(pRenderer) < 0) {
		printf("Error!: %s\n", SDL_GetError());
		return 0;
	}
	else printf("OK.\n");

	// Render 120 VSynced frames
	printf("Rendering");
	for ( int r = 0; r < 120; r++) {
        SDL_Event event;
        while(SDL_PollEvent(&event)) {}
        
		printf(".");

        // Present the screen - returns void
        SDL_RenderClear(pRenderer);
		SDL_RenderPresent(pRenderer);
	}
	printf("\n");

	printf("Killing renderer, window and closing SDL...");
	if (pRenderer != NULL) SDL_DestroyRenderer(pRenderer); 
	if (pWindow != NULL) SDL_DestroyWindow(pWindow);
	SDL_Quit();
	
	printf("OK. Quitting to OS.\n");
		
	return 0;
}

Maybe the SDL_Renderer backend it’s using can’t vsync, or can’t right away (like with the Metal backend on macOS).

But since with Vulkan you create and manage the swapchain yourself, it’s always vsync’ed if you want it to be.