From 866cf89b65c9be2572b644206f78636cb070dc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Oct 2026 17:22:41 +0200 Subject: [PATCH] Make the resized flag atomic On Android it's set on the Java UI thread right after writing g_display, and read on the render thread, which then copies the dp size into the UI bounds just once. With a plain bool the render thread could see the flag before the new size. Co-Authored-By: Claude Opus 5.5 --- UI/NativeApp.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 5df6223361..1341b5fb36 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -184,7 +185,9 @@ void SaveFrameDump(); ScreenManager *g_screenManager; std::string config_filename; -static bool resized = false; +// Set from any thread (on Android, the Java UI thread right after it writes g_display). Atomic, so the frame +// that consumes it also sees those writes - with a plain bool it could see the flag first and keep stale bounds. +static std::atomic resized{false}; static int renderCounter = 0; @@ -1157,10 +1160,9 @@ void NativeFrame(GraphicsContext *graphicsContext) { } // Resize before drawing anything, so the first frame at a new size isn't drawn into the old backbuffer. - const bool resizedThisFrame = resized; - if (resized) { - INFO_LOG(Log::G3D, "Resized flag set - recalculating bounds"); - resized = false; + const bool resizedThisFrame = resized.exchange(false); + if (resizedThisFrame) { + INFO_LOG(Log::G3D, "Resized flag set - recalculating bounds (%dx%d dp)", g_display.dp_xres, g_display.dp_yres); if (uiContext) { uiContext->SetBounds(Bounds(0, 0, g_display.dp_xres, g_display.dp_yres));