Compare commits

...
Author SHA1 Message Date
jirik2077 49868b68b0 poc fix for sdl main window race condition 2026-07-02 19:55:29 +02:00
4 changed files with 95 additions and 10 deletions
+14
View File
@@ -171,6 +171,12 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
windowInit(1, flags);
paletteInit();
// Map the window now that the render surface exists, so the splash screen
// and the rest of startup are visible. Throttled pumpStartupEvents() calls
// below keep the window manager from iconifying it during the long init
// under slow tracing parents like Valgrind.
screenShowWindow();
// SFALL: Execute all code that should be executed ON game init
sfallOnGameInit();
@@ -231,6 +237,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">gsound_init\t");
pumpStartupEvents();
movieInit();
debugPrint(">initMovie\t\t");
@@ -241,6 +248,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">gmovie_init\t");
pumpStartupEvents();
if (movieEffectsInit() != 0) {
debugPrint("Failed on moviefx_init\n");
@@ -255,6 +263,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">iso_init\t");
pumpStartupEvents();
if (gameMouseInit() != 0) {
debugPrint("Failed on gmouse_init\n");
@@ -269,6 +278,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">proto_init\t");
pumpStartupEvents();
animationInit();
debugPrint(">anim_init\t");
@@ -279,6 +289,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">scr_init\t");
pumpStartupEvents();
if (gameLoadGlobalVars() != 0) {
debugPrint("Failed on game_load_info\n");
@@ -300,6 +311,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">wmWorldMap_init\t");
pumpStartupEvents();
characterEditorInit();
debugPrint(">CharEditInit\t");
@@ -317,6 +329,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">gdialog_init\t");
pumpStartupEvents();
if (combatInit() != 0) {
debugPrint("Failed on combat_init\n");
@@ -331,6 +344,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
}
debugPrint(">automap_init\t");
pumpStartupEvents();
if (!messageListInit(&gMiscMessageList)) {
debugPrint("Failed on message_init\n");
+8
View File
@@ -1039,6 +1039,14 @@ void _GNW95_process_message()
case SDL_WINDOWEVENT_SIZE_CHANGED:
handleWindowSizeChanged();
break;
case SDL_WINDOWEVENT_RESTORED:
// Make sure the window is brought back to the foreground when
// it is un-minimized; some window managers leave it behind.
SDL_RaiseWindow(gSdlWindow);
gProgramIsActive = true;
windowRefreshAll(&_scr_size);
audioEngineResume();
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
gProgramIsActive = true;
windowRefreshAll(&_scr_size);
+71 -10
View File
@@ -24,6 +24,10 @@ namespace fallout {
static bool createRenderer(int width, int height);
static void destroyRenderer();
static void pumpPendingEvents();
static constexpr int kMaxStartupEventPumpPasses = 10;
static constexpr Uint32 kStartupEventPumpIntervalMs = 250;
// screen rect
Rect _scr_size;
@@ -127,15 +131,6 @@ int _GNW95_init_mode_ex(int width, int height, int bpp)
return -1;
}
// macOS seems to require dequeuing NSApp events in order for window to
// become visible. There is no concrete number of calls required to make
// it happen. Sadly there is no particular event to watch for because SDL
// marks window as shown immediately after creation (see
// `SDL_FinishWindowCreation`).
for (int i = 0; i < 10; i++) {
SDL_PumpEvents();
}
_scr_size.left = 0;
_scr_size.top = 0;
_scr_size.right = width - 1;
@@ -161,7 +156,7 @@ int _GNW95_init_window(int width, int height, bool fullscreen, int scale)
if (gSdlWindow == nullptr) {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI;
Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN;
if (fullscreen) {
windowFlags |= SDL_WINDOW_FULLSCREEN;
@@ -348,6 +343,72 @@ bool screenIsFullscreen()
return (flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0;
}
void screenShowWindow()
{
if (gSdlWindow == nullptr) {
return;
}
// The window is created hidden and mapped here, once a render surface
// exists, so the splash screen and the rest of startup are visible. The
// remaining long init keeps the window manager happy via periodic
// pumpStartupEvents() calls; otherwise a slow init (e.g. under tracing
// parents like Valgrind) could let some WMs iconify the window before the
// main loop runs.
SDL_ShowWindow(gSdlWindow);
SDL_RaiseWindow(gSdlWindow);
pumpPendingEvents();
}
void pumpStartupEvents()
{
if (gSdlWindow == nullptr) {
return;
}
// Throttled so it can be called liberally between subsystem inits without
// overhead. Servicing the event queue periodically keeps the window
// manager from treating the (now visible) window as unresponsive during the
// long startup sequence. most easily triggered under tracing parents like
// Valgrind that slow startup dramatically.
static Uint32 lastPump = 0;
Uint32 now = SDL_GetTicks();
if (now - lastPump < kStartupEventPumpIntervalMs) {
return;
}
lastPump = now;
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
exit(EXIT_SUCCESS);
}
}
}
static void pumpPendingEvents()
{
// macOS seems to require dequeuing NSApp events in order for the window to
// become visible. SDL marks the window as shown immediately after creation
// (see `SDL_FinishWindowCreation`), so drain pending startup events instead
// of waiting for a reliable SDL_WINDOWEVENT_SHOWN signal.
for (int pass = 0; pass < kMaxStartupEventPumpPasses; pass++) {
SDL_PumpEvents();
SDL_Event event;
if (!SDL_PollEvent(&event)) {
break;
}
do {
if (event.type == SDL_QUIT) {
exit(EXIT_SUCCESS);
}
} while (SDL_PollEvent(&event));
}
}
static bool createRenderer(int width, int height)
{
gSdlRenderer = SDL_CreateRenderer(gSdlWindow, -1, 0);
+2
View File
@@ -43,6 +43,8 @@ void _GNW95_zero_vid_mem();
int screenGetWidth();
int screenGetHeight();
int screenGetVisibleHeight();
void screenShowWindow();
void pumpStartupEvents();
void handleWindowSizeChanged();
void renderPresent();
bool screenIsFullscreen();