What specifically does SDL_RENDERER_SOFTWARE do?

the renderer is a software fallback

What does this mean? That if SDL_RENDERER_SOFTWARE flag is on, and there is no GPU, that instead of failing, the rendering will be done on the CPU?

That if this flag is on, and SDL_RENDERER_ACCELERATED is off, that the CPU will be used for rendering, despite there being a GPU?

I really can’t find any answer to this question anywhere. I have even tried reading the source code.

I need to know this in order to be able to decide which flags I want. The current explanation doesn’t really parse.

Exactly. But in these days, having GPU and not using it is just stupid. :wink:

But what happens in the following scenarios:

SOFTWARE : ACCELERATED
   OFF        OFF
   OFF        ON
   ON         OFF
   ON         ON

?

@multivita: SDL have additional checks to set proper renderer type if no one is specified and in the case that both are specified. You can also check the implementation of the SDL_CreateRendererWithProperties function, if you are curious.

If you don’t explicitly create the renderer as SOFTWARE then SDL will try to create one using whatever the default GPU backend is for the given platform.

edit: beaten

@furious-programming : I have actually extensively looked at the source code, but I am unable to deduce what is going on. Could you be so kind and interpret for me what happens if both flags are on

Specifically, I would like to know what is the order of preference? Because of the confusing bits of info I have:

  • order of preference in case of no flags is ACCELERATED is prefered (as mentioned in the wiki)
  • I heard that having both flags is an indicator that you want either of the two posibilites (is there a preference hierarchy?)
  • looking at SDL_RenderGeometryRaw, SOFTWARE looks like an indiscriminate manual ovveride on each function call (which would imply it overrides ACCELERATED)

The code he posted makes it pretty explicit: if SOFTWARE is specified then you get a software renderer. Otherwise it tries to create a renderer using whatever backend was specified (in the case of NULL it will try to create the renderer using whatever backend is the default for the given system).

The idea is that you can specify ACCELERATED if you only want a hardware accelerated renderer, and if one can’t be created then creating the renderer will fail instead of falling back on creating a software renderer. At the same time, if you want a software-only renderer, even if a GPU is present, you can specify SOFTWARE and all rendering will be done by the CPU.

Since even the Raspberry Pi has a GPU, it’s kind of a moot point unless you’re specifically developing for an embedded system you know doesn’t have one (but those systems usually have a weak CPU, so you might be better off using the SDL_Surface software blitting methods), or you’re porting SDL to a new platform and want to use the software renderer as a reference.

1 Like

@sjr I’lll be honest, I haven’t even looked at the code because I have read it a hundred times.

To prove I have different code, I send you the link to the latest 2.28.5 release to prove it is infinitely more unreadable and illogical. I assume the link @furious-programming sent is SDL3 and this part of the code was changed recently. I would love if you guys could somehow confirm that the functionality is the same in 2.28.5

Heck, there isn’t even a SDL_SetStringProperty function in the old version.

Conceptually the two flags are mutually exclusive (“always use software rendering” versus “never use software rendering”), so it doesn’t really matter what happens if they’re both specified because you’re not meant to do that. C just doesn’t have an easy way to express mutual exclusion in bit flags, aside from the names of each flag and the documentation and intent of them.

So in SDL2 if a hardware renderer can’t be created, and the ACCELERATED flag isn’t set, it will try to create a software renderer as a fallback. If the flag is set then the call instead fails if a hardware renderer can’t be created.

In the code you linked to, it checks to see if the application has specified a specific renderer backend (OpenGL, Metal, etc.). If not, SDL loops through the available backends, checking to see if the flags specified by the application are compatible with the flags specified by the backend. If they are, it tries to create a renderer using it. If creation fails, or the flags aren’t compatible, it moves on to the next backend in the list.

Since the software renderer is always the last one in the list, if SDL_RENDERER_ACCELERATED wasn’t specified then you’ll get a software renderer if a hardware renderer can’t be created (such as by not having a GPU). If SDL_RENDERER_SOFTWARE was specified then it’ll skip trying to create a hardware renderer because the hardware renderer’s don’t have SDL_RENDERER_SOFTWARE in their compatibility flags.

If you specify both then you’ll probably just not get a renderer at all. Like @slime said, they’re mutually exclusive.

Ok guys I have an update on this. Straight from one of the top guys.

closed github issue link

Apparently, setting no flags, or setting both does the same thing.

Dude, I literally went through the source code and explained it to you.

@slouken is probably thinking of SDL3, because actual testing with SDL2 reveals, as I stated in my previous post, that specifying both SDL_RENDERER_ACCELERATED and SDL_RENDERER_SOFTWARE doesn’t work. Because no renderer backend matches both flags, and SDL_CreateRenderer() just goes through the list until it finds a renderer that matches the flags you specified. And since no renderer is both a HW and a SW renderer, it doesn’t find one and fails.

You can try it yourself:

/* compile with
cc softwarehardware.c -o softwarehardware `sdl2-config --cflags --libs`
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <SDL2/SDL.h>

static void bailout(const char *title, const char *message)
{
	fprintf(stderr, "ERROR: %s: %s\n", title, message);
	exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
	if(SDL_Init(SDL_INIT_VIDEO) != 0) {
		bailout("Can't init SDL", SDL_GetError());
	}

	SDL_Window *window = SDL_CreateWindow("Test",
			SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
			0, 0,
			0);
	if(window == NULL) {
		bailout("Can't create window", SDL_GetError());
	}

	/* This shouldn't work, these are mutually exclusive! */
	uint32_t renderFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_SOFTWARE;
	SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, renderFlags);
	if(renderer == NULL) {
		bailout("Can't create renderer", SDL_GetError());
	}

	int running = 1;
	while(running) {
		SDL_Event event;
		while(SDL_PollEvent(&event)) {
			switch(event.type) {
			case SDL_QUIT:
				running = 0;
				break;
			}
		}

		SDL_SetRenderDrawColor(renderer, 0, 127, 255, 255);
		SDL_RenderClear(renderer);

		SDL_RenderPresent(renderer);
	}

	SDL_Quit();

	return 0;
}

Fails and exits with:

ERROR: Can’t create renderer: Couldn’t find matching render driver

1 Like

I don’t know why this discussion is still going on, since it is obvious that you either create a hardware or software renderer, depending on your needs. The way SDL works is strictly defined (and well explained by @sjr), so everything should be clear.

However, creating a renderer using both flags is incorrect and useless (impractical), so it doesn’t really matter what happens if you try it, because it is fundamentally a mistake. Just don’t do stupid things and everything will be fine. :wink:


By the way, the implementation in SDL3 is better because it generates an error when both flags are used, so there are no ambiguities here. Although I would prefer SDL to explicitly state that it is not possible to create a renderer that is both hardware and software. A separate error message dedicated to this situation would be recommended.

1 Like