Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
# macOS runner performance has gotten unbearably slow so let's turn them off temporarily.
# - { prettyname: macOS, fullname: macos-latest }
- { prettyname: Linux, fullname: ubuntu-latest }
threadingMode: ['SingleThread', 'MultiThreaded']
threadingMode: ['MultiThreaded']
timeout-minutes: 120
steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ Settings → Graphics → Renderer now exposes the full set of fork-added option
| **Renderer** | Picks the GPU backend. On Windows you get Metal / Vulkan / D3D11 / **D3D12 (new)** / OpenGL plus their `Deferred_*` experimental variants. On Android you get Vulkan (if supported) and OpenGL ES. |
| **Frame limiter** | VSync, **VSync Unbuffered (new)** — ideal for G-Sync / FreeSync / VRR displays, 2×/4×/8× refresh, Unlimited, or **Custom (new)**. |
| **Custom draw rate limit** | Slider 0–1000 Hz, only visible when the frame limiter is set to Custom. `0` = unlimited draw thread. Useful for benchmarking or VRR-specific tuning. |
| **Threading mode** | Single / MultiThreaded / MultiThreadedDrawing. |
| **Low latency** | `Off` / `On` / `Boost` — drives the fork's generic `ILowLatencyProvider` (NVIDIA Reflex / LatencyFlex-ready on D3D11 & D3D12; no-op on other backends until a provider plugin is supplied). `Boost` also sleeps at the start of each update frame for lower input-to-photon latency. |

---
Expand All @@ -184,6 +183,7 @@ Settings → Graphics → Renderer now exposes the full set of fork-added option

This fork includes several hardening fixes on top of upstream:

- **Multi-threaded execution lock-in (v145+)** — the framework's `ExecutionMode = SingleThread` is force-set to `MultiThreaded` on every startup and the threading-mode toggle is removed from Settings → Graphics → Renderer. SingleThread on Android collapsed the SDL/Vulkan thread onto the same thread that delivers the `SurfaceHolder.Callback`, so `VeldridDevice`'s 5-second `SurfaceHandle` poll deadlocked and Vulkan device creation crashed on a null function pointer (`SDLThread` `SI_TKILL` ~5 s into launch). The same risk applies to iOS Metal drawable attach; on desktop SingleThread is strictly slower with no UX benefit, so the lock-in is unconditional across all platforms.
- **Sentry-safe init** — the app gracefully handles a missing/placeholder Sentry DSN instead of failing on startup
- **Graceful native library loading** — if the Oboe or Vulkan native libraries are missing, the app continues without them
- **JNI surface safety** — proper lifecycle management with atomic swaps and timeouts to prevent race conditions between Android surface creation and destruction
Expand Down
9 changes: 0 additions & 9 deletions osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
Expand Down Expand Up @@ -104,13 +102,6 @@ public void TestNullRulesetHandled()
AddAssert("ruleset unchanged", () => ReferenceEquals(Ruleset.Value, ruleset));
}

[Test]
public void TestSwitchThreadExecutionMode()
{
AddStep("Change thread mode to multi threaded", () => { Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.MultiThreaded); });
AddStep("Change thread mode to single thread", () => { Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.SingleThread); });
}

[Test]
public void TestUnavailableRulesetHandled()
{
Expand Down
5 changes: 0 additions & 5 deletions osu.Game/Localisation/GraphicsSettingsStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public static class GraphicsSettingsStrings
/// </summary>
public static LocalisableString FrameLimiter => new TranslatableString(getKey(@"frame_limiter"), @"Frame limiter");

/// <summary>
/// "Threading mode"
/// </summary>
public static LocalisableString ThreadingMode => new TranslatableString(getKey(@"threading_mode"), @"Threading mode");

/// <summary>
/// "Show FPS"
/// </summary>
Expand Down
15 changes: 15 additions & 0 deletions osu.Game/OsuGameBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,21 @@ private void load(ReadableKeyCombinationProvider keyCombinationProvider, Framewo

MessageFormatter.WebsiteRootUrl = endpoints.WebsiteUrl;

// Force the framework execution mode to MultiThreaded on every startup.
//
// SingleThread used to be exposed in the graphics settings, but it is incompatible
// with our Android Vulkan-surface readiness path: VeldridDevice / AndroidGameHost
// poll AndroidGameWindow.SurfaceHandle for up to 5s, and in SingleThread mode that
// poll runs on the same thread that publishes the surface handle, deadlocking
// initialisation until the timeout fires and Vulkan device creation crashes with a
// null function pointer (see PR history around the SDLThread/SI_TKILL crash).
//
// The same risk applies to iOS Metal layer attach (drawable surfaces are also
// delivered via the main loop), and on desktop SingleThread is strictly slower with
// no UX benefit. Upstream ppy/osu defaults to MultiThreaded; we now enforce it
// unconditionally so a stale `framework.ini` cannot pin a user into the broken mode.
frameworkConfig.SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.MultiThreaded);
Comment on lines +332 to +345

// Initialise localisation
frameworkLocale = frameworkConfig.GetBindable<string>(FrameworkSetting.Locale);
frameworkLocale.BindValueChanged(_ => updateLanguage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, IDi
Keywords = new[] { @"fps", @"framerate" },
},
customDrawLimitItem,
new SettingsItemV2(new FormEnumDropdown<ExecutionMode>
{
Caption = GraphicsSettingsStrings.ThreadingMode,
Current = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode)
}),
new SettingsItemV2(new FormCheckBox
{
Caption = GraphicsSettingsStrings.ShowFPS,
Expand Down
Loading