From c45c4a5e5167bf0d0f2df8a4076d80b6e8a044da Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Tue, 21 Jan 2025 11:23:04 -0500
Subject: [PATCH] render: SDL_HINT_RENDER_DRIVER now accepts a comma-separated
list.
Fixes #11077.
---
include/SDL3/SDL_hints.h | 8 +++++++
include/SDL3/SDL_render.h | 3 +++
src/render/SDL_render.c | 46 ++++++++++++++++++++++-----------------
3 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index 9f6b58ba4bdef..58a2fc5dffdf7 100644
--- a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -2900,6 +2900,10 @@ extern "C" {
* - "gpu"
* - "software"
*
+ * This hint accepts a comma-separated list of driver names, and each will
+ * be tried in the order listed when creating a renderer until one succeeds
+ * or all of them fail.
+ *
* The default varies by platform, but it's the first one in the list that is
* available on the current platform.
*
@@ -3289,6 +3293,10 @@ extern "C" {
* force a specific target, such as "x11" if, say, you are on Wayland but want
* to try talking to the X server instead.
*
+ * This hint accepts a comma-separated list of driver names, and each will
+ * be tried in the order listed during init, until one succeeds or all of them
+ * fail.
+ *
* This hint should be set before SDL is initialized.
*
* \since This hint is available since SDL 3.1.3.
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index 56a6770f97a05..5cd37654ed759 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -219,6 +219,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CreateWindowAndRenderer(const char *title,
* don't need a specific renderer, specify NULL and SDL will attempt to choose
* the best option for you, based on what is available on the user's system.
*
+ * If `name` is a comma-separated list, SDL will try each name, in the order
+ * listed, until one succeeds or all of them fail.
+ *
* By default the rendering size matches the window size in pixels, but you
* can call SDL_SetRenderLogicalPresentation() to change the content size and
* scaling options.
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 9774abe169751..45f3686a31380 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -958,10 +958,8 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
#ifndef SDL_RENDER_DISABLED
SDL_Window *window = (SDL_Window *)SDL_GetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, NULL);
SDL_Surface *surface = (SDL_Surface *)SDL_GetPointerProperty(props, SDL_PROP_RENDERER_CREATE_SURFACE_POINTER, NULL);
- const char *name = SDL_GetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, NULL);
- const int n = SDL_GetNumRenderDrivers();
+ const char *driver_name = SDL_GetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, NULL);
const char *hint;
- int i, attempted = 0;
SDL_PropertiesID new_props;
#ifdef SDL_PLATFORM_ANDROID
@@ -1008,28 +1006,34 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
}
} else {
bool rc = false;
- if (!name) {
- name = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
- }
-
- if (name) {
- for (i = 0; i < n; i++) {
- const SDL_RenderDriver *driver = render_drivers[i];
- if (SDL_strcasecmp(name, driver->name) == 0) {
- // Create a new renderer instance
- ++attempted;
- rc = driver->CreateRenderer(renderer, window, props);
- break;
+ if (!driver_name) {
+ driver_name = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
+ }
+
+ if (driver_name && *driver_name != 0) {
+ const char *driver_attempt = driver_name;
+ while (driver_attempt && *driver_attempt != 0 && !rc) {
+ const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
+ const size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt) : SDL_strlen(driver_attempt);
+
+ for (int i = 0; render_drivers[i]; i++) {
+ const SDL_RenderDriver *driver = render_drivers[i];
+ if ((driver_attempt_len == SDL_strlen(driver->name)) && (SDL_strncasecmp(driver->name, driver_attempt, driver_attempt_len) == 0)) {
+ rc = driver->CreateRenderer(renderer, window, props);
+ if (rc) {
+ break;
+ }
+ }
}
+
+ driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL;
}
} else {
- for (i = 0; i < n; i++) {
+ for (int i = 0; render_drivers[i]; i++) {
const SDL_RenderDriver *driver = render_drivers[i];
- // Create a new renderer instance
- ++attempted;
rc = driver->CreateRenderer(renderer, window, props);
if (rc) {
- break; // Yay, we got one!
+ break;
}
SDL_DestroyRendererWithoutFreeing(renderer);
SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct.
@@ -1037,7 +1041,9 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
}
if (!rc) {
- if (!name || !attempted) {
+ if (driver_name) {
+ SDL_SetError("%s not available", driver_name);
+ } else {
SDL_SetError("Couldn't find matching render driver");
}
goto error;