From 0ea5b381a3b95308852bd70e5c6a418381035bce Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 8 Jan 2026 12:38:09 -0500
Subject: [PATCH] video: Don't tear everything down in SDL_SetVideoMode
software surface changes.
This is noticable in, for example, Loki's port of Sid Meier's Alpha Centauri,
where it wants to show static Loki/Firaxis logos on an 8-bit screen surface,
then set the video mode to 16-bit for intro videos through SMPEG, then back to
an 8-bit surface for the main menu and gameplay. Before this, windows would
be destroyed and immediately pop back up: an unnecessary visual glitch, but
also it caused rendering to fail on at least one system.
Since software surfaces already go through a conversion to whatever format the
SDL2 renderer's texture wants, it was better to avoid all the damage by
letting the conversion surface absorb the format change.
Fixes #389.
---
src/SDL12_compat.c | 40 ++++++++++++++++++++++++----------------
src/SDL20_syms.h | 1 +
2 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index 44bd0f2ba..db9f4092e 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -6515,8 +6515,8 @@ SetVideoModeImpl(int width, int height, int bpp, Uint32 flags12)
if (VideoSurface12->surface20 && ((VideoSurface12->flags & SDL12_OPENGL) != (flags12 & SDL12_OPENGL))) {
EndVidModeCreate(); /* rebuild the window if moving to/from a GL context */
- } else if (VideoSurface12->surface20 && (VideoSurface12->surface20->format->format != appfmt)) {
- EndVidModeCreate(); /* rebuild the window if changing pixel format */
+ } else if ((flags12 & SDL12_OPENGL) && VideoSurface12->surface20 && (VideoSurface12->surface20->format->format != appfmt)) {
+ EndVidModeCreate(); /* rebuild the window if changing pixel format on an OpenGL surface */
} else if (DesiredRefreshRate != CurrentRefreshRate) {
EndVidModeCreate(); /* rebuild the window if changing refresh rate */
} else {
@@ -6525,7 +6525,7 @@ SetVideoModeImpl(int width, int height, int bpp, Uint32 flags12)
/* The windx5 driver _always_ destroyed the window, unconditionally, but the default (windib) did not, so match windib.
* windib: keep if:
* - window already exists
- * - BitsPerPixel hasn't changed
+ * - BitsPerPixel hasn't changed (in OpenGL mode; for software we don't care about the format change).
* - none of the window flags (except SDL_ANYFORMAT) have changed
* - window is already SDL_OPENGL.
* - window is not a fullscreen window.
@@ -6533,7 +6533,7 @@ SetVideoModeImpl(int width, int height, int bpp, Uint32 flags12)
const Uint32 important_flags = ~(SDL12_PREALLOC | SDL12_ANYFORMAT);
const SDL_bool recreate_window = (
((VideoSurface12->flags & important_flags) != (flags12 & important_flags)) ||
- (!VideoSurface12->format || (VideoSurface12->format->BitsPerPixel != bpp)) ||
+ ((flags12 & SDL12_OPENGL) && (!VideoSurface12->format || (VideoSurface12->format->BitsPerPixel != bpp))) ||
((flags12 & SDL12_FULLSCREEN) == SDL12_FULLSCREEN)
) ? SDL_TRUE : SDL_FALSE;
#elif defined(__APPLE__)
@@ -6547,12 +6547,12 @@ SetVideoModeImpl(int width, int height, int bpp, Uint32 flags12)
* - window already exists
* - window is already SDL_OPENGL.
* - new flags also want SDL_OPENGL.
- * - BitsPerPixel hasn't changed
+ * - BitsPerPixel hasn't changed (in OpenGL mode; for software we don't care about the format change).
* - SDL_NOFRAME hasn't changed
*/
const SDL_bool recreate_window = (
((VideoSurface12->flags & SDL12_OPENGL) != (flags12 & SDL12_OPENGL)) ||
- (!VideoSurface12->format || (VideoSurface12->format->BitsPerPixel != bpp)) ||
+ ((flags12 & SDL12_OPENGL) && (!VideoSurface12->format || (VideoSurface12->format->BitsPerPixel != bpp))) ||
((VideoSurface12->flags & SDL12_NOFRAME) != (flags12 & SDL12_NOFRAME))
) ? SDL_TRUE : SDL_FALSE;
#else
@@ -6804,20 +6804,28 @@ SetVideoModeImpl(int width, int height, int bpp, Uint32 flags12)
return EndVidModeCreate();
}
- if (VideoTexture20) {
- SDL20_DestroyTexture(VideoTexture20);
+ if (!VideoTexture20) {
+ SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, WantScaleMethodNearest ? "0" : "1");
+ VideoTexture20 = SDL20_CreateTexture(VideoRenderer20, rinfo.texture_formats[0], SDL_TEXTUREACCESS_STREAMING, width, height);
+ SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_scale_quality);
+ if (!VideoTexture20) {
+ return EndVidModeCreate();
+ }
}
- if (VideoConvertSurface20) {
- SDL20_FreeSurface(VideoConvertSurface20);
- VideoConvertSurface20 = NULL;
+ /* clear the texture for (re)use */
+ {
+ SDL_Surface *surface = NULL;
+ if (SDL20_LockTextureToSurface(VideoTexture20, NULL, &surface) == 0) {
+ SDL20_FillRect(surface, NULL, SDL20_MapRGB(surface->format, 0, 0, 0));
+ SDL20_UnlockTexture(VideoTexture20);
+ }
}
- SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, WantScaleMethodNearest ? "0" : "1");
- VideoTexture20 = SDL20_CreateTexture(VideoRenderer20, rinfo.texture_formats[0], SDL_TEXTUREACCESS_STREAMING, width, height);
- SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_scale_quality);
- if (!VideoTexture20) {
- return EndVidModeCreate();
+ /* don't need conversion, or need to change the conversion surface's format? Nuke the existing surface (and maybe rebuild it later). */
+ if (VideoConvertSurface20 && ((rinfo.texture_formats[0] == appfmt) || (rinfo.texture_formats[0] != VideoConvertSurface20->format->format))) {
+ SDL20_FreeSurface(VideoConvertSurface20);
+ VideoConvertSurface20 = NULL;
}
if (rinfo.texture_formats[0] != appfmt) {
diff --git a/src/SDL20_syms.h b/src/SDL20_syms.h
index 23b8bcc52..f0ac1e91d 100644
--- a/src/SDL20_syms.h
+++ b/src/SDL20_syms.h
@@ -325,6 +325,7 @@ SDL20_SYM(void,RenderGetScale,(SDL_Renderer *a, float *b, float *c),(a,b,c),retu
SDL20_SYM(void,RenderGetViewport,(SDL_Renderer *a, SDL_Rect *b),(a,b),return)
SDL20_SYM(SDL_Texture *,CreateTexture,(SDL_Renderer *a, Uint32 b, int c, int d, int e),(a,b,c,d,e),return)
SDL20_SYM(int,LockTexture,(SDL_Texture *a, const SDL_Rect *b, void **c, int *d),(a,b,c,d),return)
+SDL20_SYM(int,LockTextureToSurface,(SDL_Texture *a, const SDL_Rect *b, SDL_Surface **c),(a,b,c),return)
SDL20_SYM(void,UnlockTexture,(SDL_Texture *a),(a),)
SDL20_SYM(int,UpdateTexture,(SDL_Texture *a, const SDL_Rect *b, const void *c, int d),(a,b,c,d),return)
SDL20_SYM(int,UpdateYUVTexture,(SDL_Texture *a, const SDL_Rect *b, const Uint8 *c, int d, const Uint8 *e, int f, const Uint8 *g, int h),(a,b,c,d,e,f,g,h),return)