SDL: video: Don't check if we can use a "texture framebuffer" until needed.

From f37e4a94d3acaa5c1872386d5a682292d48faf93 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 26 Jan 2022 17:02:49 -0500
Subject: [PATCH] video: Don't check if we can use a "texture framebuffer"
 until needed.

This prevents SDL from making an OpenGL context and maybe throwing it away
immediately by default. It will now only do it when trying to request a
window framebuffer directly, or creating an SDL_Renderer with the "software"
backend, which makes that request itself.

The way SDL decides if it should use a "texture framebuffer" needs dramatic
updating, but this solves the immediate problem.

Reference Issue #4624.
---
 src/video/SDL_sysvideo.h |  1 +
 src/video/SDL_video.c    | 46 ++++++++++++++++++++++++++++++----------
 2 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 3f401a5b2ef..470c14ba352 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -330,6 +330,7 @@ struct SDL_VideoDevice
 
     /* * * */
     /* Data common to all drivers */
+    SDL_bool checked_texture_framebuffer;
     SDL_bool is_dummy;
     SDL_bool suspend_screensaver;
     SDL_Window *wakeup_window;
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index d3fe655029e..b0a7058d76e 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -414,6 +414,27 @@ SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window)
 }
 
 
+/* This will switch the video backend from using a software surface to
+   using a GPU texture through the 2D render API, if we think this would
+   be more efficient. This only checks once, on demand. */
+static void
+PrepareWindowFramebuffer()
+{
+    /* Add the renderer framebuffer emulation if desired */
+    if (_this->checked_texture_framebuffer) {
+        return;
+    }
+
+    _this->checked_texture_framebuffer = SDL_TRUE;
+
+    if (ShouldUseTextureFramebuffer()) {
+        _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
+        _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
+        _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
+    }
+}
+
+
 static int
 cmpmodes(const void *A, const void *B)
 {
@@ -564,13 +585,6 @@ SDL_VideoInit(const char *driver_name)
         return SDL_SetError("The video driver did not add any displays");
     }
 
-    /* Add the renderer framebuffer emulation if desired */
-    if (ShouldUseTextureFramebuffer()) {
-        _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
-        _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
-        _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
-    }
-
     /* Disable the screen saver by default. This is a change from <= 2.0.1,
        but most things using SDL are games or media players; you wouldn't
        want a screensaver to trigger if you're playing exclusively with a
@@ -1827,9 +1841,13 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
         window->surface = NULL;
         window->surface_valid = SDL_FALSE;
     }
-    if (_this->DestroyWindowFramebuffer) {
-        _this->DestroyWindowFramebuffer(_this, window);
+
+    if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */
+        if (_this->DestroyWindowFramebuffer) {
+            _this->DestroyWindowFramebuffer(_this, window);
+        }
     }
+
     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
         _this->DestroyWindow(_this, window);
     }
@@ -2547,6 +2565,8 @@ SDL_CreateWindowFramebuffer(SDL_Window * window)
     int bpp;
     Uint32 Rmask, Gmask, Bmask, Amask;
 
+    PrepareWindowFramebuffer();
+
     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
         return NULL;
     }
@@ -2610,6 +2630,8 @@ SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
     }
 
+    SDL_assert(_this->checked_texture_framebuffer); /* we should have done this before we had a valid surface. */
+
     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
 }
 
@@ -3138,8 +3160,10 @@ SDL_DestroyWindow(SDL_Window * window)
         window->surface = NULL;
         window->surface_valid = SDL_FALSE;
     }
-    if (_this->DestroyWindowFramebuffer) {
-        _this->DestroyWindowFramebuffer(_this, window);
+    if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */
+        if (_this->DestroyWindowFramebuffer) {
+            _this->DestroyWindowFramebuffer(_this, window);
+        }
     }
     if (_this->DestroyWindow) {
         _this->DestroyWindow(_this, window);