Skip to content

Commit fcb512e

Browse files
committed
Fix high-DPI SDL window state handling
1 parent 3f24192 commit fcb512e

2 files changed

Lines changed: 50 additions & 29 deletions

File tree

Nu/Nu/Sdl/SdlDeps.fs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,24 @@ module SdlDeps =
122122
else Left error
123123

124124
/// Attempt to initalize an SDL resource.
125-
let private tryMakeSdlResource create destroy =
125+
let private tryMakeSdlResource create destroy failureDestroy =
126126
let resource = create ()
127127
if NativePtr.isNullPtr resource
128-
then Left ("SDL3# resource creation failed due to '" + SDL3.SDL_GetError () + "'.")
128+
then
129+
let error = "SDL3# resource creation failed due to '" + SDL3.SDL_GetError () + "'."
130+
failureDestroy ()
131+
Left error
129132
else Right (resource, destroy)
130133

131134
/// Attempt to initalize a global SDL resource.
132-
let private tryMakeSdlGlobalResource create destroy =
135+
let private tryMakeSdlGlobalResource create destroy failureDestroy =
133136
let resource : SDLBool = create ()
134137
if SDLBool.op_Implicit resource
135138
then Right ((), destroy)
136-
else Left ("SDL3# global resource creation failed due to '" + SDL3.SDL_GetError () + "'.")
139+
else
140+
let error = "SDL3# global resource creation failed due to '" + SDL3.SDL_GetError () + "'."
141+
failureDestroy ()
142+
Left error
137143

138144
/// Get the display mode for the desktop occupied by the given window.
139145
let internal getDisplayModeInternal window =
@@ -164,21 +170,24 @@ module SdlDeps =
164170
| Some window ->
165171

166172
// get a snapshot of whether screen was full
167-
let mutable (windowWidth, windowHeight) = (0, 0)
168-
SDL3.SDL_GetWindowSizeInPixels (window, &&windowWidth, &&windowHeight) |> ignore<SDLBool>
169-
let displayMode = getDisplayModeInternal window
170-
let wasFullScreen = windowWidth = displayMode.w || windowHeight = displayMode.h
173+
let flags = SDL3.SDL_GetWindowFlags window
174+
let wasFullScreen =
175+
flags &&& SDL_WindowFlags.SDL_WINDOW_FULLSCREEN <> LanguagePrimitives.EnumOfValue 0UL
171176

172177
// change full screen status via flags
173-
SDL3.SDL_SetWindowFullscreen (window, fullScreen) |> ignore<SDLBool>
178+
let fullScreenChanged = SDL3.SDL_SetWindowFullscreen (window, fullScreen) |> SDLBool.op_Implicit
174179

175180
// when changing from full screen, set window to windowed size and make sure its title bar is visible
176-
if wasFullScreen && not fullScreen then
177-
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
178-
let sizeWindowed = Constants.Render.DisplayVirtualResolution * 2
179-
SDL3.SDL_RestoreWindow window |> ignore<SDLBool>
180-
SDL3.SDL_SetWindowSize (window, int (single sizeWindowed.X / pixelDensity), int (single sizeWindowed.Y / pixelDensity)) |> ignore
181-
SDL3.SDL_SetWindowPosition (window, 100, 100) |> ignore<SDLBool> // NOTE: pretty arbitrary numbers here...
181+
if fullScreenChanged && wasFullScreen && not fullScreen then
182+
if SDL3.SDL_SyncWindow window |> SDLBool.op_Implicit then
183+
let windowSizeWindowed = Constants.Render.DisplayVirtualResolution * 2
184+
if SDL3.SDL_RestoreWindow window |> SDLBool.op_Implicit then
185+
if SDL3.SDL_SyncWindow window |> SDLBool.op_Implicit then
186+
// Restoration can change the window's display, and therefore its pixel density.
187+
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
188+
SDL3.SDL_SetWindowSize (window, int (single windowSizeWindowed.X / pixelDensity), int (single windowSizeWindowed.Y / pixelDensity)) |> ignore<SDLBool>
189+
if SDL3.SDL_SyncWindow window |> SDLBool.op_Implicit then
190+
SDL3.SDL_SetWindowPosition (window, 100, 100) |> ignore<SDLBool> // NOTE: pretty arbitrary numbers here...
182191

183192
| None -> ()
184193
sdlDeps
@@ -281,18 +290,24 @@ module SdlDeps =
281290
let windowConfig = sdlConfig.WindowConfig
282291
let windowOpt = SDL3.SDL_CreateWindow (windowConfig.WindowTitle, windowSize.X, windowSize.Y, windowConfig.WindowFlags)
283292
if NativePtr.notNullPtr windowOpt then
284-
285293
// set window position
286294
let window = windowOpt
287295
SDL3.SDL_SetWindowPosition (window, windowConfig.WindowX, windowConfig.WindowY) |> ignore<SDLBool>
288-
296+
// Wait for the move so pixel density reflects the display now containing the window.
297+
SDL3.SDL_SyncWindow window |> ignore<SDLBool>
298+
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
299+
SDL3.SDL_SetWindowSize (window, int (single windowSize.X / pixelDensity), int (single windowSize.Y / pixelDensity)) |> ignore<SDLBool>
300+
// Wait for the resize because the pre-splash immediately queries pixel dimensions and the window surface.
301+
SDL3.SDL_SyncWindow window |> ignore<SDLBool>
289302
// start text input except on platforms that would obscure the game with a virtual keyboard
290303
if not (SDL3.SDL_HasScreenKeyboardSupport ()) then
291304
SDL3.SDL_StartTextInput window |> ignore<SDLBool>
292305

293306
// set to full screen when window taking up entire screen and unaccompanied
294-
let mutable displayMode = getDisplayModeInternal window
295-
if (windowSize.X = displayMode.w || windowSize.Y = displayMode.h) && not accompanied then
307+
let displayMode = getDisplayModeInternal window
308+
if (windowSize.X = int (single displayMode.w * pixelDensity) ||
309+
windowSize.Y = int (single displayMode.h * pixelDensity)) &&
310+
not accompanied then
296311
SDL3.SDL_SetWindowFullscreen (window, true) |> ignore<SDLBool>
297312

298313
// attempt to show splash screen (software surface; will be overwritten by Vulkan)
@@ -301,13 +316,20 @@ module SdlDeps =
301316
// fin
302317
windowOpt)
303318

304-
(fun window -> SDL3.SDL_DestroyWindow window; destroy ()) with
319+
(fun window -> SDL3.SDL_DestroyWindow window; destroy ())
320+
destroy with
305321
| Left error -> Left error
306322
| Right (window, destroy) ->
307-
match tryMakeSdlGlobalResource SDL3_ttf.TTF_Init (fun () -> SDL3_ttf.TTF_Quit (); destroy window) with
323+
match tryMakeSdlGlobalResource
324+
SDL3_ttf.TTF_Init
325+
(fun () -> SDL3_ttf.TTF_Quit (); destroy window)
326+
(fun () -> destroy window) with
308327
| Left error -> Left error
309328
| Right ((), destroy) ->
310-
match tryMakeSdlGlobalResource SDL3_mixer.MIX_Init (fun () -> SDL3_mixer.MIX_Quit (); destroy ()) with
329+
match tryMakeSdlGlobalResource
330+
SDL3_mixer.MIX_Init
331+
(fun () -> SDL3_mixer.MIX_Quit (); destroy ())
332+
destroy with
311333
| Left error -> Left error
312334
| Right ((), destroy) ->
313335
Log.info

Nu/Nu/World/WorldPrelude.fs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -669,11 +669,9 @@ module internal AmbientState =
669669

670670
let internal tryGetWindowFullScreen state =
671671
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
672-
| Some window ->
673-
let mutable width, height = 0, 0
674-
SDL3.SDL_GetWindowSizeInPixels (window, &&width, &&height) |> ignore
675-
let displayMode = SdlDeps.getDisplayModeInternal window
676-
Some (width = displayMode.w || height = displayMode.h)
672+
| Some window ->
673+
let flags = SDL3.SDL_GetWindowFlags window
674+
Some (flags &&& SDL_WindowFlags.SDL_WINDOW_FULLSCREEN <> LanguagePrimitives.EnumOfValue 0UL)
677675
| _ -> None
678676

679677
let internal trySetWindowFullScreen fullScreen state =
@@ -698,7 +696,7 @@ module internal AmbientState =
698696
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
699697
| Some window ->
700698
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
701-
SDL3.SDL_SetWindowPosition (window, int (single position.X * pixelDensity), int (single position.Y * pixelDensity)) |> ignore<SDLBool>
699+
SDL3.SDL_SetWindowPosition (window, int (single position.X / pixelDensity), int (single position.Y / pixelDensity)) |> ignore<SDLBool>
702700
| None -> ()
703701

704702
let internal tryGetWindowSize state =
@@ -713,7 +711,8 @@ module internal AmbientState =
713711
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
714712
| Some window ->
715713
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
716-
SDL3.SDL_SetWindowSize (window, int (single size.X / pixelDensity), int (single size.Y / pixelDensity)) |> ignore
714+
SDL3.SDL_SetWindowSize (window, int (single size.X / pixelDensity), int (single size.Y / pixelDensity)) |> ignore<SDLBool>
715+
SDL3.SDL_SyncWindow window |> ignore<SDLBool>
717716
| None -> ()
718717

719718
let internal tryGetWindowProperties state =

0 commit comments

Comments
 (0)