mirror of
https://github.com/glfw/glfw.git
synced 2024-11-12 17:51:48 +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:
parent
4e3204d86d
commit
82ca58da04
12
src/nsgl_context.h
Normal file → Executable file
12
src/nsgl_context.h
Normal file → Executable file
@ -27,13 +27,21 @@
|
|||||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
|
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
|
||||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
|
||||||
|
|
||||||
|
#import <CoreVideo/CoreVideo.h>
|
||||||
|
|
||||||
|
#include <stdatomic.h>
|
||||||
|
|
||||||
|
|
||||||
// NSGL-specific per-context data
|
// NSGL-specific per-context data
|
||||||
//
|
//
|
||||||
typedef struct _GLFWcontextNSGL
|
typedef struct _GLFWcontextNSGL
|
||||||
{
|
{
|
||||||
id pixelFormat;
|
id pixelFormat;
|
||||||
id object;
|
id object;
|
||||||
|
CVDisplayLinkRef displayLink;
|
||||||
|
atomic_int swapInterval;
|
||||||
|
int swapIntervalsPassed;
|
||||||
|
id swapIntervalCond;
|
||||||
|
|
||||||
} _GLFWcontextNSGL;
|
} _GLFWcontextNSGL;
|
||||||
|
|
||||||
|
56
src/nsgl_context.m
Normal file → Executable file
56
src/nsgl_context.m
Normal file → Executable file
@ -31,6 +31,27 @@
|
|||||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||||
#endif
|
#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)
|
static void makeContextCurrentNSGL(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
@ -48,21 +69,33 @@ static void makeContextCurrentNSGL(_GLFWwindow* window)
|
|||||||
static void swapBuffersNSGL(_GLFWwindow* window)
|
static void swapBuffersNSGL(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@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
|
// ARP appears to be unnecessary, but this is future-proof
|
||||||
[window->context.nsgl.object flushBuffer];
|
[window->context.nsgl.object flushBuffer];
|
||||||
|
|
||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapIntervalNSGL(int interval)
|
static void swapIntervalNSGL(int interval)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
atomic_store(&window->context.nsgl.swapInterval, interval);
|
||||||
GLint sync = interval;
|
[window->context.nsgl.swapIntervalCond lock];
|
||||||
[window->context.nsgl.object setValues:&sync
|
window->context.nsgl.swapIntervalsPassed = 0;
|
||||||
forParameter:NSOpenGLContextParameterSwapInterval];
|
[window->context.nsgl.swapIntervalCond unlock];
|
||||||
|
|
||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +363,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
|||||||
window->context.getProcAddress = getProcAddressNSGL;
|
window->context.getProcAddress = getProcAddressNSGL;
|
||||||
window->context.destroy = destroyContextNSGL;
|
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;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user