SDL: render: Manage memory for SDL_Renderer* at higher level.

From 39c8434f5fd099397df7c6269d30b6f807b2456a Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 18 Apr 2024 10:16:50 -0400
Subject: [PATCH] render: Manage memory for SDL_Renderer* at higher level.

Previously, each backend would allocate and free the renderer struct. Now
the higher level does it, so the backends only manage their private resources.

This removes some boilerplate and avoids some potential accidents.
---
 src/render/SDL_render.c                  | 39 +++++++++++++++---------
 src/render/SDL_sysrender.h               |  2 +-
 src/render/direct3d/SDL_render_d3d.c     | 32 +++++--------------
 src/render/direct3d11/SDL_render_d3d11.c | 23 ++++----------
 src/render/direct3d12/SDL_render_d3d12.c | 26 +++++-----------
 src/render/metal/SDL_render_metal.m      | 29 +++++-------------
 src/render/opengl/SDL_render_gl.c        | 26 +++-------------
 src/render/opengles2/SDL_render_gles2.c  | 28 +++--------------
 src/render/ps2/SDL_render_ps2.c          | 19 +++---------
 src/render/psp/SDL_render_psp.c          | 19 +++---------
 src/render/software/SDL_render_sw.c      | 39 +++++++-----------------
 src/render/software/SDL_render_sw_c.h    |  2 +-
 src/render/vitagxm/SDL_render_vita_gxm.c | 24 ++++-----------
 src/render/vulkan/SDL_render_vulkan.c    | 33 +++++++-------------
 14 files changed, 100 insertions(+), 241 deletions(-)

diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 8ffe304b401b2..2131da194cd74 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -900,12 +900,18 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
     SDL_Window *window = (SDL_Window *)SDL_GetProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, NULL);
     SDL_Surface *surface = (SDL_Surface *)SDL_GetProperty(props, SDL_PROP_RENDERER_CREATE_SURFACE_POINTER, NULL);
     const char *name = SDL_GetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, NULL);
-    SDL_Renderer *renderer = NULL;
     const int n = SDL_GetNumRenderDrivers();
     const char *hint;
     int i, attempted = 0;
     SDL_PropertiesID new_props;
 
+    SDL_Renderer *renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
+    if (!renderer) {
+        return NULL;
+    }
+
+    renderer->magic = &SDL_renderer_magic;
+
 #ifdef SDL_PLATFORM_ANDROID
     Android_ActivityMutex_Lock_Running();
 #endif
@@ -932,15 +938,15 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
 
     if (surface) {
 #if SDL_VIDEO_RENDER_SW
-        renderer = SW_CreateRendererForSurface(surface, props);
+        const int rc = SW_CreateRendererForSurface(renderer, surface, props);
 #else
-        renderer = NULL;
-        SDL_SetError("SDL not built with software renderer");
+        const int rc = SDL_SetError("SDL not built with software renderer");
 #endif
-        if (!renderer) {
+        if (rc == -1) {
             goto error;
         }
     } else {
+        int rc = -1;
         if (!name) {
             name = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
         }
@@ -949,26 +955,27 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
             for (i = 0; i < n; i++) {
                 const SDL_RenderDriver *driver = render_drivers[i];
                 if (SDL_strcasecmp(name, driver->info.name) == 0) {
-                    /* Create a new renderer instance */
+                    // Create a new renderer instance
                     ++attempted;
-                    renderer = driver->CreateRenderer(window, props);
+                    rc = driver->CreateRenderer(renderer, window, props);
                     break;
                 }
             }
         } else {
             for (i = 0; i < n; i++) {
                 const SDL_RenderDriver *driver = render_drivers[i];
-                /* Create a new renderer instance */
+                // Create a new renderer instance
                 ++attempted;
-                renderer = driver->CreateRenderer(window, props);
-                if (renderer) {
-                    /* Yay, we got one! */
-                    break;
+                rc = driver->CreateRenderer(renderer, window, props);
+                if (rc == 0) {
+                    break;  // Yay, we got one!
                 }
+                SDL_zerop(renderer);  // make sure we don't leave function pointers from a previous CreateRenderer() in this struct.
+                renderer->magic = &SDL_renderer_magic;
             }
         }
 
-        if (!renderer) {
+        if (rc == -1) {
             if (!name || !attempted) {
                 SDL_SetError("Couldn't find matching render driver");
             }
@@ -1072,6 +1079,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
 #ifdef SDL_PLATFORM_ANDROID
     Android_ActivityMutex_Unlock();
 #endif
+    SDL_free(renderer);
     return NULL;
 
 #else
@@ -4522,7 +4530,6 @@ void SDL_DestroyRenderer(SDL_Renderer *renderer)
     /* Free existing textures for this renderer */
     while (renderer->textures) {
         SDL_Texture *tex = renderer->textures;
-        (void)tex;
         SDL_DestroyTextureInternal(renderer->textures, SDL_TRUE /* is_destroying */);
         SDL_assert(tex != renderer->textures); /* satisfy static analysis. */
     }
@@ -4540,8 +4547,10 @@ void SDL_DestroyRenderer(SDL_Renderer *renderer)
     SDL_DestroyMutex(renderer->target_mutex);
     renderer->target_mutex = NULL;
 
-    /* Free the renderer instance */
+    /* Clean up renderer-specific resources */
     renderer->DestroyRenderer(renderer);
+
+    SDL_free(renderer);
 }
 
 void *SDL_GetRenderMetalLayer(SDL_Renderer *renderer)
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index 6ff18020f0e16..3ab7a269acefa 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -295,7 +295,7 @@ struct SDL_Renderer
 /* Define the SDL render driver structure */
 struct SDL_RenderDriver
 {
-    SDL_Renderer *(*CreateRenderer)(SDL_Window *window, SDL_PropertiesID props);
+    int (*CreateRenderer)(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID props);
 
     /* Info about the renderer capabilities */
     SDL_RendererInfo info;
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index 9384bd6d064f1..51d4c4bad9703 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -1469,7 +1469,6 @@ static void D3D_DestroyRenderer(SDL_Renderer *renderer)
         }
         SDL_free(data);
     }
-    SDL_free(renderer);
 }
 
 static int D3D_Reset(SDL_Renderer *renderer)
@@ -1567,9 +1566,8 @@ static int D3D_SetVSync(SDL_Renderer *renderer, const int vsync)
     return 0;
 }
 
-SDL_Renderer *D3D_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+int D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
     D3D_RenderData *data;
     HRESULT result;
     D3DPRESENT_PARAMETERS pparams;
@@ -1580,31 +1578,20 @@ SDL_Renderer *D3D_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_pro
     SDL_DisplayID displayID;
     const SDL_DisplayMode *fullscreen_mode = NULL;
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        return NULL;
-    }
-    renderer->magic = &SDL_renderer_magic;
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
-        SDL_SetError("Unsupported output colorspace");
-        SDL_free(renderer);
-        return NULL;
+        return SDL_SetError("Unsupported output colorspace");
     }
 
     data = (D3D_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
-        SDL_free(renderer);
-        return NULL;
+        return -1;
     }
 
     if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
-        SDL_SetError("Unable to create Direct3D interface");
-        SDL_free(renderer);
         SDL_free(data);
-        return NULL;
+        return SDL_SetError("Unable to create Direct3D interface");
     }
 
     renderer->WindowEvent = D3D_WindowEvent;
@@ -1685,23 +1672,20 @@ SDL_Renderer *D3D_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_pro
                                      &pparams, &data->device);
     if (FAILED(result)) {
         D3D_DestroyRenderer(renderer);
-        D3D_SetError("CreateDevice()", result);
-        return NULL;
+        return D3D_SetError("CreateDevice()", result);
     }
 
     /* Get presentation parameters to fill info */
     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
     if (FAILED(result)) {
         D3D_DestroyRenderer(renderer);
-        D3D_SetError("GetSwapChain()", result);
-        return NULL;
+        return D3D_SetError("GetSwapChain()", result);
     }
     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
     if (FAILED(result)) {
         IDirect3DSwapChain9_Release(chain);
         D3D_DestroyRenderer(renderer);
-        D3D_SetError("GetPresentParameters()", result);
-        return NULL;
+        return D3D_SetError("GetPresentParameters()", result);
     }
     IDirect3DSwapChain9_Release(chain);
     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
@@ -1741,7 +1725,7 @@ SDL_Renderer *D3D_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_pro
 
     SDL_SetProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_D3D9_DEVICE_POINTER, data->device);
 
-    return renderer;
+    return 0;
 }
 
 SDL_RenderDriver D3D_RenderDriver = {
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index 8498d37418578..14e4ac334c55f 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -413,7 +413,6 @@ static void D3D11_DestroyRenderer(SDL_Renderer *renderer)
     if (data) {
         SDL_free(data);
     }
-    SDL_free(renderer);
 }
 
 static D3D11_BLEND GetBlendFunc(SDL_BlendFactor factor)
@@ -2741,31 +2740,21 @@ static int D3D11_SetVSync(SDL_Renderer *renderer, const int vsync)
 }
 #endif
 
-SDL_Renderer *D3D11_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
     D3D11_RenderData *data;
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        return NULL;
-    }
-    renderer->magic = &SDL_renderer_magic;
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB &&
         renderer->output_colorspace != SDL_COLORSPACE_SRGB_LINEAR
         /*&& renderer->output_colorspace != SDL_COLORSPACE_HDR10*/) {
-        SDL_SetError("Unsupported output colorspace");
-        SDL_free(renderer);
-        return NULL;
+        return SDL_SetError("Unsupported output colorspace");
     }
 
     data = (D3D11_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
-        SDL_free(renderer);
-        return NULL;
+        return -1;
     }
 
     data->identity = MatrixIdentity();
@@ -2825,14 +2814,14 @@ SDL_Renderer *D3D11_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_p
     /* Initialize Direct3D resources */
     if (FAILED(D3D11_CreateDeviceResources(renderer))) {
         D3D11_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
     if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
         D3D11_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
 
-    return renderer;
+    return 0;
 }
 
 SDL_RenderDriver D3D11_RenderDriver = {
diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c
index 74d08a45b7fac..f74c686575fbf 100644
--- a/src/render/direct3d12/SDL_render_d3d12.c
+++ b/src/render/direct3d12/SDL_render_d3d12.c
@@ -587,7 +587,6 @@ static void D3D12_DestroyRenderer(SDL_Renderer *renderer)
     if (data) {
         SDL_free(data);
     }
-    SDL_free(renderer);
 }
 
 static D3D12_BLEND GetBlendFunc(SDL_BlendFactor factor)
@@ -3173,37 +3172,26 @@ static int D3D12_SetVSync(SDL_Renderer *renderer, const int vsync)
     return 0;
 }
 
-SDL_Renderer *D3D12_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+int D3D12_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
     D3D12_RenderData *data;
 
     if (SDL_GetWindowFlags(window) & SDL_WINDOW_TRANSPARENT) {
 		/* D3D12 removed the swap effect needed to support transparent windows, use D3D11 instead */
-		SDL_SetError("The direct3d12 renderer doesn't work with transparent windows");
-		return NULL;
+		return SDL_SetError("The direct3d12 renderer doesn't work with transparent windows");
 	}
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        return NULL;
-    }
-    renderer->magic = &SDL_renderer_magic;
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB &&
         renderer->output_colorspace != SDL_COLORSPACE_SRGB_LINEAR
         /*&& renderer->output_colorspace != SDL_COLORSPACE_HDR10*/) {
-        SDL_SetError("Unsupported output colorspace");
-        SDL_free(renderer);
-        return NULL;
+        return SDL_SetError("Unsupported output colorspace");
     }
 
     data = (D3D12_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
-        SDL_free(renderer);
-        return NULL;
+        return -1;
     }
 
     data->identity = MatrixIdentity();
@@ -3248,14 +3236,14 @@ SDL_Renderer *D3D12_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_p
     /* Initialize Direct3D resources */
     if (FAILED(D3D12_CreateDeviceResources(renderer))) {
         D3D12_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
     if (FAILED(D3D12_CreateWindowSizeDependentResources(renderer))) {
         D3D12_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
 
-    return renderer;
+    return 0;
 }
 
 SDL_RenderDriver D3D12_RenderDriver = {
diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 51b1c959194f8..81d1edb60dcea 100644
--- a/src/render/metal/SDL_render_metal.m
+++ b/src/render/metal/SDL_render_metal.m
@@ -1800,8 +1800,6 @@ in case we want to use it later (recreating the renderer)
             /* SDL_Metal_DestroyView(data.mtlview); */
             CFBridgingRelease(data.mtlview);
         }
-
-        SDL_free(renderer);
     }
 }
 
@@ -1874,10 +1872,9 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
     return nil;
 }
 
-static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
     @autoreleasepool {
-        SDL_Renderer *renderer = NULL;
         METAL_RenderData *data = NULL;
         id<MTLDevice> mtldevice = nil;
         SDL_MetalView view = NULL;
@@ -1939,14 +1936,8 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
         const size_t YCbCr_shader_matrix_size = 4 * 4 * sizeof(float);
 
         if (!IsMetalAvailable()) {
-            return NULL;
-        }
-
-        renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-        if (!renderer) {
-            return NULL;
+            return -1;
         }
-        renderer->magic = &SDL_renderer_magic;
 
         SDL_SetupRendererColorspace(renderer, create_props);
 
@@ -1959,9 +1950,7 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
             if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR && scRGB_supported) {
                 /* This colorspace is supported */
             } else {
-                SDL_SetError("Unsupported output colorspace");
-                SDL_free(renderer);
-                return NULL;
+                return SDL_SetError("Unsupported output colorspace");
             }
         }
 
@@ -1983,9 +1972,7 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
         }
 
         if (mtldevice == nil) {
-            SDL_free(renderer);
-            SDL_SetError("Failed to obtain Metal device");
-            return NULL;
+            return SDL_SetError("Failed to obtain Metal device");
         }
 
         view = GetWindowView(window);
@@ -1994,8 +1981,7 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
         }
 
         if (view == NULL) {
-            SDL_free(renderer);
-            return NULL;
+            return -1;
         }
 
         // !!! FIXME: error checking on all of this.
@@ -2007,8 +1993,7 @@ in case we want to use it later (recreating the renderer)
              */
             /* SDL_Metal_DestroyView(view); */
             CFBridgingRelease(view);
-            SDL_free(renderer);
-            return NULL;
+            return SDL_SetError("METAL_RenderData alloc/init failed");
         }
 
         renderer->driverdata = (void *)CFBridgingRetain(data);
@@ -2205,7 +2190,7 @@ in case we want to use it later (recreating the renderer)
         renderer->info.max_texture_width = maxtexsize;
         renderer->info.max_texture_height = maxtexsize;
 
-        return renderer;
+        return 0;
     }
 }
 
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index 1b16c51885064..82cd82cbd375e 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -1583,7 +1583,6 @@ static void GL_DestroyRenderer(SDL_Renderer *renderer)
         }
         SDL_free(data);
     }
-    SDL_free(renderer);
 }
 
 static int GL_SetVSync(SDL_Renderer *renderer, const int vsync)
@@ -1612,10 +1611,9 @@ static int GL_SetVSync(SDL_Renderer *renderer, const int vsync)
     return retval;
 }
 
-static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int GL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
-    GL_RenderData *data;
+    GL_RenderData *data = NULL;
     GLint value;
     SDL_WindowFlags window_flags;
     int profile_mask = 0, major = 0, minor = 0;
@@ -1644,22 +1642,15 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
     }
 #endif
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        goto error;
-    }
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
         SDL_SetError("Unsupported output colorspace");
-        SDL_free(renderer);
         goto error;
     }
 
     data = (GL_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
-        SDL_free(renderer);
         goto error;
     }
 
@@ -1695,21 +1686,15 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
 
     data->context = SDL_GL_CreateContext(window);
     if (!data->context) {
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
         SDL_GL_DeleteContext(data->context);
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
 
     if (GL_LoadFunctions(data) < 0) {
         SDL_GL_DeleteContext(data->context);
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
 
@@ -1844,8 +1829,6 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
     } else {
         SDL_SetError("Can't create render targets, GL_EXT_framebuffer_object not available");
         SDL_GL_DeleteContext(data->context);
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
 
@@ -1870,9 +1853,10 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
     data->drawstate.clear_color.b = 1.0f;
     data->drawstate.clear_color.a = 1.0f;
 
-    return renderer;
+    return 0;
 
 error:
+    SDL_free(data);
     if (changed_window) {
         /* Uh oh, better try to put it back... */
         char *error = SDL_strdup(SDL_GetError());
@@ -1883,7 +1867,7 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
         SDL_SetError("%s", error);
         SDL_free(error);
     }
-    return NULL;
+    return -1;
 }
 
 SDL_RenderDriver GL_RenderDriver = {
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index 2c0aa42ec677e..294317237f749 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -1445,7 +1445,6 @@ static void GLES2_DestroyRenderer(SDL_Renderer *renderer)
 
         SDL_free(data);
     }
-    SDL_free(renderer);
 }
 
 static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
@@ -2041,10 +2040,9 @@ static int GLES2_SetVSync(SDL_Renderer *renderer, const int vsync)
  * Renderer instantiation                                                                        *
  *************************************************************************************************/
 
-static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
-    GLES2_RenderData *data;
+    GLES2_RenderData *data = NULL;
     SDL_WindowFlags window_flags = 0; /* -Wconditional-uninitialized */
     GLint window_framebuffer;
     GLint value;
@@ -2078,24 +2076,15 @@ static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
         }
     }
 
-    /* Create the renderer struct */
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
-    if (!renderer) {
-        goto error;
-    }
-    renderer->magic = &SDL_renderer_magic;
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
         SDL_SetError("Unsupported output colorspace");
-        SDL_free(renderer);
         goto error;
     }
 
     data = (GLES2_RenderData *)SDL_calloc(1, sizeof(GLES2_RenderData));
     if (!data) {
-        SDL_free(renderer);
         goto error;
     }
     renderer->info = GLES2_RenderDriver.info;
@@ -2106,28 +2095,20 @@ static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
     /* Create an OpenGL ES 2.0 context */
     data->context = SDL_GL_CreateContext(window);
     if (!data->context) {
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
         SDL_GL_DeleteContext(data->context);
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
 
     if (GLES2_LoadFunctions(data) < 0) {
         SDL_GL_DeleteContext(data->context);
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
 
     if (GLES2_CacheShaders(data) < 0) {
         SDL_GL_DeleteContext(data->context);
-        SDL_free(renderer);
-        SDL_free(data);
         goto error;
     }
 
@@ -2244,9 +2225,10 @@ static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
 
     GL_CheckError("", renderer);
 
-    return renderer;
+    return 0;
 
 error:
+    SDL_free(data);
     if (changed_window) {
         /* Uh oh, better try to put it back... */
         char *error = SDL_strdup(SDL_GetError());
@@ -2257,7 +2239,7 @@ static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
         SDL_SetError("%s", error);
         SDL_free(error);
     }
-    return NULL;
+    return -1;
 }
 
 SDL_RenderDriver GLES2_RenderDriver = {
diff --git a/src/render/ps2/SDL_render_ps2.c b/src/render/ps2/SDL_render_ps2.c
index 32267fc27bd22..978190efdad50 100644
--- a/src/render/ps2/SDL_render_ps2.c
+++ b/src/render/ps2/SDL_render_ps2.c
@@ -602,8 +602,6 @@ static void PS2_DestroyRenderer(SDL_Renderer *renderer)
     if (vsync_sema_id >= 0) {
         DeleteSema(vsync_sema_id);
     }
-
-    SDL_free(renderer);
 }
 
 static int PS2_SetVSync(SDL_Renderer *renderer, const int vsync)
@@ -614,32 +612,23 @@ static int PS2_SetVSync(SDL_Renderer *renderer, const int vsync)
     return 0;
 }
 
-static SDL_Renderer *PS2_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int PS2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
     PS2_RenderData *data;
     GSGLOBAL *gsGlobal;
     ee_sema_t sema;
     SDL_bool dynamicVsync;
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        return NULL;
-    }
-    renderer->magic = &SDL_renderer_magic;
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
-        SDL_SetError("Unsupported output colorspace");
         SDL_free(renderer);
-        return NULL;
+        return SDL_SetError("Unsupported output colorspace");
     }
 
     data = (PS2_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
-        PS2_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
 
     /* Specific gsKit init */
@@ -711,7 +700,7 @@ static SDL_Renderer *PS2_CreateRenderer(SDL_Window *window, SDL_PropertiesID cre
     if (data->vsync) {
         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
     }
-    return renderer;
+    return 0;
 }
 
 SDL_RenderDriver PS2_RenderDriver = {
diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c
index 8ca0f1583023f..600a9815857b6 100644
--- a/src/render/psp/SDL_render_psp.c
+++ b/src/render/psp/SDL_render_psp.c
@@ -1277,7 +1277,6 @@ static void PSP_DestroyRenderer(SDL_Renderer *renderer)
         data->displayListAvail = SDL_FALSE;
         SDL_free(data);
     }
-    SDL_free(renderer);
 }
 
 static int PSP_SetVSync(SDL_Renderer *renderer, const int vsync)
@@ -1287,31 +1286,21 @@ static int PSP_SetVSync(SDL_Renderer *renderer, const int vsync)
     return 0;
 }
 
-SDL_Renderer *PSP_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
     PSP_RenderData *data;
     int pixelformat;
     void *doublebuffer = NULL;
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        return NULL;
-    }
-    renderer->magic = &SDL_renderer_magic;
-
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
-        SDL_SetError("Unsupported output colorspace");
-        SDL_free(renderer);
-        return NULL;
+        return SDL_SetError("Unsupported output colorspace");
     }
 
     data = (PSP_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
-        PSP_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
 
     renderer->WindowEvent = PSP_WindowEvent;
@@ -1406,7 +1395,7 @@ SDL_Renderer *PSP_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_pro
     if (data->vsync) {
         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
     }
-    return renderer;
+    return 0;
 }
 
 SDL_RenderDriver PSP_RenderDriver = {
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 6c6fef3311d29..552a76109d35d 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -1018,7 +1018,6 @@ static void SW_DestroyRenderer(SDL_Renderer *renderer)
         SDL_DestroyWindowSurface(window);
     }
     SDL_free(data);
-    SDL_free(renderer);
 }
 
 static void SW_SelectBestFormats(SDL_Renderer *renderer, SDL_PixelFormatEnum format)
@@ -1116,27 +1115,20 @@ static void SW_SelectBestFormats(SDL_Renderer *renderer, SDL_PixelFormatEnum for
     }
 }
 
-SDL_Renderer *SW_CreateRendererForSurface(SDL_Surface *surface, SDL_PropertiesID create_props)
+int SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props)
 {
-    SDL_Renderer *renderer;
     SW_RenderData *data;
 
     if (!surface) {
-        SDL_InvalidParamError("surface");
-        return NULL;
+        return SDL_InvalidParamError("surface");
     }
 
-    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        return NULL;
-    }
-    renderer->magic = &SDL_renderer_magic;
     renderer->software = SDL_TRUE;
 
     data = (SW_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
         SW_DestroyRenderer(renderer);
-        return NULL;
+        return -1;
     }
     data->surface = surface;
     data->window = surface;
@@ -1172,27 +1164,18 @@ SDL_Renderer *SW_CreateRendererForSurface(SDL_Surface *surface, SDL_PropertiesID
     SDL_SetupRendererColorspace(renderer, create_props);
 
     if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
-        SDL_SetError("Unsupported output colorspace");
         SW_DestroyRenderer(renderer);
-        return NULL;
+        return SDL_SetError("Unsupported output colorspace");
     }
 
-    return renderer;
+    return 0;
 }
 
-static SDL_Renderer *SW_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props)
+static int SW_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
 {
-    const char *hint;
-    SDL_Surface *surface;
-    SDL_bool no_hint_set;
-
     /* Set the vsync hint based on our flags, if it's not already set */
-    hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
-    if (!hint || !*hint) {
-        no_hint_set = SDL_TRUE;
-    } else {
-        no_hint_set = SDL_FALSE;
-    }
+    const char *hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
+    const SDL_bool no_hint_set = (!hint || !*hint);
 
     if (no_hint_set) {
         if (SDL_GetBooleanProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_BOOLEAN, SDL_FALSE)) {
@@ -1202,7 +1185,7 @@ static SDL_Renderer *SW_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
         }
     }
 
-    surface = SDL_GetWindowSurface(window);
+    SDL_Surface *surface = SDL_GetWindowSurface(window);
 
     /* Reset the vsync hint if we set it above */
     if (no_hint_set) {
@@ -1210,10 +1193,10 @@ static SDL_Renderer *SW_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea
     }
 
     if (!surface) {
-        return NULL;
+        return -1;
     }
 
-    return SW_CreateRendererForSurface(surface, create_props);
+    return SW_CreateRendererForSurface(renderer, surface, create_props);
 }
 
 SDL_RenderDriver SW_RenderDriver = {
diff --git a/src/render/software/SDL_render_sw_c.h b/src/render/software/SDL_render_sw_c.h
index 40966d181adbf..27eb84ded4678 100644
--- a/src/render/software/SDL_render_sw_c.h
+++ b/src/render/software/SDL_render_sw_c.h
@@ -22,6 +22,6 @@
 #ifndef SDL_render_sw_c_h_
 #define SDL_render_sw_c_h_
 
-extern SDL_Renderer *SW_CreateRendererForSurface(SDL_Surface *surface, SDL_PropertiesID create_props);
+extern int SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props);
 
 #endif /* SDL_render_sw_c_h_ */
diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c
index dfd4d3ac16083..52cc8eb26e298 100644
--- a/src/render/vitagxm/SDL_render_vita_gxm.c
+++ b/src/render/vitagxm/SDL_render_vita_gx

(Patch may be truncated, please check the link at the top of this post.)