From 44527c1503048a8c8357a1c17a63c71631a7e48e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 18:58:33 +0900 Subject: [PATCH 01/37] Rename `CreateRenderer` to `CreateGLRenderer` and never return veldrid renderer --- osu.Framework.iOS/IOSGameHost.cs | 2 +- osu.Framework/Platform/GameHost.cs | 14 +------------- osu.Framework/Platform/OsuTKGameHost.cs | 2 +- osu.Framework/Platform/Windows/WindowsGameHost.cs | 8 +------- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/osu.Framework.iOS/IOSGameHost.cs b/osu.Framework.iOS/IOSGameHost.cs index efdd650bce..fae83e0251 100644 --- a/osu.Framework.iOS/IOSGameHost.cs +++ b/osu.Framework.iOS/IOSGameHost.cs @@ -38,7 +38,7 @@ public IOSGameHost(IOSGameView gameView) this.gameView = gameView; } - protected override IRenderer CreateRenderer() => new IOSGLRenderer(gameView); + protected override IRenderer CreateGLRenderer() => new IOSGLRenderer(gameView); protected override void SetupForRun() { diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 5d5e679b60..9342a04377 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -326,19 +326,7 @@ protected GameHost([NotNull] string gameName, [CanBeNull] HostOptions options = }; } - protected virtual IRenderer CreateRenderer() - { - switch (FrameworkEnvironment.PreferredGraphicsRenderer) - { - case "veldrid": - return new VeldridRenderer(); - - default: - case "gl": - case "opengl": - return new GLRenderer(); - } - } + protected virtual IRenderer CreateGLRenderer() => new GLRenderer(); /// /// Performs a GC collection and frees all framework caches. diff --git a/osu.Framework/Platform/OsuTKGameHost.cs b/osu.Framework/Platform/OsuTKGameHost.cs index 4c8d835d08..d0a599ff4c 100644 --- a/osu.Framework/Platform/OsuTKGameHost.cs +++ b/osu.Framework/Platform/OsuTKGameHost.cs @@ -18,7 +18,7 @@ protected OsuTKGameHost() toolkit = Toolkit.Init(); } - protected override IRenderer CreateRenderer() => new GLRenderer(); + protected override IRenderer CreateGLRenderer() => new GLRenderer(); protected override void Dispose(bool disposing) { diff --git a/osu.Framework/Platform/Windows/WindowsGameHost.cs b/osu.Framework/Platform/Windows/WindowsGameHost.cs index 18af9a9bad..8ef2cdbbad 100644 --- a/osu.Framework/Platform/Windows/WindowsGameHost.cs +++ b/osu.Framework/Platform/Windows/WindowsGameHost.cs @@ -65,13 +65,7 @@ protected override IEnumerable CreateAvailableInputHandlers() .Concat(new InputHandler[] { new WindowsMouseHandler() }); } - protected override IRenderer CreateRenderer() - { - if (FrameworkEnvironment.PreferredGraphicsRenderer != null || FrameworkEnvironment.PreferredGraphicsSurface != null) - return base.CreateRenderer(); - - return new WindowsGLRenderer(this); - } + protected override IRenderer CreateGLRenderer() => new WindowsGLRenderer(this); protected override void SetupForRun() { From 471770f51ca84050ce96d6048bd864410e28839e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 18:59:45 +0900 Subject: [PATCH 02/37] Add renderer configuration setting --- .../Configuration/FrameworkConfigManager.cs | 2 ++ osu.Framework/Configuration/Renderer.cs | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 osu.Framework/Configuration/Renderer.cs diff --git a/osu.Framework/Configuration/FrameworkConfigManager.cs b/osu.Framework/Configuration/FrameworkConfigManager.cs index 1935204e02..b39a51171b 100644 --- a/osu.Framework/Configuration/FrameworkConfigManager.cs +++ b/osu.Framework/Configuration/FrameworkConfigManager.cs @@ -39,6 +39,7 @@ protected override void InitialiseDefaults() SetDefault(FrameworkSetting.SizeFullscreen, new Size(9999, 9999), new Size(320, 240)); SetDefault(FrameworkSetting.FrameSync, FrameSync.Limit2x); SetDefault(FrameworkSetting.WindowMode, WindowMode.Windowed); + SetDefault(FrameworkSetting.Renderer, Renderer.Automatic); SetDefault(FrameworkSetting.ShowUnicode, false); SetDefault(FrameworkSetting.Locale, string.Empty); @@ -90,6 +91,7 @@ public enum FrameworkSetting SizeFullscreen, + Renderer, WindowMode, ConfineMouseMode, FrameSync, diff --git a/osu.Framework/Configuration/Renderer.cs b/osu.Framework/Configuration/Renderer.cs new file mode 100644 index 0000000000..e5a88f7a21 --- /dev/null +++ b/osu.Framework/Configuration/Renderer.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Framework.Configuration +{ + public enum Renderer + { + [Description("Automatic")] + Automatic, + + [Description("Metal")] + Metal, + + [Description("Vulkan")] + Vulkan, + + [Description("Direct3D 11")] + Direct3D11, + + [Description("OpenGL")] + OpenGL, + + [Description("OpenGL (Legacy)")] + Legacy, + } +} From 864403ea74c72c4af99fe78f1a804b02a5fa9dce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 19:03:07 +0900 Subject: [PATCH 03/37] Restructure renderer / window construction to allow reading from the config --- osu.Framework/Platform/GameHost.cs | 98 +++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 9342a04377..416b46e599 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -668,8 +668,6 @@ public void Run(Game game) if (ExecutionState != ExecutionState.Idle) throw new InvalidOperationException("A game that has already been run cannot be restarted."); - Renderer = CreateRenderer(); - try { if (!host_running_mutex.Wait(10000)) @@ -689,13 +687,6 @@ public void Run(Game game) Monitor = { HandleGC = true }, }); - GraphicsSurfaceType surfaceType = FrameworkEnvironment.PreferredGraphicsSurface ?? GraphicsSurfaceType.OpenGL; - - Logger.Log("Using renderer: " + Renderer.GetType().ReadableName()); - Logger.Log("Using graphics surface: " + surfaceType); - - RegisterThread(DrawThread = new DrawThread(DrawFrame, this, $"{Renderer.GetType().ReadableName().Replace("Renderer", "")} / {surfaceType}")); - Trace.Listeners.Clear(); Trace.Listeners.Add(new ThrowingTraceListener()); @@ -706,34 +697,65 @@ public void Run(Game game) Dependencies.CacheAs(this); Dependencies.CacheAs(Storage = game.CreateStorage(this, GetDefaultGameStorage())); - Dependencies.CacheAs(Renderer); CacheStorage = GetDefaultGameStorage().GetStorageForDirectory("cache"); SetupForRun(); - Window = CreateWindow(surfaceType); - populateInputHandlers(); SetupConfig(game.GetFrameworkConfigDefaults() ?? new Dictionary()); - initialiseInputHandlers(); - - if (Window != null) + // Always give preference to environment variables. + if (FrameworkEnvironment.PreferredGraphicsSurface != null || FrameworkEnvironment.PreferredGraphicsRenderer != null) { - Window.SetupWindow(Config); + // And allow this to hard fail with no fallbacks. + setupRendererAndWindow( + FrameworkEnvironment.PreferredGraphicsRenderer ?? "veldrid", + FrameworkEnvironment.PreferredGraphicsSurface ?? GraphicsSurfaceType.OpenGL); + } + else + { + string renderer; + GraphicsSurfaceType surfaceType; - Window.Create(); - Window.Title = $@"osu!framework (running ""{Name}"")"; + switch (Config.Get(FrameworkSetting.Renderer)) + { + case Configuration.Renderer.Metal: + renderer = "veldrid"; + surfaceType = GraphicsSurfaceType.Metal; + break; + + case Configuration.Renderer.Vulkan: + renderer = "veldrid"; + surfaceType = GraphicsSurfaceType.Vulkan; + break; + + case Configuration.Renderer.Direct3D11: + renderer = "veldrid"; + surfaceType = GraphicsSurfaceType.Direct3D11; + break; + + case Configuration.Renderer.OpenGL: + renderer = "veldrid"; + surfaceType = GraphicsSurfaceType.OpenGL; + break; + + default: + case Configuration.Renderer.Automatic: + case Configuration.Renderer.Legacy: + renderer = "gl"; + surfaceType = GraphicsSurfaceType.OpenGL; + break; + } - Renderer.Initialise(Window.GraphicsSurface); + setupRendererAndWindow(renderer, surfaceType); + } - currentDisplayMode = Window.CurrentDisplayMode.GetBoundCopy(); - currentDisplayMode.BindValueChanged(_ => updateFrameSyncMode()); + // Prepare renderer (requires config). + Dependencies.CacheAs(Renderer); - IsActive.BindTo(Window.IsActive); - } + RegisterThread(DrawThread = new DrawThread(DrawFrame, this, $"{Renderer.GetType().ReadableName().Replace("Renderer", "")} / {Window.GraphicsSurface.Type}")); Dependencies.CacheAs(readableKeyCombinationProvider = CreateReadableKeyCombinationProvider()); Dependencies.CacheAs(CreateTextInput()); @@ -802,6 +824,36 @@ public void Run(Game game) } } + private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) + { + Renderer = renderer == "veldrid" + ? new VeldridRenderer() + : CreateLegacyRenderer(); + + Logger.Log("Using renderer: " + Renderer.GetType().ReadableName()); + Logger.Log("Using graphics surface: " + surfaceType); + + // Prepare window + Window = CreateWindow(surfaceType); + + initialiseInputHandlers(); + + if (Window != null) + { + Window.SetupWindow(Config); + + Window.Create(); + Window.Title = $@"osu!framework (running ""{Name}"")"; + + Renderer.Initialise(Window.GraphicsSurface); + + currentDisplayMode = Window.CurrentDisplayMode.GetBoundCopy(); + currentDisplayMode.BindValueChanged(_ => updateFrameSyncMode()); + + IsActive.BindTo(Window.IsActive); + } + } + /// /// Finds the default for the game to be used if is not overridden. /// From 5283911cf016f27a9569f093c558421c4ba78280 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 19:07:13 +0900 Subject: [PATCH 04/37] Add basic fallback step This will handle the case where the user has chosen a renderer which will not work with their system. --- osu.Framework/Platform/GameHost.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 416b46e599..0a608f7e2e 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -749,7 +749,16 @@ public void Run(Game game) break; } - setupRendererAndWindow(renderer, surfaceType); + try + { + setupRendererAndWindow(renderer, surfaceType); + } + catch + { + // fallback to legacy renderer. + setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Legacy); + } } // Prepare renderer (requires config). From 4a5d2b1c4817640e7d64b03fbfb3c8cbea6b6175 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 19:24:40 +0900 Subject: [PATCH 05/37] Move renderer selection to own method and add per-platform fallback logic --- osu.Framework/Platform/GameHost.cs | 142 +++++++++++++++++------------ 1 file changed, 84 insertions(+), 58 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 0a608f7e2e..dfe0824cbc 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -706,60 +706,7 @@ public void Run(Game game) SetupConfig(game.GetFrameworkConfigDefaults() ?? new Dictionary()); - // Always give preference to environment variables. - if (FrameworkEnvironment.PreferredGraphicsSurface != null || FrameworkEnvironment.PreferredGraphicsRenderer != null) - { - // And allow this to hard fail with no fallbacks. - setupRendererAndWindow( - FrameworkEnvironment.PreferredGraphicsRenderer ?? "veldrid", - FrameworkEnvironment.PreferredGraphicsSurface ?? GraphicsSurfaceType.OpenGL); - } - else - { - string renderer; - GraphicsSurfaceType surfaceType; - - switch (Config.Get(FrameworkSetting.Renderer)) - { - case Configuration.Renderer.Metal: - renderer = "veldrid"; - surfaceType = GraphicsSurfaceType.Metal; - break; - - case Configuration.Renderer.Vulkan: - renderer = "veldrid"; - surfaceType = GraphicsSurfaceType.Vulkan; - break; - - case Configuration.Renderer.Direct3D11: - renderer = "veldrid"; - surfaceType = GraphicsSurfaceType.Direct3D11; - break; - - case Configuration.Renderer.OpenGL: - renderer = "veldrid"; - surfaceType = GraphicsSurfaceType.OpenGL; - break; - - default: - case Configuration.Renderer.Automatic: - case Configuration.Renderer.Legacy: - renderer = "gl"; - surfaceType = GraphicsSurfaceType.OpenGL; - break; - } - - try - { - setupRendererAndWindow(renderer, surfaceType); - } - catch - { - // fallback to legacy renderer. - setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); - Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Legacy); - } - } + chooseAndSetupRenderer(); // Prepare renderer (requires config). Dependencies.CacheAs(Renderer); @@ -833,14 +780,93 @@ public void Run(Game game) } } + private void chooseAndSetupRenderer() + { + // Always give preference to environment variables. + if (FrameworkEnvironment.PreferredGraphicsSurface != null || FrameworkEnvironment.PreferredGraphicsRenderer != null) + { + // And allow this to hard fail with no fallbacks. + setupRendererAndWindow( + FrameworkEnvironment.PreferredGraphicsRenderer ?? "veldrid", + FrameworkEnvironment.PreferredGraphicsSurface ?? GraphicsSurfaceType.OpenGL); + } + else + { + List attemptSurfaceTypes = new List(); + bool attemptOperatingSystemSpecificFallbacks = true; + + switch (Config.Get(FrameworkSetting.Renderer)) + { + case Configuration.Renderer.Metal: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); + break; + + case Configuration.Renderer.Vulkan: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); + break; + + case Configuration.Renderer.Direct3D11: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); + break; + + case Configuration.Renderer.OpenGL: + attemptSurfaceTypes.Add(GraphicsSurfaceType.OpenGL); + break; + + case Configuration.Renderer.Legacy: + attemptOperatingSystemSpecificFallbacks = false; + break; + } + + if (attemptOperatingSystemSpecificFallbacks) + { + // Best case, we can make use of veldrid with a new graphics API. + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); + attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); + break; + + case RuntimeInfo.Platform.Linux: + case RuntimeInfo.Platform.Android: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); + break; + + case RuntimeInfo.Platform.macOS: + case RuntimeInfo.Platform.iOS: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); + break; + } + } + + foreach (var attemptSurfaceType in attemptSurfaceTypes) + { + try + { + setupRendererAndWindow("veldrid", attemptSurfaceType); + return; + } + catch + { + // If we fail, assume the user may have had a custom setting and switch it back to automatic. + Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Automatic); + } + } + + // fallback to legacy renderer. this is basically guaranteed to support all platforms. + setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Legacy); + } + } + private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) { + Logger.Log($"Attempting initialisation using renderer: {renderer} surface: {surfaceType}"); + Renderer = renderer == "veldrid" ? new VeldridRenderer() - : CreateLegacyRenderer(); - - Logger.Log("Using renderer: " + Renderer.GetType().ReadableName()); - Logger.Log("Using graphics surface: " + surfaceType); + : CreateGLRenderer(); // Prepare window Window = CreateWindow(surfaceType); From 05e1d15d98e32793bb66aa37e604c50b44abad95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 19:33:21 +0900 Subject: [PATCH 06/37] Add more logging and avoid duplicate attempts of same surface type --- osu.Framework/Platform/GameHost.cs | 157 +++++++++++++++++------------ 1 file changed, 90 insertions(+), 67 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index dfe0824cbc..f1412e7a33 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -785,107 +785,130 @@ private void chooseAndSetupRenderer() // Always give preference to environment variables. if (FrameworkEnvironment.PreferredGraphicsSurface != null || FrameworkEnvironment.PreferredGraphicsRenderer != null) { + Logger.Log("🖼️ Using environment variables for renderer and surface selection.", level: LogLevel.Important); + // And allow this to hard fail with no fallbacks. setupRendererAndWindow( FrameworkEnvironment.PreferredGraphicsRenderer ?? "veldrid", FrameworkEnvironment.PreferredGraphicsSurface ?? GraphicsSurfaceType.OpenGL); + return; } - else + + List attemptSurfaceTypes = new List(); + bool attemptOperatingSystemSpecificFallbacks = true; + + var configRenderer = Config.Get(FrameworkSetting.Renderer); + Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); + + switch (configRenderer) { - List attemptSurfaceTypes = new List(); - bool attemptOperatingSystemSpecificFallbacks = true; + case Configuration.Renderer.Metal: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); + break; - switch (Config.Get(FrameworkSetting.Renderer)) - { - case Configuration.Renderer.Metal: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); - break; + case Configuration.Renderer.Vulkan: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); + break; - case Configuration.Renderer.Vulkan: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); - break; + case Configuration.Renderer.Direct3D11: + attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); + break; + + case Configuration.Renderer.OpenGL: + attemptSurfaceTypes.Add(GraphicsSurfaceType.OpenGL); + break; + + case Configuration.Renderer.Legacy: + attemptOperatingSystemSpecificFallbacks = false; + break; + } - case Configuration.Renderer.Direct3D11: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); + if (attemptOperatingSystemSpecificFallbacks) + { + // Best case, we can make use of veldrid with a new graphics API. + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + addFallback(GraphicsSurfaceType.Vulkan); + addFallback(GraphicsSurfaceType.Direct3D11); break; - case Configuration.Renderer.OpenGL: - attemptSurfaceTypes.Add(GraphicsSurfaceType.OpenGL); + case RuntimeInfo.Platform.Linux: + case RuntimeInfo.Platform.Android: + addFallback(GraphicsSurfaceType.Vulkan); break; - case Configuration.Renderer.Legacy: - attemptOperatingSystemSpecificFallbacks = false; + case RuntimeInfo.Platform.macOS: + case RuntimeInfo.Platform.iOS: + addFallback(GraphicsSurfaceType.Metal); break; } - if (attemptOperatingSystemSpecificFallbacks) + void addFallback(GraphicsSurfaceType surface) { - // Best case, we can make use of veldrid with a new graphics API. - switch (RuntimeInfo.OS) - { - case RuntimeInfo.Platform.Windows: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); - attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); - break; - - case RuntimeInfo.Platform.Linux: - case RuntimeInfo.Platform.Android: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); - break; - - case RuntimeInfo.Platform.macOS: - case RuntimeInfo.Platform.iOS: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); - break; - } + if (!attemptSurfaceTypes.Contains(surface)) + attemptSurfaceTypes.Add(surface); } + } - foreach (var attemptSurfaceType in attemptSurfaceTypes) + Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", attemptSurfaceTypes.Select(e => e.ToString()).Append("Legacy"))} ]"); + + foreach (var attemptSurfaceType in attemptSurfaceTypes) + { + try { - try - { - setupRendererAndWindow("veldrid", attemptSurfaceType); - return; - } - catch - { - // If we fail, assume the user may have had a custom setting and switch it back to automatic. - Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Automatic); - } + setupRendererAndWindow("veldrid", attemptSurfaceType); + return; + } + catch + { + // If we fail, assume the user may have had a custom setting and switch it back to automatic. + Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Automatic); } - - // fallback to legacy renderer. this is basically guaranteed to support all platforms. - setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); - Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Legacy); } + + // fallback to legacy renderer. this is basically guaranteed to support all platforms. + setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Legacy); } private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) { - Logger.Log($"Attempting initialisation using renderer: {renderer} surface: {surfaceType}"); + Logger.Log($"🖼️ Attempting initialisation using renderer: {renderer} surface: {surfaceType}"); - Renderer = renderer == "veldrid" - ? new VeldridRenderer() - : CreateGLRenderer(); + try + { + Renderer = renderer == "veldrid" + ? new VeldridRenderer() + : CreateGLRenderer(); - // Prepare window - Window = CreateWindow(surfaceType); + // Prepare window + Window = CreateWindow(surfaceType); - initialiseInputHandlers(); + initialiseInputHandlers(); - if (Window != null) - { - Window.SetupWindow(Config); + if (Window != null) + { + Window.SetupWindow(Config); + + Window.Create(); + Window.Title = $@"osu!framework (running ""{Name}"")"; - Window.Create(); - Window.Title = $@"osu!framework (running ""{Name}"")"; + Renderer.Initialise(Window.GraphicsSurface); - Renderer.Initialise(Window.GraphicsSurface); + currentDisplayMode = Window.CurrentDisplayMode.GetBoundCopy(); + currentDisplayMode.BindValueChanged(_ => updateFrameSyncMode()); - currentDisplayMode = Window.CurrentDisplayMode.GetBoundCopy(); - currentDisplayMode.BindValueChanged(_ => updateFrameSyncMode()); + IsActive.BindTo(Window.IsActive); + } - IsActive.BindTo(Window.IsActive); + Logger.Log("🖼️ Renderer initialised!"); + } + catch (Exception e) + { + Logger.Log("🖼️ Renderer initialisation failed with:"); + Logger.Log(e.ToString()); + throw; } } From 2abce46c10cfb7abe90f71ff7259830f1416cd86 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 19:35:48 +0900 Subject: [PATCH 07/37] Move out input handler initialisation from window setup function --- osu.Framework/Platform/GameHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index f1412e7a33..72b04f0f10 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -708,6 +708,8 @@ public void Run(Game game) chooseAndSetupRenderer(); + initialiseInputHandlers(); + // Prepare renderer (requires config). Dependencies.CacheAs(Renderer); @@ -885,8 +887,6 @@ private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surface // Prepare window Window = CreateWindow(surfaceType); - initialiseInputHandlers(); - if (Window != null) { Window.SetupWindow(Config); From 684d339371fa95d158ff203013372567a137c176 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 20:01:27 +0900 Subject: [PATCH 08/37] Ensure any unsuccessful initialisation attempts destroy the associated window --- osu.Framework/Platform/GameHost.cs | 3 +++ osu.Framework/Platform/SDL2DesktopWindow.cs | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 72b04f0f10..0de4763ed9 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -908,6 +908,9 @@ private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surface { Logger.Log("🖼️ Renderer initialisation failed with:"); Logger.Log(e.ToString()); + + Window?.Close(); + Window = null; throw; } } diff --git a/osu.Framework/Platform/SDL2DesktopWindow.cs b/osu.Framework/Platform/SDL2DesktopWindow.cs index 18f167ddf4..6ac7a1232b 100644 --- a/osu.Framework/Platform/SDL2DesktopWindow.cs +++ b/osu.Framework/Platform/SDL2DesktopWindow.cs @@ -303,7 +303,11 @@ public void OnDraw() /// /// Forcefully closes the window. /// - public void Close() => ScheduleCommand(() => Exists = false); + public void Close() => ScheduleCommand(() => + { + SDL.SDL_DestroyWindow(SDLWindowHandle); + Exists = false; + }); public void Raise() => ScheduleCommand(() => { From c913ba83717c313124402286bb79ae39b64c7aff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 20:06:31 +0900 Subject: [PATCH 09/37] Fix early access to `DrawThread` causing test failures --- osu.Framework/Platform/GameHost.cs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 0de4763ed9..1eab6c5da0 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -275,9 +275,16 @@ public double MaximumUpdateHz public double MaximumDrawHz { get => maximumDrawHz; - set => DrawThread.ActiveHz = maximumDrawHz = value; + set + { + maximumDrawHz = value; + if (DrawThread != null) + DrawThread.ActiveHz = maximumDrawHz; + } } + private double maximumInactiveHz; + /// /// The target number of updates per second when the game window is inactive. /// This is applied to all threads. @@ -287,11 +294,12 @@ public double MaximumDrawHz /// public double MaximumInactiveHz { - get => DrawThread.InactiveHz; + get => maximumInactiveHz; set { - DrawThread.InactiveHz = value; - threadRunner.MaximumInactiveHz = UpdateThread.InactiveHz = value; + maximumInactiveHz = threadRunner.MaximumInactiveHz = UpdateThread.InactiveHz = value; + if (DrawThread != null) + DrawThread.InactiveHz = maximumInactiveHz; } } @@ -713,7 +721,11 @@ public void Run(Game game) // Prepare renderer (requires config). Dependencies.CacheAs(Renderer); - RegisterThread(DrawThread = new DrawThread(DrawFrame, this, $"{Renderer.GetType().ReadableName().Replace("Renderer", "")} / {Window.GraphicsSurface.Type}")); + RegisterThread(DrawThread = new DrawThread(DrawFrame, this, $"{Renderer.GetType().ReadableName().Replace("Renderer", "")} / {(Window?.GraphicsSurface.Type.ToString() ?? "headless")}") + { + ActiveHz = maximumDrawHz, + InactiveHz = MaximumInactiveHz, + }); Dependencies.CacheAs(readableKeyCombinationProvider = CreateReadableKeyCombinationProvider()); Dependencies.CacheAs(CreateTextInput()); From 145ba9a8fca59b67ac676200c1d8f994d62fae8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 20:07:01 +0900 Subject: [PATCH 10/37] Rename `Legacy` to `OpenGLLegacy` --- osu.Framework/Configuration/Renderer.cs | 2 +- osu.Framework/Platform/GameHost.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Configuration/Renderer.cs b/osu.Framework/Configuration/Renderer.cs index e5a88f7a21..c9aad75929 100644 --- a/osu.Framework/Configuration/Renderer.cs +++ b/osu.Framework/Configuration/Renderer.cs @@ -23,6 +23,6 @@ public enum Renderer OpenGL, [Description("OpenGL (Legacy)")] - Legacy, + OpenGLLegacy, } } diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 1eab6c5da0..972e2f7998 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -832,7 +832,7 @@ private void chooseAndSetupRenderer() attemptSurfaceTypes.Add(GraphicsSurfaceType.OpenGL); break; - case Configuration.Renderer.Legacy: + case Configuration.Renderer.OpenGLLegacy: attemptOperatingSystemSpecificFallbacks = false; break; } @@ -883,7 +883,7 @@ void addFallback(GraphicsSurfaceType surface) // fallback to legacy renderer. this is basically guaranteed to support all platforms. setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); - Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Legacy); + Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.OpenGLLegacy); } private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) From e90a35b2009a3d9c5bb9f6c7a8932a6105fa8d57 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2023 20:14:01 +0900 Subject: [PATCH 11/37] Fix headless tests failing due to attempting to use the veldrid renderer --- osu.Framework/Platform/GameHost.cs | 12 ++++++------ osu.Framework/Platform/HeadlessGameHost.cs | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 972e2f7998..23e524d7d3 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -714,7 +714,7 @@ public void Run(Game game) SetupConfig(game.GetFrameworkConfigDefaults() ?? new Dictionary()); - chooseAndSetupRenderer(); + ChooseAndSetupRenderer(); initialiseInputHandlers(); @@ -794,7 +794,7 @@ public void Run(Game game) } } - private void chooseAndSetupRenderer() + protected virtual void ChooseAndSetupRenderer() { // Always give preference to environment variables. if (FrameworkEnvironment.PreferredGraphicsSurface != null || FrameworkEnvironment.PreferredGraphicsRenderer != null) @@ -802,7 +802,7 @@ private void chooseAndSetupRenderer() Logger.Log("🖼️ Using environment variables for renderer and surface selection.", level: LogLevel.Important); // And allow this to hard fail with no fallbacks. - setupRendererAndWindow( + SetupRendererAndWindow( FrameworkEnvironment.PreferredGraphicsRenderer ?? "veldrid", FrameworkEnvironment.PreferredGraphicsSurface ?? GraphicsSurfaceType.OpenGL); return; @@ -871,7 +871,7 @@ void addFallback(GraphicsSurfaceType surface) { try { - setupRendererAndWindow("veldrid", attemptSurfaceType); + SetupRendererAndWindow("veldrid", attemptSurfaceType); return; } catch @@ -882,11 +882,11 @@ void addFallback(GraphicsSurfaceType surface) } // fallback to legacy renderer. this is basically guaranteed to support all platforms. - setupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.OpenGLLegacy); } - private void setupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) + protected void SetupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) { Logger.Log($"🖼️ Attempting initialisation using renderer: {renderer} surface: {surfaceType}"); diff --git a/osu.Framework/Platform/HeadlessGameHost.cs b/osu.Framework/Platform/HeadlessGameHost.cs index 560b593fa5..0dbc7a5d6c 100644 --- a/osu.Framework/Platform/HeadlessGameHost.cs +++ b/osu.Framework/Platform/HeadlessGameHost.cs @@ -46,6 +46,8 @@ public HeadlessGameHost(string gameName = null, HostOptions options = null, bool this.realtime = realtime; } + protected override void ChooseAndSetupRenderer() => SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + protected override void SetupConfig(IDictionary defaultOverrides) { defaultOverrides[FrameworkSetting.AudioDevice] = "No sound"; From 5c0ec9e7f444fbdfe14147cbda2bf78a8673599b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 08:44:02 +0300 Subject: [PATCH 12/37] Rename configuration enum to not conflict with `Renderer` class --- .../Configuration/FrameworkConfigManager.cs | 2 +- .../{Renderer.cs => RendererType.cs} | 2 +- osu.Framework/Platform/GameHost.cs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) rename osu.Framework/Configuration/{Renderer.cs => RendererType.cs} (95%) diff --git a/osu.Framework/Configuration/FrameworkConfigManager.cs b/osu.Framework/Configuration/FrameworkConfigManager.cs index b39a51171b..c8498c53ae 100644 --- a/osu.Framework/Configuration/FrameworkConfigManager.cs +++ b/osu.Framework/Configuration/FrameworkConfigManager.cs @@ -39,7 +39,7 @@ protected override void InitialiseDefaults() SetDefault(FrameworkSetting.SizeFullscreen, new Size(9999, 9999), new Size(320, 240)); SetDefault(FrameworkSetting.FrameSync, FrameSync.Limit2x); SetDefault(FrameworkSetting.WindowMode, WindowMode.Windowed); - SetDefault(FrameworkSetting.Renderer, Renderer.Automatic); + SetDefault(FrameworkSetting.Renderer, RendererType.Automatic); SetDefault(FrameworkSetting.ShowUnicode, false); SetDefault(FrameworkSetting.Locale, string.Empty); diff --git a/osu.Framework/Configuration/Renderer.cs b/osu.Framework/Configuration/RendererType.cs similarity index 95% rename from osu.Framework/Configuration/Renderer.cs rename to osu.Framework/Configuration/RendererType.cs index c9aad75929..bd028b074d 100644 --- a/osu.Framework/Configuration/Renderer.cs +++ b/osu.Framework/Configuration/RendererType.cs @@ -5,7 +5,7 @@ namespace osu.Framework.Configuration { - public enum Renderer + public enum RendererType { [Description("Automatic")] Automatic, diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 23e524d7d3..e3eb19de18 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -811,28 +811,28 @@ protected virtual void ChooseAndSetupRenderer() List attemptSurfaceTypes = new List(); bool attemptOperatingSystemSpecificFallbacks = true; - var configRenderer = Config.Get(FrameworkSetting.Renderer); + var configRenderer = Config.Get(FrameworkSetting.Renderer); Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); switch (configRenderer) { - case Configuration.Renderer.Metal: + case RendererType.Metal: attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); break; - case Configuration.Renderer.Vulkan: + case RendererType.Vulkan: attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); break; - case Configuration.Renderer.Direct3D11: + case RendererType.Direct3D11: attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); break; - case Configuration.Renderer.OpenGL: + case RendererType.OpenGL: attemptSurfaceTypes.Add(GraphicsSurfaceType.OpenGL); break; - case Configuration.Renderer.OpenGLLegacy: + case RendererType.OpenGLLegacy: attemptOperatingSystemSpecificFallbacks = false; break; } @@ -877,13 +877,13 @@ void addFallback(GraphicsSurfaceType surface) catch { // If we fail, assume the user may have had a custom setting and switch it back to automatic. - Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.Automatic); + Config.SetValue(FrameworkSetting.Renderer, RendererType.Automatic); } } // fallback to legacy renderer. this is basically guaranteed to support all platforms. SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); - Config.SetValue(FrameworkSetting.Renderer, Configuration.Renderer.OpenGLLegacy); + Config.SetValue(FrameworkSetting.Renderer, RendererType.OpenGLLegacy); } protected void SetupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) From a10e2eeb40fa83b06862f94cb8570e2417e2d5d9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 08:47:34 +0300 Subject: [PATCH 13/37] Allow `GameHost` subclasses to use custom renderer implementations --- osu.Framework/Platform/GameHost.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index e3eb19de18..0db61c66da 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -887,14 +887,27 @@ void addFallback(GraphicsSurfaceType surface) } protected void SetupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) + { + switch (renderer) + { + case "veldrid": + SetupRendererAndWindow(new VeldridRenderer(), surfaceType); + break; + + default: + case "gl": + SetupRendererAndWindow(CreateGLRenderer(), surfaceType); + break; + } + } + + protected void SetupRendererAndWindow(IRenderer renderer, GraphicsSurfaceType surfaceType) { Logger.Log($"🖼️ Attempting initialisation using renderer: {renderer} surface: {surfaceType}"); try { - Renderer = renderer == "veldrid" - ? new VeldridRenderer() - : CreateGLRenderer(); + Renderer = renderer; // Prepare window Window = CreateWindow(surfaceType); From 2861dca65a29f388ca4680f8b7ff558111940b1f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 08:52:15 +0300 Subject: [PATCH 14/37] Reword initialisation log message --- osu.Framework/Platform/GameHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 0db61c66da..2af2c670b4 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -903,7 +903,7 @@ protected void SetupRendererAndWindow(string renderer, GraphicsSurfaceType surfa protected void SetupRendererAndWindow(IRenderer renderer, GraphicsSurfaceType surfaceType) { - Logger.Log($"🖼️ Attempting initialisation using renderer: {renderer} surface: {surfaceType}"); + Logger.Log($"🖼️ Initialising \"{renderer.GetType().ReadableName().Replace("Renderer", "")}\" renderer with \"{surfaceType}\" surface"); try { From eac4660490d79e0b377a1f41dc1cc80767404e37 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 08:56:31 +0300 Subject: [PATCH 15/37] Keep try-catch limited to the phase of window/renderer initialisation --- osu.Framework/Platform/GameHost.cs | 37 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 2af2c670b4..255e916c9b 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -905,27 +905,25 @@ protected void SetupRendererAndWindow(IRenderer renderer, GraphicsSurfaceType su { Logger.Log($"🖼️ Initialising \"{renderer.GetType().ReadableName().Replace("Renderer", "")}\" renderer with \"{surfaceType}\" surface"); - try - { - Renderer = renderer; + Renderer = renderer; - // Prepare window - Window = CreateWindow(surfaceType); - - if (Window != null) - { - Window.SetupWindow(Config); + // Prepare window + Window = CreateWindow(surfaceType); - Window.Create(); - Window.Title = $@"osu!framework (running ""{Name}"")"; + if (Window == null) + { + Logger.Log("🖼️ Renderer could not be initialised, no window exists."); + return; + } - Renderer.Initialise(Window.GraphicsSurface); + Window.SetupWindow(Config); - currentDisplayMode = Window.CurrentDisplayMode.GetBoundCopy(); - currentDisplayMode.BindValueChanged(_ => updateFrameSyncMode()); + try + { + Window.Create(); + Window.Title = $@"osu!framework (running ""{Name}"")"; - IsActive.BindTo(Window.IsActive); - } + Renderer.Initialise(Window.GraphicsSurface); Logger.Log("🖼️ Renderer initialised!"); } @@ -936,8 +934,15 @@ protected void SetupRendererAndWindow(IRenderer renderer, GraphicsSurfaceType su Window?.Close(); Window = null; + + Renderer = null; throw; } + + currentDisplayMode = Window.CurrentDisplayMode.GetBoundCopy(); + currentDisplayMode.BindValueChanged(_ => updateFrameSyncMode()); + + IsActive.BindTo(Window.IsActive); } /// From 8d863d15a671e5f7b6e66963c2a76635d86326eb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 09:09:53 +0300 Subject: [PATCH 16/37] Update fallback order log --- osu.Framework/Platform/GameHost.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 255e916c9b..b41192b308 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -23,6 +23,7 @@ using osu.Framework.Bindables; using osu.Framework.Configuration; using osu.Framework.Development; +using osu.Framework.Extensions; using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.TypeExtensions; @@ -865,7 +866,7 @@ void addFallback(GraphicsSurfaceType surface) } } - Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", attemptSurfaceTypes.Select(e => e.ToString()).Append("Legacy"))} ]"); + Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", attemptSurfaceTypes.Select(e => e.GetDescription()).Append("OpenGL (Legacy)"))} ]"); foreach (var attemptSurfaceType in attemptSurfaceTypes) { From b34820559eca81b89ae876e98a7f164b5a6723cb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 09:25:58 +0300 Subject: [PATCH 17/37] Fix maximum inactive fps for draw thread not correct --- osu.Framework/Platform/GameHost.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index b41192b308..df5447d05e 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -251,7 +251,7 @@ public void UnregisterThread(GameThread thread) public InputThread InputThread { get; private set; } public AudioThread AudioThread { get; private set; } - private double maximumUpdateHz; + private double maximumUpdateHz = GameThread.DEFAULT_ACTIVE_HZ; /// /// The target number of update frames per second when the game window is active. @@ -265,7 +265,7 @@ public double MaximumUpdateHz set => threadRunner.MaximumUpdateHz = UpdateThread.ActiveHz = maximumUpdateHz = value; } - private double maximumDrawHz; + private double maximumDrawHz = GameThread.DEFAULT_ACTIVE_HZ; /// /// The target number of draw frames per second when the game window is active. @@ -284,7 +284,7 @@ public double MaximumDrawHz } } - private double maximumInactiveHz; + private double maximumInactiveHz = GameThread.DEFAULT_INACTIVE_HZ; /// /// The target number of updates per second when the game window is inactive. @@ -298,7 +298,7 @@ public double MaximumInactiveHz get => maximumInactiveHz; set { - maximumInactiveHz = threadRunner.MaximumInactiveHz = UpdateThread.InactiveHz = value; + threadRunner.MaximumInactiveHz = UpdateThread.InactiveHz = maximumInactiveHz = value; if (DrawThread != null) DrawThread.InactiveHz = maximumInactiveHz; } @@ -724,7 +724,7 @@ public void Run(Game game) RegisterThread(DrawThread = new DrawThread(DrawFrame, this, $"{Renderer.GetType().ReadableName().Replace("Renderer", "")} / {(Window?.GraphicsSurface.Type.ToString() ?? "headless")}") { - ActiveHz = maximumDrawHz, + ActiveHz = MaximumDrawHz, InactiveHz = MaximumInactiveHz, }); From 9dcc5be717690402d9315ac28ac6403ddc31761a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Mar 2023 09:45:05 +0300 Subject: [PATCH 18/37] Move window and SDL destruction to disposal --- osu.Framework/Platform/GameHost.cs | 1 + osu.Framework/Platform/SDL2DesktopWindow.cs | 15 +++++---------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index df5447d05e..9b0d8c5d22 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -934,6 +934,7 @@ protected void SetupRendererAndWindow(IRenderer renderer, GraphicsSurfaceType su Logger.Log(e.ToString()); Window?.Close(); + Window?.Dispose(); Window = null; Renderer = null; diff --git a/osu.Framework/Platform/SDL2DesktopWindow.cs b/osu.Framework/Platform/SDL2DesktopWindow.cs index 6ac7a1232b..deda6e1cca 100644 --- a/osu.Framework/Platform/SDL2DesktopWindow.cs +++ b/osu.Framework/Platform/SDL2DesktopWindow.cs @@ -282,11 +282,6 @@ public void Run() } Exited?.Invoke(); - - if (SDLWindowHandle != IntPtr.Zero) - SDL.SDL_DestroyWindow(SDLWindowHandle); - - SDL.SDL_Quit(); } private bool firstDraw = true; @@ -303,11 +298,7 @@ public void OnDraw() /// /// Forcefully closes the window. /// - public void Close() => ScheduleCommand(() => - { - SDL.SDL_DestroyWindow(SDLWindowHandle); - Exists = false; - }); + public void Close() => ScheduleCommand(() => Exists = false); public void Raise() => ScheduleCommand(() => { @@ -534,6 +525,10 @@ internal virtual void SetIconFromGroup(IconGroup iconGroup) public void Dispose() { + if (SDLWindowHandle != IntPtr.Zero) + SDL.SDL_DestroyWindow(SDLWindowHandle); + + SDL.SDL_Quit(); } } } From 586009e0f2bc52e626398b99ee239bbba733f14d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2023 16:02:10 +0900 Subject: [PATCH 19/37] Add quit/close back to run method --- osu.Framework/Platform/SDL2DesktopWindow.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Framework/Platform/SDL2DesktopWindow.cs b/osu.Framework/Platform/SDL2DesktopWindow.cs index deda6e1cca..870006ca1b 100644 --- a/osu.Framework/Platform/SDL2DesktopWindow.cs +++ b/osu.Framework/Platform/SDL2DesktopWindow.cs @@ -282,6 +282,9 @@ public void Run() } Exited?.Invoke(); + + Close(); + SDL.SDL_Quit(); } private bool firstDraw = true; @@ -298,7 +301,16 @@ public void OnDraw() /// /// Forcefully closes the window. /// - public void Close() => ScheduleCommand(() => Exists = false); + public void Close() => ScheduleCommand(() => + { + Exists = false; + + if (SDLWindowHandle != IntPtr.Zero) + { + SDL.SDL_DestroyWindow(SDLWindowHandle); + SDLWindowHandle = IntPtr.Zero; + } + }); public void Raise() => ScheduleCommand(() => { @@ -525,9 +537,7 @@ internal virtual void SetIconFromGroup(IconGroup iconGroup) public void Dispose() { - if (SDLWindowHandle != IntPtr.Zero) - SDL.SDL_DestroyWindow(SDLWindowHandle); - + Close(); SDL.SDL_Quit(); } } From 85f04bf10d0d28cfeb588ad687e453414171a2e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2023 16:24:55 +0900 Subject: [PATCH 20/37] Harden logic surrounding window close to avoid any chance of misfirings --- osu.Framework/Platform/SDL2DesktopWindow.cs | 24 +++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Framework/Platform/SDL2DesktopWindow.cs b/osu.Framework/Platform/SDL2DesktopWindow.cs index 870006ca1b..ab0abdaf36 100644 --- a/osu.Framework/Platform/SDL2DesktopWindow.cs +++ b/osu.Framework/Platform/SDL2DesktopWindow.cs @@ -232,11 +232,10 @@ public virtual void Create() if (SDLWindowHandle == IntPtr.Zero) throw new InvalidOperationException($"Failed to create SDL window. SDL Error: {SDL.SDL_GetError()}"); - Exists = true; - graphicsSurface.Initialise(); initialiseWindowingAfterCreation(); + Exists = true; } /// @@ -281,6 +280,7 @@ public void Run() Update?.Invoke(); } + Exists = false; Exited?.Invoke(); Close(); @@ -301,16 +301,22 @@ public void OnDraw() /// /// Forcefully closes the window. /// - public void Close() => ScheduleCommand(() => + public void Close() { - Exists = false; - - if (SDLWindowHandle != IntPtr.Zero) + if (Exists) { - SDL.SDL_DestroyWindow(SDLWindowHandle); - SDLWindowHandle = IntPtr.Zero; + // Close will be called as part of finishing the Run loop. + ScheduleCommand(() => Exists = false); } - }); + else + { + if (SDLWindowHandle != IntPtr.Zero) + { + SDL.SDL_DestroyWindow(SDLWindowHandle); + SDLWindowHandle = IntPtr.Zero; + } + } + } public void Raise() => ScheduleCommand(() => { From 7d924d3dc651c201b88cd985ad4e1d9ba5634b1f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2023 17:55:22 +0900 Subject: [PATCH 21/37] Add important log output when user renderer setting is reverted --- osu.Framework/Platform/GameHost.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 9b0d8c5d22..4e1905596a 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -812,10 +812,10 @@ protected virtual void ChooseAndSetupRenderer() List attemptSurfaceTypes = new List(); bool attemptOperatingSystemSpecificFallbacks = true; - var configRenderer = Config.Get(FrameworkSetting.Renderer); + var configRenderer = Config.GetBindable(FrameworkSetting.Renderer); Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); - switch (configRenderer) + switch (configRenderer.Value) { case RendererType.Metal: attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); @@ -877,8 +877,13 @@ void addFallback(GraphicsSurfaceType surface) } catch { - // If we fail, assume the user may have had a custom setting and switch it back to automatic. - Config.SetValue(FrameworkSetting.Renderer, RendererType.Automatic); + if (configRenderer.Value != RendererType.Automatic) + { + // If we fail, assume the user may have had a custom setting and switch it back to automatic. + Logger.Log($"The selected renderer ({configRenderer.Value.GetDescription()}) failed to initialise. Renderer selection has been reverted to automatic.", + level: LogLevel.Important); + configRenderer.Value = RendererType.Automatic; + } } } From a03ebadd5945ff25f93b1d88412942f6597b5d31 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2023 20:16:04 +0900 Subject: [PATCH 22/37] Don't force config value to legacy GL when falling back --- osu.Framework/Platform/GameHost.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 4e1905596a..b168653685 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -889,7 +889,6 @@ void addFallback(GraphicsSurfaceType surface) // fallback to legacy renderer. this is basically guaranteed to support all platforms. SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); - Config.SetValue(FrameworkSetting.Renderer, RendererType.OpenGLLegacy); } protected void SetupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) From 24e07e7e330a57ba2c762c0b71093a6947d87a4c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2023 20:26:10 +0900 Subject: [PATCH 23/37] Refactor to expose enough information to show a renderer selector game-side --- osu.Framework/Platform/GameHost.cs | 168 ++++++++++++++++++----------- 1 file changed, 104 insertions(+), 64 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index b168653685..59cb07ea93 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -795,6 +795,50 @@ public void Run(Game game) } } + /// + /// The renderer which the game host is currently running with. + /// + public RendererType ResolvedRenderer { get; private set; } + + /// + /// All valid s for the current platform. + /// + public IEnumerable GetValidRenderersForCurrentPlatform() => + GetPreferredRenderersForCurrentPlatform() + .Append(RendererType.OpenGL) + .Append(RendererType.OpenGLLegacy); + + /// + /// All preferred s for the current platform. + /// These are used in order of appearance when is used, or when the user preference fails to initialise. + /// + public IEnumerable GetPreferredRenderersForCurrentPlatform() + { + yield return RendererType.Automatic; + + // Best case, we can make use of veldrid with a new graphics API. + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + yield return RendererType.Vulkan; + yield return RendererType.Direct3D11; + + break; + + case RuntimeInfo.Platform.Linux: + case RuntimeInfo.Platform.Android: + yield return RendererType.Vulkan; + + break; + + case RuntimeInfo.Platform.macOS: + case RuntimeInfo.Platform.iOS: + yield return RendererType.Metal; + + break; + } + } + protected virtual void ChooseAndSetupRenderer() { // Always give preference to environment variables. @@ -809,86 +853,77 @@ protected virtual void ChooseAndSetupRenderer() return; } - List attemptSurfaceTypes = new List(); - bool attemptOperatingSystemSpecificFallbacks = true; - var configRenderer = Config.GetBindable(FrameworkSetting.Renderer); Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); - switch (configRenderer.Value) + // Attempt to initialise various veldrid surface types. + // If legacy GL was requested we can skip this and fallback to the final logic below. + if (configRenderer.Value != RendererType.OpenGLLegacy) + { + var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); + + Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()).Append("OpenGL (Legacy)"))} ]"); + + // Move user's preference to the start of the attempts. + rendererTypes.Remove(configRenderer.Value); + rendererTypes.Insert(0, configRenderer.Value); + + foreach (RendererType type in rendererTypes) + { + if (type == RendererType.Automatic) + continue; + + try + { + SetupRendererAndWindow("veldrid", rendererToGraphicsSurfaceType(type)); + ResolvedRenderer = type; + return; + } + catch + { + if (configRenderer.Value != RendererType.Automatic) + { + // If we fail, assume the user may have had a custom setting and switch it back to automatic. + Logger.Log($"The selected renderer ({configRenderer.Value.GetDescription()}) failed to initialise. Renderer selection has been reverted to automatic.", + level: LogLevel.Important); + configRenderer.Value = RendererType.Automatic; + } + } + } + } + + // fallback to legacy renderer. this is basically guaranteed to support all platforms. + SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + ResolvedRenderer = RendererType.OpenGLLegacy; + } + + private static GraphicsSurfaceType rendererToGraphicsSurfaceType(RendererType renderer) + { + GraphicsSurfaceType surface; + + switch (renderer) { case RendererType.Metal: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Metal); + surface = GraphicsSurfaceType.Metal; break; case RendererType.Vulkan: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Vulkan); + surface = GraphicsSurfaceType.Vulkan; break; case RendererType.Direct3D11: - attemptSurfaceTypes.Add(GraphicsSurfaceType.Direct3D11); + surface = GraphicsSurfaceType.Direct3D11; break; case RendererType.OpenGL: - attemptSurfaceTypes.Add(GraphicsSurfaceType.OpenGL); + surface = GraphicsSurfaceType.OpenGL; break; - case RendererType.OpenGLLegacy: - attemptOperatingSystemSpecificFallbacks = false; - break; - } - - if (attemptOperatingSystemSpecificFallbacks) - { - // Best case, we can make use of veldrid with a new graphics API. - switch (RuntimeInfo.OS) - { - case RuntimeInfo.Platform.Windows: - addFallback(GraphicsSurfaceType.Vulkan); - addFallback(GraphicsSurfaceType.Direct3D11); - break; - - case RuntimeInfo.Platform.Linux: - case RuntimeInfo.Platform.Android: - addFallback(GraphicsSurfaceType.Vulkan); - break; - - case RuntimeInfo.Platform.macOS: - case RuntimeInfo.Platform.iOS: - addFallback(GraphicsSurfaceType.Metal); - break; - } - - void addFallback(GraphicsSurfaceType surface) - { - if (!attemptSurfaceTypes.Contains(surface)) - attemptSurfaceTypes.Add(surface); - } - } - - Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", attemptSurfaceTypes.Select(e => e.GetDescription()).Append("OpenGL (Legacy)"))} ]"); - - foreach (var attemptSurfaceType in attemptSurfaceTypes) - { - try - { - SetupRendererAndWindow("veldrid", attemptSurfaceType); - return; - } - catch - { - if (configRenderer.Value != RendererType.Automatic) - { - // If we fail, assume the user may have had a custom setting and switch it back to automatic. - Logger.Log($"The selected renderer ({configRenderer.Value.GetDescription()}) failed to initialise. Renderer selection has been reverted to automatic.", - level: LogLevel.Important); - configRenderer.Value = RendererType.Automatic; - } - } + default: + throw new ArgumentException("Provided renderer cannot be mapped to a veldrid surface"); } - // fallback to legacy renderer. this is basically guaranteed to support all platforms. - SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + return surface; } protected void SetupRendererAndWindow(string renderer, GraphicsSurfaceType surfaceType) @@ -1267,9 +1302,14 @@ private void setVSyncMode() /// /// Construct all input handlers for this host. The order here decides the priority given to handlers, with the earliest occurring having higher priority. /// - protected abstract IEnumerable CreateAvailableInputHandlers(); + protected abstract IEnumerable + CreateAvailableInputHandlers(); - public ImmutableArray AvailableInputHandlers { get; private set; } + public ImmutableArray AvailableInputHandlers + { + get; + private set; + } protected virtual TextInputSource CreateTextInput() => new TextInputSource(); From eb60b99de33de6f4a1f637d236a11c29d2ff5ad0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Mar 2023 19:18:21 +0900 Subject: [PATCH 24/37] Don't prefer vulkan for now --- osu.Framework/Platform/GameHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 59cb07ea93..4fd1b80153 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -820,14 +820,14 @@ public IEnumerable GetPreferredRenderersForCurrentPlatform() switch (RuntimeInfo.OS) { case RuntimeInfo.Platform.Windows: - yield return RendererType.Vulkan; + // yield return RendererType.Vulkan; yield return RendererType.Direct3D11; break; case RuntimeInfo.Platform.Linux: case RuntimeInfo.Platform.Android: - yield return RendererType.Vulkan; + // yield return RendererType.Vulkan; break; From a945d0e1a83269b8c7a94bb94f61c144556b26c7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Mar 2023 19:22:06 +0900 Subject: [PATCH 25/37] Explicitly define valid renderers rather than appending to preferred list --- osu.Framework/Platform/GameHost.cs | 32 ++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 4fd1b80153..3065c416e1 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -803,10 +803,34 @@ public void Run(Game game) /// /// All valid s for the current platform. /// - public IEnumerable GetValidRenderersForCurrentPlatform() => - GetPreferredRenderersForCurrentPlatform() - .Append(RendererType.OpenGL) - .Append(RendererType.OpenGLLegacy); + public IEnumerable GetValidRenderersForCurrentPlatform() + { + yield return RendererType.Automatic; + + switch (RuntimeInfo.OS) + { + case RuntimeInfo.Platform.Windows: + yield return RendererType.Direct3D11; + yield return RendererType.Vulkan; + + break; + + case RuntimeInfo.Platform.Linux: + case RuntimeInfo.Platform.Android: + yield return RendererType.Vulkan; + + break; + + case RuntimeInfo.Platform.macOS: + case RuntimeInfo.Platform.iOS: + yield return RendererType.Metal; + + break; + } + + yield return RendererType.OpenGL; + yield return RendererType.OpenGLLegacy; + } /// /// All preferred s for the current platform. From b88763691813c8d687006bbe42f4deb0f9d07eac Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 19 Mar 2023 14:30:20 +0300 Subject: [PATCH 26/37] Add simple test scene for updating renderer configuration --- .../Visual/Platform/TestSceneRenderer.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs diff --git a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs new file mode 100644 index 0000000000..43cb473712 --- /dev/null +++ b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Platform; + +namespace osu.Framework.Tests.Visual.Platform +{ + public partial class TestSceneRenderer : FrameworkTestScene + { + [Resolved] + private GameHost host { get; set; } = null!; + + [Resolved] + private FrameworkConfigManager config { get; set; } = null!; + + [SetUp] + public void SetUp() => Schedule(() => + { + Add(new SpriteText + { + Text = $"Renderer: {host.ResolvedRenderer} ({host.Renderer.GetType().Name} / {host.Window.GraphicsSurface.Type})", + Font = FrameworkFont.Regular.With(size: 24), + }); + + Add(new BasicDropdown + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Current = config.GetBindable(FrameworkSetting.Renderer), + Items = host.GetValidRenderersForCurrentPlatform(), + Width = 200f, + }); + }); + } +} From 375fed6e8eb7886fbdce1a5815e1480e83308327 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 19 Mar 2023 14:58:32 +0300 Subject: [PATCH 27/37] Remove unused using directive --- osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs index 43cb473712..fe51090720 100644 --- a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs +++ b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Configuration; From 265de8c77be4ab7def39f24e9a270ba8994f4f47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Mar 2023 16:51:34 +0900 Subject: [PATCH 28/37] Fix weird formatting failure --- osu.Framework/Platform/GameHost.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 3065c416e1..128cefe0d9 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -1326,14 +1326,9 @@ private void setVSyncMode() /// /// Construct all input handlers for this host. The order here decides the priority given to handlers, with the earliest occurring having higher priority. /// - protected abstract IEnumerable - CreateAvailableInputHandlers(); + protected abstract IEnumerable CreateAvailableInputHandlers(); - public ImmutableArray AvailableInputHandlers - { - get; - private set; - } + public ImmutableArray AvailableInputHandlers { get; private set; } protected virtual TextInputSource CreateTextInput() => new TextInputSource(); From ccde21f1d1871036b273174d770a198017605878 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Mar 2023 16:54:27 +0900 Subject: [PATCH 29/37] Add `OpenGLLegacy` to preferred fallback order to better match expectations --- osu.Framework/Platform/GameHost.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 128cefe0d9..4ea97fa6f6 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -861,6 +861,8 @@ public IEnumerable GetPreferredRenderersForCurrentPlatform() break; } + + yield return RendererType.OpenGLLegacy; } protected virtual void ChooseAndSetupRenderer() @@ -897,6 +899,10 @@ protected virtual void ChooseAndSetupRenderer() if (type == RendererType.Automatic) continue; + // Handled below as final non-veldrid fallback. + if (type == RendererType.OpenGLLegacy) + continue; + try { SetupRendererAndWindow("veldrid", rendererToGraphicsSurfaceType(type)); From 5ae012997ff78d869866d63eac718f2041fc9b34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Mar 2023 17:18:02 +0900 Subject: [PATCH 30/37] Combine `Preferred` and `Available` methods into one --- .../Visual/Platform/TestSceneRenderer.cs | 3 +- osu.Framework/Platform/GameHost.cs | 55 ++++--------------- 2 files changed, 13 insertions(+), 45 deletions(-) diff --git a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs index fe51090720..edc41bf069 100644 --- a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs +++ b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Configuration; @@ -32,8 +33,8 @@ public partial class TestSceneRenderer : FrameworkTestScene { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Items = host.GetPreferredRenderersForCurrentPlatform().OrderBy(t => t), Current = config.GetBindable(FrameworkSetting.Renderer), - Items = host.GetValidRenderersForCurrentPlatform(), Width = 200f, }); }); diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 4ea97fa6f6..729a13f9f3 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -801,23 +801,17 @@ public void Run(Game game) public RendererType ResolvedRenderer { get; private set; } /// - /// All valid s for the current platform. + /// All valid s for the current platform, in order of how stable and performant they are deemed to be. /// - public IEnumerable GetValidRenderersForCurrentPlatform() + public IEnumerable GetPreferredRenderersForCurrentPlatform() { yield return RendererType.Automatic; + // Preferred per-platform renderers switch (RuntimeInfo.OS) { case RuntimeInfo.Platform.Windows: yield return RendererType.Direct3D11; - yield return RendererType.Vulkan; - - break; - - case RuntimeInfo.Platform.Linux: - case RuntimeInfo.Platform.Android: - yield return RendererType.Vulkan; break; @@ -828,41 +822,14 @@ public IEnumerable GetValidRenderersForCurrentPlatform() break; } - yield return RendererType.OpenGL; + // Non-veldrid "known-to-work". yield return RendererType.OpenGLLegacy; - } - - /// - /// All preferred s for the current platform. - /// These are used in order of appearance when is used, or when the user preference fails to initialise. - /// - public IEnumerable GetPreferredRenderersForCurrentPlatform() - { - yield return RendererType.Automatic; - // Best case, we can make use of veldrid with a new graphics API. - switch (RuntimeInfo.OS) - { - case RuntimeInfo.Platform.Windows: - // yield return RendererType.Vulkan; - yield return RendererType.Direct3D11; - - break; - - case RuntimeInfo.Platform.Linux: - case RuntimeInfo.Platform.Android: - // yield return RendererType.Vulkan; - - break; - - case RuntimeInfo.Platform.macOS: - case RuntimeInfo.Platform.iOS: - yield return RendererType.Metal; - - break; - } + // Other available renderers should also be returned (to make this method usable as "all available renderers for current platform"), + // but will never be preferred as OpenGLLegacy will always work. + yield return RendererType.OpenGL; - yield return RendererType.OpenGLLegacy; + if (!RuntimeInfo.IsApple) yield return RendererType.Vulkan; } protected virtual void ChooseAndSetupRenderer() @@ -882,13 +849,13 @@ protected virtual void ChooseAndSetupRenderer() var configRenderer = Config.GetBindable(FrameworkSetting.Renderer); Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); - // Attempt to initialise various veldrid surface types. + // Attempt to initialise various veldrid surface types (and legacy GL). // If legacy GL was requested we can skip this and fallback to the final logic below. if (configRenderer.Value != RendererType.OpenGLLegacy) { var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); - Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()).Append("OpenGL (Legacy)"))} ]"); + Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()))} ]"); // Move user's preference to the start of the attempts. rendererTypes.Remove(configRenderer.Value); @@ -901,7 +868,7 @@ protected virtual void ChooseAndSetupRenderer() // Handled below as final non-veldrid fallback. if (type == RendererType.OpenGLLegacy) - continue; + break; try { From a2e91ad187e7e37e4001135a653e063b8c53296e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Mar 2023 17:24:55 +0900 Subject: [PATCH 31/37] Change initialisation path to consume `OpenGLLegacy` inline inside main init loop --- osu.Framework/Platform/GameHost.cs | 56 ++++++++++++++---------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 729a13f9f3..e7892faabb 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -851,47 +851,43 @@ protected virtual void ChooseAndSetupRenderer() // Attempt to initialise various veldrid surface types (and legacy GL). // If legacy GL was requested we can skip this and fallback to the final logic below. - if (configRenderer.Value != RendererType.OpenGLLegacy) - { - var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); + var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); - Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()))} ]"); + Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()))} ]"); - // Move user's preference to the start of the attempts. - rendererTypes.Remove(configRenderer.Value); - rendererTypes.Insert(0, configRenderer.Value); + // Move user's preference to the start of the attempts. + rendererTypes.Remove(configRenderer.Value); + rendererTypes.Insert(0, configRenderer.Value); - foreach (RendererType type in rendererTypes) - { - if (type == RendererType.Automatic) - continue; + foreach (RendererType type in rendererTypes) + { + if (type == RendererType.Automatic) + continue; - // Handled below as final non-veldrid fallback. + try + { if (type == RendererType.OpenGLLegacy) - break; - - try - { + // the legacy renderer. this is basically guaranteed to support all platforms. + SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); + else SetupRendererAndWindow("veldrid", rendererToGraphicsSurfaceType(type)); - ResolvedRenderer = type; - return; - } - catch + + ResolvedRenderer = type; + return; + } + catch + { + if (configRenderer.Value != RendererType.Automatic) { - if (configRenderer.Value != RendererType.Automatic) - { - // If we fail, assume the user may have had a custom setting and switch it back to automatic. - Logger.Log($"The selected renderer ({configRenderer.Value.GetDescription()}) failed to initialise. Renderer selection has been reverted to automatic.", - level: LogLevel.Important); - configRenderer.Value = RendererType.Automatic; - } + // If we fail, assume the user may have had a custom setting and switch it back to automatic. + Logger.Log($"The selected renderer ({configRenderer.Value.GetDescription()}) failed to initialise. Renderer selection has been reverted to automatic.", + level: LogLevel.Important); + configRenderer.Value = RendererType.Automatic; } } } - // fallback to legacy renderer. this is basically guaranteed to support all platforms. - SetupRendererAndWindow("gl", GraphicsSurfaceType.OpenGL); - ResolvedRenderer = RendererType.OpenGLLegacy; + Logger.Log("No usable renderer was found!", level: LogLevel.Error); } private static GraphicsSurfaceType rendererToGraphicsSurfaceType(RendererType renderer) From 82bfcef3fd2e9d4692fb98224c49c54729d9a2f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Mar 2023 17:25:15 +0900 Subject: [PATCH 32/37] Fix fallback order being output before raising user's preference to top --- osu.Framework/Platform/GameHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index e7892faabb..dddc0dd169 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -853,12 +853,12 @@ protected virtual void ChooseAndSetupRenderer() // If legacy GL was requested we can skip this and fallback to the final logic below. var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); - Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()))} ]"); - // Move user's preference to the start of the attempts. rendererTypes.Remove(configRenderer.Value); rendererTypes.Insert(0, configRenderer.Value); + Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()))} ]"); + foreach (RendererType type in rendererTypes) { if (type == RendererType.Automatic) From 3f7500330aec9fc4d64163e6c1f8f9d80d095b2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Mar 2023 17:50:16 +0900 Subject: [PATCH 33/37] Fix renderer test running in headless mode --- osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs index edc41bf069..9d5a212dcc 100644 --- a/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs +++ b/osu.Framework.Tests/Visual/Platform/TestSceneRenderer.cs @@ -12,6 +12,7 @@ namespace osu.Framework.Tests.Visual.Platform { + [Ignore("This test cannot be run in headless mode (a renderer is required).")] public partial class TestSceneRenderer : FrameworkTestScene { [Resolved] From 28949fde3f51c02a9898b62289f2c09692967c86 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 20 Mar 2023 14:28:32 +0300 Subject: [PATCH 34/37] Remove stale comment --- osu.Framework/Platform/GameHost.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index dddc0dd169..70d0ab85e7 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -850,7 +850,6 @@ protected virtual void ChooseAndSetupRenderer() Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); // Attempt to initialise various veldrid surface types (and legacy GL). - // If legacy GL was requested we can skip this and fallback to the final logic below. var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); // Move user's preference to the start of the attempts. From f08742e506a127d1dfcc672315a05d4265763389 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 20 Mar 2023 14:34:02 +0300 Subject: [PATCH 35/37] Fix fallback order log including `Automatic` type --- osu.Framework/Platform/GameHost.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 70d0ab85e7..ffe691ff76 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -850,19 +850,19 @@ protected virtual void ChooseAndSetupRenderer() Logger.Log($"🖼️ Configuration renderer choice: {configRenderer}"); // Attempt to initialise various veldrid surface types (and legacy GL). - var rendererTypes = GetPreferredRenderersForCurrentPlatform().ToList(); + var rendererTypes = GetPreferredRenderersForCurrentPlatform().Where(r => r != RendererType.Automatic).ToList(); // Move user's preference to the start of the attempts. - rendererTypes.Remove(configRenderer.Value); - rendererTypes.Insert(0, configRenderer.Value); + if (!configRenderer.IsDefault) + { + rendererTypes.Remove(configRenderer.Value); + rendererTypes.Insert(0, configRenderer.Value); + } Logger.Log($"🖼️ Renderer fallback order: [ {string.Join(", ", rendererTypes.Select(e => e.GetDescription()))} ]"); foreach (RendererType type in rendererTypes) { - if (type == RendererType.Automatic) - continue; - try { if (type == RendererType.OpenGLLegacy) From 0486c104c84b714b433f14f34965895da698ad55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Mar 2023 15:50:33 +0900 Subject: [PATCH 36/37] Add xmldoc for `ResolvedRenderer` Co-authored-by: Salman Ahmed --- osu.Framework/Platform/GameHost.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index ffe691ff76..e2c20cf924 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -798,6 +798,9 @@ public void Run(Game game) /// /// The renderer which the game host is currently running with. /// + /// + /// This is similar to except that this is expressed as a rather than a . + /// public RendererType ResolvedRenderer { get; private set; } /// From 0fffc815f4318668b2f4e5d32bac1f715d08d781 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Mar 2023 16:04:38 +0900 Subject: [PATCH 37/37] Move window setup inside try-catch --- osu.Framework/Platform/GameHost.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index e2c20cf924..1f52e06ec5 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -951,10 +951,9 @@ protected void SetupRendererAndWindow(IRenderer renderer, GraphicsSurfaceType su return; } - Window.SetupWindow(Config); - try { + Window.SetupWindow(Config); Window.Create(); Window.Title = $@"osu!framework (running ""{Name}"")";