diff --git a/src/nsgl_context.h b/src/nsgl_context.h old mode 100644 new mode 100755 index 18042dee..76dd3e88 --- a/src/nsgl_context.h +++ b/src/nsgl_context.h @@ -27,13 +27,21 @@ #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl +#import + +#include + // NSGL-specific per-context data // typedef struct _GLFWcontextNSGL { - id pixelFormat; - id object; + id pixelFormat; + id object; + CVDisplayLinkRef displayLink; + atomic_int swapInterval; + int swapIntervalsPassed; + id swapIntervalCond; } _GLFWcontextNSGL; diff --git a/src/nsgl_context.m b/src/nsgl_context.m old mode 100644 new mode 100755 index f3bf2425..d834259d --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -31,6 +31,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) { @autoreleasepool { @@ -48,21 +69,33 @@ static void makeContextCurrentNSGL(_GLFWwindow* window) static void swapBuffersNSGL(_GLFWwindow* window) { @autoreleasepool { + + 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]; + } // autoreleasepool } static void swapIntervalNSGL(int interval) { @autoreleasepool { - _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]; } // autoreleasepool } @@ -330,6 +363,17 @@ 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; }