From 6810c5fa8ce063c97f050f56943940329baad1e7 Mon Sep 17 00:00:00 2001 From: NyakoFox Date: Mon, 28 Apr 2025 01:03:17 -0300 Subject: [PATCH] Fix #1223 (analogue mode segfault) When `SDL_RenderReadPixels` fails for some reason, the game tries to free the temporary source surface it creates. Unfortunately, it never sets it to `NULL` after, so the next time the game tries to render the filter, it'll try to work with a memory region that was already freed. To fix this, I just replaced `SDL_FreeSurface(*src);` with `VVV_freefunc(SDL_FreeSurface, *src);` which is a helper macro which sets the pointer to NULL after freeing. Now, there's a new issue -- since the temporary buffer is now NULL, next frame we'll try to remake it! So I've introduced a static bool which disables the filter entirely if `SDL_RenderReadPixels` fails. Without this, it'd create and destroy a surface every frame, which could lead to slowdown. (Not as slow as the filter when it DOES work, but still...) I also added a line which frees the second temporary surface... it's weird that was missing in the first place, but I think reimplementing analogue mode was one of the last things I did for the renderer rewrite anyways. Resolves #1223. --- desktop_version/src/GraphicsUtil.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/desktop_version/src/GraphicsUtil.cpp b/desktop_version/src/GraphicsUtil.cpp index 55e89b1a..33ffb256 100644 --- a/desktop_version/src/GraphicsUtil.cpp +++ b/desktop_version/src/GraphicsUtil.cpp @@ -189,8 +189,15 @@ void UpdateFilter(void) } } +static bool disabled_filter = false; + void ApplyFilter(SDL_Surface** src, SDL_Surface** dest) { + if (disabled_filter) + { + return; + } + if (src == NULL || dest == NULL) { SDL_assert(0 && "NULL src or dest!"); @@ -214,7 +221,9 @@ void ApplyFilter(SDL_Surface** src, SDL_Surface** dest) const int result = SDL_RenderReadPixels(gameScreen.m_renderer, NULL, 0, (*src)->pixels, (*src)->pitch); if (result != 0) { - SDL_FreeSurface(*src); + disabled_filter = true; + VVV_freefunc(SDL_FreeSurface, *src); + VVV_freefunc(SDL_FreeSurface, *dest); WHINE_ONCE_ARGS(("Could not read pixels from renderer: %s", SDL_GetError())); return; }