Using DisplayLink to emulate vsync on OSX
(cherry picked from commit b53f2d1d59
)
This commit is contained in:
parent
2ff2b727b6
commit
633ac4f753
|
@ -123,7 +123,7 @@ def configure(env):
|
||||||
|
|
||||||
env.Append(CPPPATH=['#platform/osx'])
|
env.Append(CPPPATH=['#platform/osx'])
|
||||||
env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED'])
|
env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED'])
|
||||||
env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
|
env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo'])
|
||||||
env.Append(LIBS=['pthread'])
|
env.Append(LIBS=['pthread'])
|
||||||
|
|
||||||
env.Append(CPPFLAGS=['-mmacosx-version-min=10.9'])
|
env.Append(CPPFLAGS=['-mmacosx-version-min=10.9'])
|
||||||
|
|
|
@ -42,8 +42,10 @@
|
||||||
#include "servers/visual/rasterizer.h"
|
#include "servers/visual/rasterizer.h"
|
||||||
#include "servers/visual/visual_server_wrap_mt.h"
|
#include "servers/visual/visual_server_wrap_mt.h"
|
||||||
#include "servers/visual_server.h"
|
#include "servers/visual_server.h"
|
||||||
|
#include <AppKit/AppKit.h>
|
||||||
#include <AppKit/NSCursor.h>
|
#include <AppKit/NSCursor.h>
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
#include <CoreVideo/CoreVideo.h>
|
||||||
|
|
||||||
#undef CursorShape
|
#undef CursorShape
|
||||||
/**
|
/**
|
||||||
|
@ -96,8 +98,12 @@ public:
|
||||||
id window_view;
|
id window_view;
|
||||||
id autoreleasePool;
|
id autoreleasePool;
|
||||||
id cursor;
|
id cursor;
|
||||||
id pixelFormat;
|
NSOpenGLPixelFormat *pixelFormat;
|
||||||
id context;
|
NSOpenGLContext *context;
|
||||||
|
|
||||||
|
bool waiting_for_vsync;
|
||||||
|
NSCondition *vsync_condition;
|
||||||
|
CVDisplayLinkRef displayLink;
|
||||||
|
|
||||||
CursorShape cursor_shape;
|
CursorShape cursor_shape;
|
||||||
NSCursor *cursors[CURSOR_MAX] = { NULL };
|
NSCursor *cursors[CURSOR_MAX] = { NULL };
|
||||||
|
|
|
@ -114,6 +114,21 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto
|
||||||
return Vector2(mouse_x, mouse_y);
|
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
|
@interface GodotApplication : NSApplication
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -1195,6 +1210,15 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
|
||||||
|
|
||||||
[context makeCurrentContext];
|
[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);
|
set_use_vsync(p_desired.use_vsync);
|
||||||
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
@ -1239,6 +1263,11 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
|
||||||
|
|
||||||
void OS_OSX::finalize() {
|
void OS_OSX::finalize() {
|
||||||
|
|
||||||
|
if (displayLink) {
|
||||||
|
CVDisplayLinkRelease(displayLink);
|
||||||
|
}
|
||||||
|
[vsync_condition release];
|
||||||
|
|
||||||
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
|
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
|
||||||
CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
|
CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
|
||||||
|
|
||||||
|
@ -1692,6 +1721,17 @@ String OS_OSX::get_locale() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS_OSX::swap_buffers() {
|
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];
|
[context flushBuffer];
|
||||||
}
|
}
|
||||||
|
@ -2322,22 +2362,22 @@ Error OS_OSX::move_to_trash(const String &p_path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS_OSX::_set_use_vsync(bool p_enable) {
|
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) {
|
if (ctx) {
|
||||||
GLint swapInterval = p_enable ? 1 : 0;
|
GLint swapInterval = p_enable ? 1 : 0;
|
||||||
CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
|
CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
///TODO Maybe pause/unpause display link?
|
||||||
|
waiting_for_vsync = p_enable;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
bool OS_OSX::is_vsync_enabled() const {
|
|
||||||
GLint swapInterval = 0;
|
|
||||||
CGLContextObj ctx = CGLGetCurrentContext();
|
|
||||||
if (ctx) {
|
|
||||||
CGLGetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
|
|
||||||
}
|
|
||||||
return swapInterval ? true : false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
OS_OSX *OS_OSX::singleton = NULL;
|
OS_OSX *OS_OSX::singleton = NULL;
|
||||||
|
|
||||||
OS_OSX::OS_OSX() {
|
OS_OSX::OS_OSX() {
|
||||||
|
|
Loading…
Reference in New Issue