ppy / osu-framework

A game framework written with osu! in mind.
MIT License
1.64k stars 409 forks source link

Implement `CADisplayLink` on macOS for potentially better frame timing #6217

Open frenzibyte opened 6 months ago

frenzibyte commented 6 months ago

Apple recently supported CADisplayLink on macOS, starting from macOS 14.0 onwards. According to @smoogipoo, there have been mentions that CADisplayLink helps better on frame timing than CVDisplayLink does (which we currently rely on inside veldrid), if it does at all.

CADisplayLink requires wrapping the osu!framework thread runner under itself to best achieve its functionality. I've attempted that in this branch, but I've hit a hard wall and I have no idea how to proceed.

Before reading further below, keep in mind that I have no idea what I'm doing, and everything I'm saying below may just as well be incorrect and misguided.

What I expect in that branch is that the game would set itself up normally, then at the point of MacOSWindow.RunMainLoop it will create the display link and assign the delegate, then spin on the application run loop while the display link keeps signaling, until the window is closed (signaled from inside the callback of the display link).

However, the CADisplayLink never fires off, causing no window to appear or anything to function except for the main thread continuously looping on NSRunLoop.DefaultRunLoop doing nothing (this could be happening because there's something else I'm supposed to spin on so that CADisplayLink actually functions, I don't know).

This is quite simpler on iOS because the entire game runs on a UIApplication run loop, so the application keeps spinning regardless of whether the GameHost.Run method exited and the display link fires back correctly. Maybe we're supposed to do something similar to this somehow? Wrapping it under MacOSGameHost.Run potentially.

I'm not really well-versed with how macOS run loops work under the hood in combination with .NET, so I don't have much of a clue as to what's going on and how we're supposed to implement CADisplayLink in the first place.

frenzibyte commented 6 months ago

After further attempts on my branch I had realised it's not working with how I have things structured because I'm creating the display link using NSWindow. If I create it using CADisplayLink itself, it works just fine by iterating on the run loop. This is probably not good because I imagine we need the NSWindow for display link to work when changing displays and what not, so I will need to keep attempting further until I figure it out.