Skip to content

Windows sdl3 cleanup - #709

Draft
mcarans wants to merge 6 commits into
OoliteProject:masterfrom
mcarans:win_sdl3_cleanup
Draft

Windows sdl3 cleanup#709
mcarans wants to merge 6 commits into
OoliteProject:masterfrom
mcarans:win_sdl3_cleanup

Conversation

@mcarans

@mcarans mcarans commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Clean up of Windows code
Also uses same debouncing of resizing as Linux
Tested on Windows and Linux. Also tested fullscreen, exit game and reload - worked fine for me.

oocube
oocube previously approved these changes Aug 8, 2026

@oocube oocube left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The window under Ubuntu Gnome is not controllable. But that was not the intent of the fix. After all the situation has not worsened.

@mcarans

mcarans commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

The window under Ubuntu Gnome is not controllable. But that was not the intent of the fix. After all the situation has not worsened.

Yes this does not have the Gnome fix. Thanks for confirming Linux is the same. This PR cuts out a load of Windows specific code no longer needed with SDL3.

More cleanup will come in another PR after I merge this one assuming @phkb confirms this one doesn't break anything on Windows.

@phkb

phkb commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Generally everything seems to work as expected. However, there is now a 4-5 second delay whenever the F12 (fullscreen) button is pressed before the visuals are restored. That's going both ways, from full screen to windowed, and from windowed to full screen. There was almost no delay before. When in game, the clock keeps running during that delay, so for those 4-5 seconds you're flying blind.

@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Generally everything seems to work as expected. However, there is now a 4-5 second delay whenever the F12 (fullscreen) button is pressed before the visuals are restored. That's going both ways, from full screen to windowed, and from windowed to full screen. There was almost no delay before. When in game, the clock keeps running during that delay, so for those 4-5 seconds you're flying blind.

I just tested again and I don't have this issue. For me the transition is immediate both ways. Is there any clue in the logs? Can you tell me more about your setup? Also just to make completely sure, did you do a clean and build (I've noticed occasional odd behaviour without a clean)?

Also on the offchance this improves it, I had made further refactorings on a branch taken from the PR's branch. Does this make any difference? https://github.com/mcarans/oolite/releases/tag/1.93.1-win-sdl3-cleanup2.2

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

I'm running a Win11 Pro 25H2 build, 32GB RAM, Intel 12th Gen i5-12400F, with an NVIDIA GTX 1660. Logs are clear - no errors or unexpected messages.

Issue also happens with the "cleanup2" build.

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Some more observations.
When in fullscreen mode, and the game has the focus, pressing Alt-tab to switch to another application also causes a 4-5 second black screen delay. I also don't see the window thumbnails when I press Alt-tab, so I can't tell which app I'm switching to. I have to hold down Alt for those 4-5 seconds, at which point the thumbnails appear.

If I turn on HDR, going from windowed to full screen is instantaneous. Going back from full screen to windowed has the 4-5 second black screen delay.

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Oh, and if switch back to full screen Oolite (either with alt-tab or just by clicking on the app in the task bar, I again get that 4-5 second black screen delay.

@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Oh, and if switch back to full screen Oolite (either with alt-tab or just by clicking on the app in the task bar, I again get that 4-5 second black screen delay.

Does any of this happen with current master?

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Does any of this happen with current master?

No, current master is fine.

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Just for kicks, I also re-ran the setup for the build environment, in case there was something out of date (for whatever reason). But the issue persists.

…ktop mode. If the requested window size matches the desktop resolution, it sets SDL_SetWindowFullscreenMode(window, NULL) (Desktop Fullscreen).
@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Just for kicks, I also re-ran the setup for the build environment, in case there was something out of date (for whatever reason). But the issue persists.

AI claimed "The 5-second delay you are seeing on certain setups is caused by Hardware Display Mode Switching (Exclusive Fullscreen Mode).

When switching in or out of true Exclusive Fullscreen—or Alt-Tabbing away from it—the Windows GPU driver and the monitor must physically renegotiate display parameters (resolution, refresh rate, color depth, and HDCP/HDMI/DisplayPort handshakes). On modern high-refresh-rate monitors, VRR/G-Sync/FreeSync displays, or multi-monitor setups, this handshake routinely causes a 3–5 second black screen / delay...

Your old Win32 code explicitly checked whether the requested mode was actually different from the current desktop mode. If the requested game resolution matched the desktop resolution, the old code skipped the display mode change entirely, keeping the OS in desktop windowed mode under the hood. The new SDL3 code bypasses this logic and always requests a hard mode change when v_mode is active...

To eliminate the 5-second delay:

Default to Borderless / Desktop Fullscreen (SDL_SetWindowFullscreenMode(window, NULL)), which runs fullscreen at native display resolution without mode-switching delays.

Only set an explicit mode if v_mode is YES AND the requested resolution is different from the current desktop mode resolution."

It sounds plausible. The fix I checked in does the resolution check and seems instant on my computer. Does it help on yours?

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Same issue I'm afraid. No change.

@oocube

oocube commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Ah, this is about real full screen mode. I was just maximizing the window, which remains in windowed mode.
Yes, I think other applications also show a delay when switching to/from windowed into full screen mode?

@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Ah, this is about real full screen mode. I was just maximizing the window, which remains in windowed mode. Yes, I think other applications also show a delay when switching to/from windowed into full screen mode?

Are you saying that there is a new issue in this PR with a delay switching to/from windowed into full screen mode on your system or are you saying all applications for you exhibit a delay switching to/from windowed into full screen mode (ie. no change)? If you do see a new issue, does it also happen with master?

Same issue I'm afraid. No change.

Hmm, ok. Thanks for testing. I'll have to introduce smaller changes step by step to see which one affects your system.

Setting to draft for now.

@mcarans
mcarans marked this pull request as draft August 9, 2026 19:01
@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@phkb Please can you add logging like this after BOOL isDifferentResolution... and post what is logged.

OOLog(@"display.initGL.debug", @"[DEBUG] DisplayID: %u | Desktop: %dx%d | Requested: %dx%d | v_mode: %d | isDiff: %d",
      (unsigned int)displayID,
      desktopMode ? desktopMode->w : 0, 
      desktopMode ? desktopMode->h : 0,
      (int)viewSize.width, 
      (int)viewSize.height, 
      v_mode, 
      isDifferentResolution);

It could be that the if statements that follow are always evaluating to True. If so, please could you try forcing them to false as a test so the SDL_SetWindowFullscreenMode(window, NULL); path is taken to see if that makes any difference.

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Results from debug line:
07:11:22.839 [display.initGL.debug]: [DEBUG] DisplayID: 1 | Desktop: 1920x1080 | Requested: 1920x1080 | v_mode: 1 | isDiff: 0

@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Results from debug line: 07:11:22.839 [display.initGL.debug]: [DEBUG] DisplayID: 1 | Desktop: 1920x1080 | Requested: 1920x1080 | v_mode: 1 | isDiff: 0

Can you try pasting this in to the code?

if (fullScreen)
    {
        SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
        if (displayID == 0) displayID = SDL_GetPrimaryDisplay();
        const SDL_DisplayMode *desktopMode = SDL_GetDesktopDisplayMode(displayID);

        BOOL isDifferentResolution = desktopMode && 
            (desktopMode->w != (int)viewSize.width || desktopMode->h != (int)viewSize.height);

        if (v_mode && isDifferentResolution)
        {
            // Hardware Exclusive Fullscreen: Only used if an explicit mode shift is requested
            SDL_DisplayMode closestMode;
            if (SDL_GetClosestFullscreenDisplayMode(displayID, (int)viewSize.width, (int)viewSize.height, 0.0f, true, &closestMode))
            {
                SDL_SetWindowFullscreenMode(window, &closestMode);
            }
            SDL_SetWindowFullscreen(window, true);
        }
        else
        {
            // Pure Borderless Windowed Mode (Replicates the old Win32 behavior)
            // Unsets SDL_WINDOW_FULLSCREEN to prevent Windows DWM DirectFlip / Auto-HDR stalls
            SDL_SetWindowFullscreen(window, false);
            SDL_SetWindowBordered(window, false);

            SDL_Rect displayBounds;
            if (SDL_GetDisplayBounds(displayID, &displayBounds))
            {
                SDL_SetWindowPosition(window, displayBounds.x, displayBounds.y);
                SDL_SetWindowSize(window, displayBounds.w, displayBounds.h);
            }
            else
            {
                SDL_SetWindowPosition(window, 0, 0);
                SDL_SetWindowSize(window, (int)viewSize.width, (int)viewSize.height);
            }
        }
    }
    else
    {
        // Revert to Normal Windowed Mode
        SDL_SetWindowFullscreen(window, false);
        SDL_SetWindowBordered(window, true);
        SDL_SetWindowSize(window, (int)viewSize.width, (int)viewSize.height);

The old Win32 code apparently used a hack where if resolution = native resolution, it used a borderless window instead of real fullscreen. This change should do exactly the same but with pure SDL3.

@phkb

phkb commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Same issue. No change.

@mcarans

mcarans commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Same issue. No change.

Ok thanks for testing. Looks like a step by step approach is needed to identify the issue. It's tricky because it doesn't happen for me (much like oocube's Gnome issue).

@mcarans

mcarans commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@phkb I have researched this more and I think the hardware mode switching logic was still somehow causing the delay

I've branched from this PR's branch: #714 and tried again to simplify initialiseGLwithsize reducing it to just this which has no hardware mode switching logic (and is basically what Linux was doing):

- (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode
{
	if (!window)
	{
		[self createWindowWithSize: v_size];
	}
	viewSize = v_size;
	OOLog(@"display.initGL", @"Requested a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed"));
	SDL_GL_SwapWindow(window);	// clear the buffer before resize
	
	SDL_SetWindowBordered(window, v_mode);
	SDL_SetWindowFullscreen(window, fullScreen);
	SDL_SetWindowSize(window, viewSize.width, viewSize.height);
	int w, h;
	SDL_GetWindowSize(window, &w, &h);
	bounds.size.width = w;
	bounds.size.height = h;
	viewSize = bounds.size;
	OOLog(@"display.initGL", @"Created a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed"));

	if (viewSize.width/viewSize.height > 4.0/3.0) {
		display_z = 480.0 * bounds.size.width/bounds.size.height;
		x_offset = 240.0 * bounds.size.width/bounds.size.height;
		y_offset = 240.0;
	} else {
		display_z = 640.0;
		x_offset = 320.0;
		y_offset = 320.0 * bounds.size.height/bounds.size.width;
	}

	[self autoShowMouse];

	int pixelWidth, pixelHeight;
	SDL_GetWindowSizeInPixels(window, &pixelWidth, &pixelHeight);
	NSSize pixelSize = NSMakeSize(pixelWidth, pixelHeight);
	[[self gameController] setUpBasicOpenGLStateWithSize:pixelSize];
	SDL_GL_SwapWindow(window);
	squareX = 0.0f;

	m_glContextInitialized = YES;
}

Please can you test and let me know if you still get the 5 second delay: https://github.com/mcarans/oolite/tree/common_iniitalisegl (packages https://github.com/mcarans/oolite/actions/runs/31928149423)

If you do still get a delay, please can you tell me your screen resolution and monitor native resolution if different.

https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/for-best-performance--use-dxgi-flip-model

"Flip model presents go as far as making windowed mode effectively equivalent or better when compared to the classic "fullscreen exclusive" mode. In fact, you may want to reconsider whether your application actually needs a fullscreen exclusive mode, since the benefits of a flip model borderless window include faster Alt-Tab switching and better integration with modern display features."

@phkb

phkb commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

I'm still getting the 4-5 sec delay switching between fullscreen and windowed.
Anyway, monitor 1 and 2 are both resolution 1920x1080, scale 100%. Screen resolution and monitor resolution is the same.
Monitor 1 can be HDR, but most of the time I don't have it enabled.

Opening log for Oolite version 1.93.1-common-iniitalisegl.2 by unknown (x86-64 test release) under Windows 10.0.26200.9168 64-bit at 2026-08-16 15:55:26 +1000.
12th Gen Intel(R) Core(TM) i5-12400F 12 processors detected. System RAM: 32516 MB (free: 23409 MB).
...
Build options: OpenAL, GLSL shaders, new planets, JavaScript console support, OXP verifier, localization tools, debug GraphViz support, JavaScript profiling.
15:55:26.437 [rendering.opengl.version]: OpenGL renderer version: 4.6.0 ("4.6.0 NVIDIA 610.88"). Vendor: "NVIDIA Corporation". Renderer: "NVIDIA GeForce GTX 1660/PCIe/SSE2".
15:55:26.438 [rendering.opengl.extensions]: OpenGL extensions (403):
... snip ...
15:55:26.444 [rendering.opengl.shader.support]: Shaders are supported.
... snip ...
15:55:28.875 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
15:55:28.953 [display.initGL]: Created a new surface of 1280 x 720, windowed.
15:55:28.960 [startup.complete]: ========== Loading complete in 2.89 seconds. ==========
15:55:30.361 [display.initGL]: Requested a new surface of 1920 x 1080, fullscreen.
15:55:30.381 [display.initGL]: Created a new surface of 1920 x 1080, fullscreen.
15:55:36.447 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
15:55:36.474 [display.initGL]: Created a new surface of 1280 x 720, windowed.

(switching between windowed and full screen)

@mcarans

mcarans commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@phkb Can you see if the latest changes on this branch helps? https://github.com/mcarans/oolite/tree/common_iniitalisegl
packages here: https://github.com/mcarans/oolite/actions/runs/31934818555. I'm wondering if setWindowSize has something to do with it

In your logs from before the delays seemed small eg.

15:55:30.361 [display.initGL]: Requested a new surface of 1920 x 1080, fullscreen.
15:55:30.381 [display.initGL]: Created a new surface of 1920 x 1080, fullscreen.

If there are still issues, would you be able to add logging to see where the delay is occurring?

@phkb

phkb commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Still having the same issues.

22:02:48.145 [sdl.init]: initialising SDL
22:02:48.213 [display.mode.list.native]: Windows native resolution detected: 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1920 x 1080
22:02:48.294 [display.mode.list]: Added res 1680 x 1050
22:02:48.294 [display.mode.list]: Added res 1680 x 1050
22:02:48.294 [display.mode.list]: Added res 1680 x 1050
22:02:48.294 [display.mode.list]: Added res 1680 x 1050
22:02:48.294 [display.mode.list]: Added res 1680 x 1050
22:02:48.294 [display.mode.list]: Added res 1600 x 1024
22:02:48.294 [display.mode.list]: Added res 1600 x 1024
22:02:48.294 [display.mode.list]: Added res 1600 x 1024
22:02:48.294 [display.mode.list]: Added res 1600 x 1024
22:02:48.294 [display.mode.list]: Added res 1600 x 1024
22:02:48.294 [display.mode.list]: Added res 1600 x 900
22:02:48.294 [display.mode.list]: Added res 1600 x 900
22:02:48.294 [display.mode.list]: Added res 1600 x 900
22:02:48.294 [display.mode.list]: Added res 1600 x 900
22:02:48.294 [display.mode.list]: Added res 1600 x 900
22:02:48.294 [display.mode.list]: Added res 1440 x 1080
22:02:48.294 [display.mode.list]: Added res 1440 x 1080
22:02:48.295 [display.mode.list]: Added res 1440 x 1080
22:02:48.295 [display.mode.list]: Added res 1440 x 1080
22:02:48.295 [display.mode.list]: Added res 1440 x 1080
22:02:48.295 [display.mode.list]: Added res 1440 x 1080
22:02:48.295 [display.mode.list]: Added res 1440 x 1080
22:02:48.295 [display.mode.list]: Added res 1440 x 900
22:02:48.295 [display.mode.list]: Added res 1440 x 900
22:02:48.295 [display.mode.list]: Added res 1440 x 900
22:02:48.295 [display.mode.list]: Added res 1440 x 900
22:02:48.295 [display.mode.list]: Added res 1440 x 900
22:02:48.295 [display.mode.list]: Added res 1366 x 768
22:02:48.295 [display.mode.list]: Added res 1366 x 768
22:02:48.295 [display.mode.list]: Added res 1366 x 768
22:02:48.295 [display.mode.list]: Added res 1366 x 768
22:02:48.295 [display.mode.list]: Added res 1366 x 768
22:02:48.295 [display.mode.list]: Added res 1360 x 768
22:02:48.295 [display.mode.list]: Added res 1360 x 768
22:02:48.295 [display.mode.list]: Added res 1360 x 768
22:02:48.295 [display.mode.list]: Added res 1360 x 768
22:02:48.295 [display.mode.list]: Added res 1360 x 768
22:02:48.295 [display.mode.list]: Added res 1280 x 1024
22:02:48.295 [display.mode.list]: Added res 1280 x 1024
22:02:48.295 [display.mode.list]: Added res 1280 x 1024
22:02:48.295 [display.mode.list]: Added res 1280 x 1024
22:02:48.295 [display.mode.list]: Added res 1280 x 1024
22:02:48.295 [display.mode.list]: Added res 1280 x 1024
22:02:48.295 [display.mode.list]: Added res 1280 x 960
22:02:48.295 [display.mode.list]: Added res 1280 x 960
22:02:48.295 [display.mode.list]: Added res 1280 x 960
22:02:48.295 [display.mode.list]: Added res 1280 x 960
22:02:48.295 [display.mode.list]: Added res 1280 x 960
22:02:48.295 [display.mode.list]: Added res 1280 x 800
22:02:48.295 [display.mode.list]: Added res 1280 x 800
22:02:48.295 [display.mode.list]: Added res 1280 x 800
22:02:48.295 [display.mode.list]: Added res 1280 x 800
22:02:48.295 [display.mode.list]: Added res 1280 x 800
22:02:48.295 [display.mode.list]: Added res 1280 x 768
22:02:48.295 [display.mode.list]: Added res 1280 x 768
22:02:48.295 [display.mode.list]: Added res 1280 x 768
22:02:48.295 [display.mode.list]: Added res 1280 x 768
22:02:48.295 [display.mode.list]: Added res 1280 x 768
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1280 x 720
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1176 x 664
22:02:48.295 [display.mode.list]: Added res 1152 x 864
22:02:48.295 [display.mode.list]: Added res 1152 x 864
22:02:48.295 [display.mode.list]: Added res 1152 x 864
22:02:48.295 [display.mode.list]: Added res 1152 x 864
22:02:48.295 [display.mode.list]: Added res 1152 x 864
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 1024 x 768
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 800 x 600
22:02:48.295 [display.mode.list]: Added res 720 x 576
22:02:48.295 [display.mode.list]: Added res 720 x 576
22:02:48.295 [display.mode.list]: Added res 720 x 576
22:02:48.295 [display.mode.list]: Added res 720 x 576
22:02:48.295 [display.mode.list]: Added res 720 x 576
22:02:48.295 [display.mode.list]: Added res 720 x 480
22:02:48.295 [display.mode.list]: Added res 720 x 480
22:02:48.295 [display.mode.list]: Added res 720 x 480
22:02:48.295 [display.mode.list]: Added res 720 x 480
22:02:48.295 [display.mode.list]: Added res 720 x 480
22:02:48.295 [display.mode.list]: Added res 720 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.295 [display.mode.list]: Added res 640 x 480
22:02:48.333 [display.mode.list]: CREATING MODE LIST
22:02:48.336 [display.initGL]: Trying 8-bpcc, 24-bit depth buffer
22:02:48.512 [display.initGL]: V-Sync requested.
22:02:48.512 [display.initGL]: Achieved color / depth buffer sizes (bits):
22:02:48.512 [display.initGL]: Red: 8
22:02:48.512 [display.initGL]: Green: 8
22:02:48.512 [display.initGL]: Blue: 8
22:02:48.512 [display.initGL]: Alpha: 8
22:02:48.512 [display.initGL]: Depth Buffer: 24
22:02:48.512 [display.initGL]: Pixel type is float : 0
22:02:48.512 [display.initGL]: Pixel format index: 10
22:02:48.512 [display.initGL]: ----- WARNING: Could not enable V-Sync. Please check that your graphics driver supports the WGL_EXT_swap_control extension.
22:02:48.518 [joystick.init]: Number of joysticks detected: 1
22:02:48.519 [rendering.opengl.version]: OpenGL renderer version: 4.6.0 ("4.6.0 NVIDIA 610.88"). Vendor: "NVIDIA Corporation". Renderer: "NVIDIA GeForce GTX 1660/PCIe/SSE2".
...snip...
22:03:48.475 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
22:03:48.565 [display.initGL]: Created a new surface of 1280 x 720, windowed.
22:03:54.654 [display.initGL]: Requested a new surface of 1920 x 1080, fullscreen.
22:03:54.685 [display.initGL]: Created a new surface of 1920 x 1080, fullscreen.
22:03:59.008 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
22:03:59.044 [display.initGL]: Created a new surface of 1280 x 720, windowed.
22:04:11.419 [exit.context]: Exiting: Exit Game selected on start screen.

Time between the different sizes is how fast I was able to change from one mode to another. ie. Press F12, wait until display appears, immediately press F12 again.

@mcarans

mcarans commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@phkb Hmm I need to narrow down where the delay is occurring. One suggestion from AI:

check NVIDIA Control Panel → Set up G-SYNC.

What is it set to currently?

Try changing G-SYNC from "Enable for windowed and full screen mode" to "Enable for full screen mode only" if it isn't set to that already

If you have that setting, can you see if it makes any difference? It would give a clue as to where the problem lies.

Also, please try adding this before the SDL_SetWindowFullscreen call and let me know what it says:

const SDL_DisplayMode *fsMode = SDL_GetWindowFullscreenMode(window);

if (fsMode)
{
    OOLog(@"display.fullscreen",
          @"SDL fullscreen mode: %dx%d %.3f Hz",
          fsMode->w,
          fsMode->h,
          fsMode->refresh_rate);
}
else
{
    OOLog(@"display.fullscreen",
          @"SDL fullscreen mode: NULL (desktop/borderless fullscreen)");
}

Also add instrumentation at the end (since we already established that between request and create surface, the time is short):

OOLog(@"display.initGL", @"Created ...");

OOLog(@"display.initGL", @"Before setUpBasicOpenGLState");
[[self gameController] setUpBasicOpenGLStateWithSize:pixelSize];
OOLog(@"display.initGL", @"After setUpBasicOpenGLState");

OOLog(@"display.initGL", @"Before final SwapWindow");
SDL_GL_SwapWindow(window);
OOLog(@"display.initGL", @"After final SwapWindow");

@phkb

phkb commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Tried with G-SYNC on/off/fullscreen only/fullscreen+windowed and all had the same issue.

Log file with extra info:

Opening log for Oolite version 1.93.1-common-iniitalisegl.4+dirty.0 by unknown (x86-64 test release) under Windows 10.0.26200.9168 64-bit at 2026-08-17 09:13:37 +1000.
12th Gen Intel(R) Core(TM) i5-12400F 12 processors detected. System RAM: 32516 MB (free: 21611 MB).
Build options: OpenAL, GLSL shaders, new planets, JavaScript console support, OXP verifier, localization tools, debug GraphViz support, JavaScript profiling.

Note that the contents of the log file can be adjusted by editing logcontrol.plist.

09:13:37.139 [process.args]: Startup command: C:\Build\Oolite193\oolite\build\meson_test\oolite.app\oolite.exe
09:13:37.199 [display.mode.list.native]: Windows native resolution detected: 1920 x 1080
09:13:37.332 [display.initGL]: Trying 8-bpcc, 24-bit depth buffer
09:13:37.509 [display.initGL]: V-Sync requested.
09:13:37.509 [display.initGL]: Achieved color / depth buffer sizes (bits):
09:13:37.509 [display.initGL]: Red: 8
09:13:37.509 [display.initGL]: Green: 8
09:13:37.509 [display.initGL]: Blue: 8
09:13:37.509 [display.initGL]: Alpha: 8
09:13:37.509 [display.initGL]: Depth Buffer: 24
09:13:37.509 [display.initGL]: Pixel type is float : 0
09:13:37.509 [display.initGL]: Pixel format index: 10
09:13:37.509 [display.initGL]: ----- WARNING: Could not enable V-Sync. Please check that your graphics driver supports the WGL_EXT_swap_control extension.
09:13:37.516 [joystick.init]: Number of joysticks detected: 1
09:13:37.517 [rendering.opengl.version]: OpenGL renderer version: 4.6.0 ("4.6.0 NVIDIA 610.88"). Vendor: "NVIDIA Corporation". Renderer: "NVIDIA GeForce GTX 1660/PCIe/SSE2".
09:13:37.517 [rendering.opengl.extensions]: OpenGL extensions (403):
...snip...
09:13:37.522 [rendering.opengl.shader.support]: Shaders are supported.
09:13:37.541 [searchPaths.dumpAll]: Resource paths:
~/Resources
~/AddOns
~/AddOns/Basic-debug.oxp
09:13:37.545 [MSAA.setup]: Multisample anti-aliasing not requested.
09:13:37.562 [shipData.load.begin]: Loading ship data.
09:13:37.713 [script.javascript.init]: JavaScript reset successful.
09:13:37.756 [display.fullscreen]: SDL fullscreen mode: NULL (desktop/borderless fullscreen)
09:13:37.782 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
09:13:37.861 [display.initGL]: Created a new surface of 1280 x 720, windowed.
09:13:37.861 [display.initGL]: Created ...
09:13:37.861 [display.initGL]: Before setUpBasicOpenGLState
09:13:37.861 [display.initGL]: After setUpBasicOpenGLState
09:13:37.861 [display.initGL]: Before final SwapWindow
09:13:37.861 [display.initGL]: After final SwapWindow
09:13:37.870 [startup.complete]: ========== Loading complete in 0.73 seconds. ==========
09:13:37.924 [debugTCP.connected]: Connected to debug console "DebugConsole".
09:13:45.505 [display.initGL]: Requested a new surface of 1920 x 1080, fullscreen.
09:13:45.534 [display.initGL]: Created a new surface of 1920 x 1080, fullscreen.
09:13:45.534 [display.initGL]: Created ...
09:13:45.534 [display.initGL]: Before setUpBasicOpenGLState
09:13:45.534 [display.initGL]: After setUpBasicOpenGLState
09:13:45.534 [display.initGL]: Before final SwapWindow
09:13:45.534 [display.initGL]: After final SwapWindow
09:13:49.825 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
09:13:49.861 [display.initGL]: Created a new surface of 1280 x 720, windowed.
09:13:49.863 [display.initGL]: Created ...
09:13:49.863 [display.initGL]: Before setUpBasicOpenGLState
09:13:49.863 [display.initGL]: After setUpBasicOpenGLState
09:13:49.863 [display.initGL]: Before final SwapWindow
09:13:49.863 [display.initGL]: After final SwapWindow
09:13:54.122 [display.initGL]: Requested a new surface of 1920 x 1080, fullscreen.
09:13:54.151 [display.initGL]: Created a new surface of 1920 x 1080, fullscreen.
09:13:54.151 [display.initGL]: Created ...
09:13:54.151 [display.initGL]: Before setUpBasicOpenGLState
09:13:54.151 [display.initGL]: After setUpBasicOpenGLState
09:13:54.151 [display.initGL]: Before final SwapWindow
09:13:54.151 [display.initGL]: After final SwapWindow
09:13:58.425 [display.initGL]: Requested a new surface of 1280 x 720, windowed.
09:13:58.514 [display.initGL]: Created a new surface of 1280 x 720, windowed.
09:13:58.514 [display.initGL]: Created ...
09:13:58.514 [display.initGL]: Before setUpBasicOpenGLState
09:13:58.514 [display.initGL]: After setUpBasicOpenGLState
09:13:58.514 [display.initGL]: Before final SwapWindow
09:13:58.514 [display.initGL]: After final SwapWindow
09:14:05.235 [exit.context]: Exiting: Exit Game selected on start screen.
09:14:05.241 [gameController.exitApp]: .GNUstepDefaults synchronized.

Closing log at 2026-08-17 09:14:05 +1000.

Pressing F12 as soon as the window was visible, 4 times in total.

Watching the log while changing screen size, all the entries for each change would appear about 1 second after I pressed F12, then there is a further delay before I see anything in the window. It would appear that whatever the delay is, it's happening later in the process. I'll add some more debug messages and report back.

@mcarans

mcarans commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

It would appear that whatever the delay is, it's happening later in the process. I'll add some more debug messages and report back.

Yes indeed. How strange! Thanks for testing.

F12 calls toggleScreenMode which calls initialiseGLWithSize. The lines after initialiseGLWithSize in toggleScreenMode are:

	if ([PlayerEntity sharedPlayer])
	{
		[[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates];
	}

If that is being called, presumably the delay is somewhere in there. I was able to remove that call from resizing altogether without ill effect (already on master) so maybe it can be removed here too? I just tried on Linux and it seems to be fine.

@phkb

phkb commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

I did find this issue: libsdl-org/SDL#11041
I'm guessing you've found that already, though.

@mcarans

mcarans commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

I did find this issue: libsdl-org/SDL#11041 I'm guessing you've found that already, though.

Interesting, I hadn't seen that - it could be a clue. Please try adding logging before and after various calls using this function:

static void LogWindowStyle(const char *label, HWND hwnd)
{
	LONG style = GetWindowLong(hwnd, GWL_STYLE);
	LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);

	OOLog(@"display.style",
		  @"%s: STYLE=%08lX EXSTYLE=%08lX "
		  @"POPUP=%d OVERLAPPED=%d CAPTION=%d THICKFRAME=%d "
		  @"SYSMENU=%d MINIMIZEBOX=%d MAXIMIZEBOX=%d "
		  @"VISIBLE=%d MINIMIZED=%d MAXIMIZED=%d",
		  label,
		  style,
		  exStyle,
		  !!(style & WS_POPUP),
		  !!(style & WS_OVERLAPPED),
		  !!(style & WS_CAPTION),
		  !!(style & WS_THICKFRAME),
		  !!(style & WS_SYSMENU),
		  !!(style & WS_MINIMIZEBOX),
		  !!(style & WS_MAXIMIZEBOX),
		  !!(style & WS_VISIBLE),
		  !!(style & WS_MINIMIZE),
		  !!(style & WS_MAXIMIZE));
}

Log like this:

LogWindowStyle("BEFORE SDL_SetWindowBordered", windowHandle);

SDL_SetWindowBordered(window, v_mode);

LogWindowStyle("AFTER SDL_SetWindowBordered", windowHandle);

SDL_SetWindowFullscreen(window, fullScreen);

LogWindowStyle("AFTER SDL_SetWindowFullscreen", windowHandle);

SDL_SetWindowSize(window, viewSize.width, viewSize.height);

LogWindowStyle("AFTER SDL_SetWindowSize", windowHandle);

I also just found these issues which may be related:
libsdl-org/SDL#12791
libsdl-org/SDL#14777

From the first of those two:
"Hats off to OP for coming up with the hack on their own, but the actual trick for any window covering the entire screen is just not to use the WS_POPUP or WS_EX_TOPMOST styles." (let's see what the logging of flags above reveals)

Also can you try this (also from a comment in that issue)?
"Changing in the NVIDIA Control Panel, Vulkan/OpenGL present method to Prefer layered on DXGI Swapchain entirely fixes this issue. Your window will be proper borderless with overlay popup workings and Alt-Tab instant.

Interestingly, that setting seems to also make fullscreen borderless any suitable SDL_WINDOW_FULLSCREEN window (which would normally be fullscreen exclusive)."

@phkb

phkb commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

From windowed to full screen

14:18:57.526 [testing]: F12 pressed
14:18:57.530 [display.initGL]: Requested a new surface of 1920 x 1080, fullscreen.
14:18:57.541 [display.style]: Before SDL_SetWindowFullscreen: STYLE=16CF0000 EXSTYLE=00000110 POPUP=0 OVERLAPPED=0 CAPTION=1 THICKFRAME=1 SYSMENU=1 MINIMIZEBOX=1 MAXIMIZEBOX=1 VISIBLE=1 MINIMIZED=0 MAXIMIZED=0
14:18:57.559 [display.style]: After SDL_SetWindowFullscreen: STYLE=96020000 EXSTYLE=00000010 POPUP=1 OVERLAPPED=0 CAPTION=0 THICKFRAME=0 SYSMENU=0 MINIMIZEBOX=1 MAXIMIZEBOX=0 VISIBLE=1 MINIMIZED=0 MAXIMIZED=0
14:18:57.559 [display.initGL]: Created a new surface of 1920 x 1080, fullscreen.
14:18:57.559 [display.initGL]: Created ...
14:18:57.559 [display.initGL]: Before setUpBasicOpenGLState
14:18:57.559 [display.initGL]: After setUpBasicOpenGLState
14:18:57.559 [display.initGL]: Before final SwapWindow
14:18:57.559 [display.initGL]: After final SwapWindow

From full screen to windowed

14:19:05.414 [testing]: F12 pressed
14:19:05.418 [display.initGL]: Requested a new surface of 1370 x 808, windowed.
14:19:05.429 [display.style]: Before SDL_SetWindowSize: STYLE=96020000 EXSTYLE=00000010 POPUP=1 OVERLAPPED=0 CAPTION=0 THICKFRAME=0 SYSMENU=0 MINIMIZEBOX=1 MAXIMIZEBOX=0 VISIBLE=1 MINIMIZED=0 MAXIMIZED=0
14:19:05.429 [display.style]: Before SDL_SetWindowBoardered: STYLE=96020000 EXSTYLE=00000010 POPUP=1 OVERLAPPED=0 CAPTION=0 THICKFRAME=0 SYSMENU=0 MINIMIZEBOX=1 MAXIMIZEBOX=0 VISIBLE=1 MINIMIZED=0 MAXIMIZED=0
14:19:05.429 [display.style]: Before SDL_SetWindowFullscreen: STYLE=96020000 EXSTYLE=00000010 POPUP=1 OVERLAPPED=0 CAPTION=0 THICKFRAME=0 SYSMENU=0 MINIMIZEBOX=1 MAXIMIZEBOX=0 VISIBLE=1 MINIMIZED=0 MAXIMIZED=0
14:19:05.456 [display.style]: After SDL_SetWindowFullscreen: STYLE=16CF0000 EXSTYLE=00000110 POPUP=0 OVERLAPPED=0 CAPTION=1 THICKFRAME=1 SYSMENU=1 MINIMIZEBOX=1 MAXIMIZEBOX=1 VISIBLE=1 MINIMIZED=0 MAXIMIZED=0
14:19:05.456 [display.initGL]: Created a new surface of 1370 x 808, windowed.
14:19:05.457 [display.initGL]: Created ...
14:19:05.457 [display.initGL]: Before setUpBasicOpenGLState
14:19:05.457 [display.initGL]: After setUpBasicOpenGLState
14:19:05.457 [display.initGL]: Before final SwapWindow
14:19:05.457 [display.initGL]: After final SwapWindow

@phkb

phkb commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Also can you try this (also from a comment in that issue)?
"Changing in the NVIDIA Control Panel, Vulkan/OpenGL present method to Prefer layered on DXGI Swapchain entirely fixes this issue. Your window will be proper borderless with overlay popup workings and Alt-Tab instant.

I can also report that this works! Switching, alt-tab, everything is instantaneous again!

Is this something all players with NVIDIA cards will need to do? Or is it because my card is a bit old now?

@mcarans

mcarans commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Also can you try this (also from a comment in that issue)?
"Changing in the NVIDIA Control Panel, Vulkan/OpenGL present method to Prefer layered on DXGI Swapchain entirely fixes this issue. Your window will be proper borderless with overlay popup workings and Alt-Tab instant.

I can also report that this works! Switching, alt-tab, everything is instantaneous again!

Is this something all players with NVIDIA cards will need to do? Or is it because my card is a bit old now?

That is excellent news! So glad you found that GitHub issue.

What is happening for you is a Windows/NVIDIA OpenGL presentation-path problem triggered by SDL3's fullscreen window configuration (WS_POPUP). I don't think that it should be necessary for all Windows nVidia users to make changes (I have nVidia and don't need to do anything). I think a workaround should be possible, hopefully without reintroducing all the old Win32 code.

@mcarans

mcarans commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

@phkb Please try creating this function:

- (void) restoreOldStyleBorderless
{
	LONG currentWindowStyle = GetWindowLong(windowHandle, GWL_STYLE);

	OOLog(@"display.style",
		  @"Before restoreOldStyleBorderless: STYLE=%08lX EXSTYLE=%08lX",
		  (unsigned long)currentWindowStyle,
		  (unsigned long)GetWindowLong(windowHandle, GWL_EXSTYLE));

	// Remove SDL's WS_POPUP fullscreen style and restore the old
	// Oolite-style borderless window: normal window style with
	// caption and thick frame removed.
	currentWindowStyle &= ~WS_POPUP;
	currentWindowStyle &= ~WS_CAPTION;
	currentWindowStyle &= ~WS_THICKFRAME;

	SetWindowLong(windowHandle, GWL_STYLE, currentWindowStyle);

	SetWindowPos(windowHandle,
				 NULL,
				 0, 0, 0, 0,
				 SWP_NOMOVE |
				 SWP_NOSIZE |
				 SWP_FRAMECHANGED |
				 SWP_NOACTIVATE);

	OOLog(@"display.style",
		  @"After restoreOldStyleBorderless: STYLE=%08lX EXSTYLE=%08lX",
		  (unsigned long)GetWindowLong(windowHandle, GWL_STYLE),
		  (unsigned long)GetWindowLong(windowHandle, GWL_EXSTYLE));
}

After SDL_SetWindowFullscreen add:

if (fullScreen)
{
	OOLog(@"display.initGL",
		  @"Before restoreOldStyleBorderless");

	[self restoreOldStyleBorderless];

	OOLog(@"display.initGL",
		  @"After restoreOldStyleBorderless");
}

Run this with the original nVidia driver setting not "Prefer layered on DXGI Swapchain". Does this give a delay?

@phkb

phkb commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

No delay with the old setting. Success!

@mcarans

mcarans commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

@phkb please can you change the hack function to only remove WS_POPUP and give me this fuller log output:

- (void) restoreOldStyleBorderless
{
	LONG currentWindowStyle = GetWindowLong(windowHandle, GWL_STYLE);
	LONG currentExStyle = GetWindowLong(windowHandle, GWL_EXSTYLE);

	OOLog(@"display.style",
		  @"Before: STYLE=%08lX EXSTYLE=%08lX "
		  @"POPUP=%d CAPTION=%d THICKFRAME=%d "
		  @"SYSMENU=%d MINIMIZEBOX=%d MAXIMIZEBOX=%d",
		  (unsigned long)currentWindowStyle,
		  (unsigned long)currentExStyle,
		  !!(currentWindowStyle & WS_POPUP),
		  !!(currentWindowStyle & WS_CAPTION),
		  !!(currentWindowStyle & WS_THICKFRAME),
		  !!(currentWindowStyle & WS_SYSMENU),
		  !!(currentWindowStyle & WS_MINIMIZEBOX),
		  !!(currentWindowStyle & WS_MAXIMIZEBOX));

	currentWindowStyle &= ~WS_POPUP;

	SetWindowLong(windowHandle, GWL_STYLE, currentWindowStyle);

	SetWindowPos(windowHandle,
				 NULL,
				 0, 0, 0, 0,
				 SWP_NOMOVE |
				 SWP_NOSIZE |
				 SWP_FRAMECHANGED |
				 SWP_NOACTIVATE);

	currentWindowStyle = GetWindowLong(windowHandle, GWL_STYLE);
	currentExStyle = GetWindowLong(windowHandle, GWL_EXSTYLE);

	OOLog(@"display.style",
		  @"After: STYLE=%08lX EXSTYLE=%08lX "
		  @"POPUP=%d CAPTION=%d THICKFRAME=%d "
		  @"SYSMENU=%d MINIMIZEBOX=%d MAXIMIZEBOX=%d",
		  (unsigned long)currentWindowStyle,
		  (unsigned long)currentExStyle,
		  !!(currentWindowStyle & WS_POPUP),
		  !!(currentWindowStyle & WS_CAPTION),
		  !!(currentWindowStyle & WS_THICKFRAME),
		  !!(currentWindowStyle & WS_SYSMENU),
		  !!(currentWindowStyle & WS_MINIMIZEBOX),
		  !!(currentWindowStyle & WS_MAXIMIZEBOX));
}

Also did you already remove the code below from toggleScreenMode? If not, can you try removing it to see if it makes any difference? If it can be removed, the entire doGuiScreenResizeUpdates can be removed as it isn't called from anywhere else from what I've seen.

	if ([PlayerEntity sharedPlayer])
	{
		[[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates];
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants