Skip to content

Commit d598d13

Browse files
committed
Fix game crashing when no displays are connected
1 parent 44725d0 commit d598d13

File tree

2 files changed

+67
-11
lines changed

2 files changed

+67
-11
lines changed

osu.Framework/Platform/SDL2/SDL2Window_Windowing.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private void setupWindowing(FrameworkConfigManager config)
2727
ScheduleCommand(() => SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, e.NewValue ? "1" : "0"));
2828
}, true);
2929

30-
fetchDisplays();
30+
fetchDisplays(generateFakeDisplayIfEmpty: true);
3131

3232
DisplaysChanged += _ => CurrentDisplayBindable.Default = PrimaryDisplay;
3333
CurrentDisplayBindable.Default = PrimaryDisplay;
@@ -292,6 +292,8 @@ public WindowState WindowState
292292
// ReSharper disable once UnusedParameter.Local
293293
private void handleDisplayEvent(SDL_DisplayEvent evtDisplay) => fetchDisplays();
294294

295+
private static bool fetchDisplayModes => RuntimeInfo.IsDesktop;
296+
295297
/// <summary>
296298
/// Updates <see cref="Displays"/> with the latest display information reported by SDL.
297299
/// </summary>
@@ -300,10 +302,36 @@ public WindowState WindowState
300302
/// <see cref="currentDisplay"/> /
301303
/// <see cref="CurrentDisplayBindable"/>.
302304
/// </remarks>
303-
private void fetchDisplays()
305+
private void fetchDisplays(bool generateFakeDisplayIfEmpty = false)
304306
{
305-
Displays = getSDLDisplays();
306-
DisplaysChanged?.Invoke(Displays);
307+
var newDisplays = getSDLDisplays();
308+
309+
if (generateFakeDisplayIfEmpty && newDisplays.Length == 0)
310+
{
311+
Logger.Log("Got zero displays from SDL during startup. Generating a fake display so we have a valid one to prevent crashes.");
312+
313+
newDisplays =
314+
[
315+
new Display(0,
316+
"Fake osu!framework display",
317+
new Rectangle(0, 0, 1920, 1080),
318+
new Rectangle(0, 0, 1920, 1080),
319+
fetchDisplayModes ? [new DisplayMode("SDL_PIXELFORMAT_XRGB8888", new Size(1920, 1080), 32, 60f, 0)] : [])
320+
];
321+
}
322+
323+
if (newDisplays.Length > 0)
324+
{
325+
Displays = newDisplays;
326+
DisplaysChanged?.Invoke(newDisplays);
327+
}
328+
else
329+
{
330+
// keep Displays stale if zero displays are currently detected
331+
Logger.Log("Got zero displays from SDL, ignoring.");
332+
}
333+
334+
Debug.Assert(Displays.Length > 0);
307335
}
308336

309337
/// <summary>
@@ -328,7 +356,7 @@ private static ImmutableArray<Display> getSDLDisplays()
328356
{
329357
int numDisplays = SDL_GetNumVideoDisplays();
330358

331-
if (numDisplays <= 0)
359+
if (numDisplays < 0)
332360
throw new InvalidOperationException($"Failed to get number of SDL displays. Return code: {numDisplays}. SDL Error: {SDL_GetError()}");
333361

334362
var builder = ImmutableArray.CreateBuilder<Display>(numDisplays);
@@ -363,7 +391,7 @@ private static bool tryGetDisplayFromSDL(int displayIndex, [NotNullWhen(true)] o
363391

364392
DisplayMode[] displayModes = Array.Empty<DisplayMode>();
365393

366-
if (RuntimeInfo.IsDesktop)
394+
if (fetchDisplayModes)
367395
{
368396
int numModes = SDL_GetNumDisplayModes(displayIndex);
369397

osu.Framework/Platform/SDL3/SDL3Window_Windowing.cs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ private unsafe void setupWindowing(FrameworkConfigManager config)
2828
ScheduleCommand(() => SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, e.NewValue ? "1"u8 : "0"u8).LogErrorIfFailed());
2929
}, true);
3030

31-
fetchDisplays();
31+
fetchDisplays(generateFakeDisplayIfEmpty: true);
3232

3333
DisplaysChanged += _ => CurrentDisplayBindable.Default = PrimaryDisplay;
3434
CurrentDisplayBindable.Default = PrimaryDisplay;
@@ -296,6 +296,8 @@ public WindowState WindowState
296296
// ReSharper disable once UnusedParameter.Local
297297
private void handleDisplayEvent(SDL_DisplayEvent evtDisplay) => fetchDisplays();
298298

299+
private static bool fetchDisplayModes => RuntimeInfo.IsDesktop;
300+
299301
/// <summary>
300302
/// Updates <see cref="Displays"/> with the latest display information reported by SDL.
301303
/// </summary>
@@ -304,10 +306,36 @@ public WindowState WindowState
304306
/// <see cref="currentDisplay"/> /
305307
/// <see cref="CurrentDisplayBindable"/>.
306308
/// </remarks>
307-
private void fetchDisplays()
309+
private void fetchDisplays(bool generateFakeDisplayIfEmpty = false)
308310
{
309-
Displays = getSDLDisplays();
310-
DisplaysChanged?.Invoke(Displays);
311+
var newDisplays = getSDLDisplays();
312+
313+
if (generateFakeDisplayIfEmpty && newDisplays.Length == 0)
314+
{
315+
Logger.Log("Got zero displays from SDL during startup. Generating a fake display so we have a valid one to prevent crashes.");
316+
317+
newDisplays =
318+
[
319+
new Display(0,
320+
"Fake osu!framework display",
321+
new Rectangle(0, 0, 1920, 1080),
322+
new Rectangle(0, 0, 1920, 1080),
323+
fetchDisplayModes ? [new DisplayMode("SDL_PIXELFORMAT_XRGB8888", new Size(1920, 1080), 32, 60f, 0)] : [])
324+
];
325+
}
326+
327+
if (newDisplays.Length > 0)
328+
{
329+
Displays = newDisplays;
330+
DisplaysChanged?.Invoke(newDisplays);
331+
}
332+
else
333+
{
334+
// keep Displays stale if zero displays are currently detected
335+
Logger.Log("Got zero displays from SDL, ignoring.");
336+
}
337+
338+
Debug.Assert(Displays.Length > 0);
311339
}
312340

313341
/// <summary>
@@ -371,7 +399,7 @@ private static unsafe bool tryGetDisplayFromSDL(int displayIndex, SDL_DisplayID
371399

372400
DisplayMode[] displayModes = Array.Empty<DisplayMode>();
373401

374-
if (RuntimeInfo.IsDesktop)
402+
if (fetchDisplayModes)
375403
{
376404
using var modes = SDL_GetFullscreenDisplayModes(displayID);
377405

0 commit comments

Comments
 (0)