mirror of
https://github.com/glfw/glfw.git
synced 2026-09-21 16:44:11 +00:00
NSGL: Implement swap interval with CVDisplayLink
This fixes OpenGL swap interval (vsync) on macOS 10.14 Mojave by using CVDisplayLink to synchronise to the monitor refresh rate rather than setting NSOpenGLContextParameterSwapInterval. Solution based on advice provided by @rcgordon. Closes #1417.
This commit is contained in:
Regular → Executable
+50
-6
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user