diff --git a/docs/changelog.rst b/docs/changelog.rst index d0ae6bbc7..ce9aa4bf0 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -56,6 +56,9 @@ To update |kitty|, :doc:`follow the instructions `. - macOS: When closing a top-level window only switch focus to the previous kitty window if it is on the same workspace (:iss:`1379`) +- macOS: Fix v-sync to monitor refresh rate no longer working under Mojave. See + :opt:`sync_to_monitor` + 0.13.3 [2019-01-19] ------------------------------ diff --git a/glfw/nsgl_context.h b/glfw/nsgl_context.h index 585ae72fc..b7ddf10c1 100644 --- a/glfw/nsgl_context.h +++ b/glfw/nsgl_context.h @@ -27,6 +27,8 @@ #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl +#import +#include // NSGL-specific per-context data // @@ -34,6 +36,10 @@ typedef struct _GLFWcontextNSGL { id pixelFormat; id object; + CVDisplayLinkRef displayLink; + atomic_int swapInterval; + int swapIntervalsPassed; + id swapIntervalCond; } _GLFWcontextNSGL; @@ -53,4 +59,3 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextNSGL(_GLFWwindow* window); - diff --git a/glfw/nsgl_context.m b/glfw/nsgl_context.m index 2c7211f7a..8c7822c9a 100644 --- a/glfw/nsgl_context.m +++ b/glfw/nsgl_context.m @@ -32,6 +32,27 @@ #define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity #endif +static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp* now, + const CVTimeStamp* outputTime, + CVOptionFlags flagsIn, + CVOptionFlags* flagsOut, + void* userInfo) +{ + _GLFWwindow* window = (_GLFWwindow *) userInfo; + + const int setting = atomic_load(&window->context.nsgl.swapInterval); + if (setting > 0) + { + [window->context.nsgl.swapIntervalCond lock]; + window->context.nsgl.swapIntervalsPassed++; + [window->context.nsgl.swapIntervalCond signal]; + [window->context.nsgl.swapIntervalCond unlock]; + } + + return kCVReturnSuccess; +} + static void makeContextCurrentNSGL(_GLFWwindow* window) { if (window) @@ -44,6 +65,18 @@ static void makeContextCurrentNSGL(_GLFWwindow* window) static void swapBuffersNSGL(_GLFWwindow* window) { + + const int setting = atomic_load(&window->context.nsgl.swapInterval); + if (setting > 0) + { + [window->context.nsgl.swapIntervalCond lock]; + do + { + [window->context.nsgl.swapIntervalCond wait]; + } while (window->context.nsgl.swapIntervalsPassed % setting != 0); + window->context.nsgl.swapIntervalsPassed = 0; + [window->context.nsgl.swapIntervalCond unlock]; + } // ARP appears to be unnecessary, but this is future-proof [window->context.nsgl.object flushBuffer]; } @@ -52,9 +85,11 @@ static void swapIntervalNSGL(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - GLint sync = interval; - [window->context.nsgl.object setValues:&sync - forParameter:NSOpenGLContextParameterSwapInterval]; + atomic_store(&window->context.nsgl.swapInterval, interval); + [window->context.nsgl.swapIntervalCond lock]; + window->context.nsgl.swapIntervalsPassed = 0; + + [window->context.nsgl.swapIntervalCond unlock]; } static int extensionSupportedNSGL(const char* extension) @@ -316,6 +351,18 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, window->context.getProcAddress = getProcAddressNSGL; window->context.destroy = destroyContextNSGL; + CVDisplayLinkCreateWithActiveCGDisplays(&window->context.nsgl.displayLink); + CVDisplayLinkSetOutputCallback(window->context.nsgl.displayLink, + &displayLinkCallback, + window); + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext( + window->context.nsgl.displayLink, + (CGLContextObj)window->context.nsgl.object, + (CGLPixelFormatObj)window->context.nsgl.pixelFormat); + CVDisplayLinkStart(window->context.nsgl.displayLink); + + window->context.nsgl.swapIntervalCond = [NSCondition new]; + return GLFW_TRUE; }