|
@@ -117,6 +117,21 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto
|
|
|
return Vector2(mouse_x, mouse_y);
|
|
|
}
|
|
|
|
|
|
+// DisplayLinkCallback is called from our DisplayLink OS thread informing us right before
|
|
|
+// a screen update is required. We can use it to work around the broken vsync.
|
|
|
+static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) {
|
|
|
+ OS_OSX *os = (OS_OSX *)displayLinkContext;
|
|
|
+
|
|
|
+ // Set flag so we know we can output our next frame and signal our conditional lock
|
|
|
+ // if we're not doing vsync this will be ignored
|
|
|
+ [os->vsync_condition lock];
|
|
|
+ os->waiting_for_vsync = false;
|
|
|
+ [os->vsync_condition signal];
|
|
|
+ [os->vsync_condition unlock];
|
|
|
+
|
|
|
+ return kCVReturnSuccess;
|
|
|
+}
|
|
|
+
|
|
|
@interface GodotApplication : NSApplication
|
|
|
@end
|
|
|
|
|
@@ -1366,6 +1381,15 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
|
|
|
|
|
|
[context makeCurrentContext];
|
|
|
|
|
|
+ // setup our display link, this will inform us when a refresh is needed
|
|
|
+ CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
|
|
|
+ CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, this);
|
|
|
+ CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, context.CGLContextObj, pixelFormat.CGLPixelFormatObj);
|
|
|
+ CVDisplayLinkStart(displayLink);
|
|
|
+
|
|
|
+ // initialise a conditional lock object
|
|
|
+ vsync_condition = [[NSCondition alloc] init];
|
|
|
+
|
|
|
set_use_vsync(p_desired.use_vsync);
|
|
|
|
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
@@ -1453,6 +1477,11 @@ void OS_OSX::finalize() {
|
|
|
midi_driver.close();
|
|
|
#endif
|
|
|
|
|
|
+ if (displayLink) {
|
|
|
+ CVDisplayLinkRelease(displayLink);
|
|
|
+ }
|
|
|
+ [vsync_condition release];
|
|
|
+
|
|
|
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
|
|
|
CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
|
|
|
|
|
@@ -1967,6 +1996,17 @@ String OS_OSX::get_locale() const {
|
|
|
}
|
|
|
|
|
|
void OS_OSX::swap_buffers() {
|
|
|
+ if (is_vsync_enabled()) {
|
|
|
+ // Wait until our DisplayLink callback unsets our flag...
|
|
|
+ [vsync_condition lock];
|
|
|
+ while (waiting_for_vsync)
|
|
|
+ [vsync_condition wait];
|
|
|
+
|
|
|
+ // Make sure we wait again next frame around
|
|
|
+ waiting_for_vsync = true;
|
|
|
+
|
|
|
+ [vsync_condition unlock];
|
|
|
+ }
|
|
|
|
|
|
[context flushBuffer];
|
|
|
}
|
|
@@ -2633,22 +2673,22 @@ Error OS_OSX::move_to_trash(const String &p_path) {
|
|
|
}
|
|
|
|
|
|
void OS_OSX::_set_use_vsync(bool p_enable) {
|
|
|
- CGLContextObj ctx = CGLGetCurrentContext();
|
|
|
+ // CGLCPSwapInterval broke in OSX 10.14 and it seems Apple is not interested in fixing
|
|
|
+ // it as OpenGL is now deprecated and Metal solves this differently.
|
|
|
+ // Following SDLs example we're working around this using DisplayLink
|
|
|
+ // When vsync is enabled we set a flag "waiting_for_vsync" to true.
|
|
|
+ // This flag is set to false when DisplayLink informs us our display is about to refresh.
|
|
|
+
|
|
|
+ /* CGLContextObj ctx = CGLGetCurrentContext();
|
|
|
if (ctx) {
|
|
|
GLint swapInterval = p_enable ? 1 : 0;
|
|
|
CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
|
|
|
- }
|
|
|
-}
|
|
|
-/*
|
|
|
-bool OS_OSX::is_vsync_enabled() const {
|
|
|
- GLint swapInterval = 0;
|
|
|
- CGLContextObj ctx = CGLGetCurrentContext();
|
|
|
- if (ctx) {
|
|
|
- CGLGetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
|
|
|
- }
|
|
|
- return swapInterval ? true : false;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ ///TODO Maybe pause/unpause display link?
|
|
|
+ waiting_for_vsync = p_enable;
|
|
|
}
|
|
|
-*/
|
|
|
+
|
|
|
OS_OSX *OS_OSX::singleton = NULL;
|
|
|
|
|
|
OS_OSX::OS_OSX() {
|