zdoom-macos-deps/patch/glfw-fix-vsync.diff
2025-03-17 12:02:49 +02:00

190 lines
6.7 KiB
Diff

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1057a6f9..36b3fe0b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -151,10 +151,11 @@ endif()
if (GLFW_BUILD_COCOA)
target_link_libraries(glfw PRIVATE "-framework Cocoa"
"-framework IOKit"
- "-framework CoreFoundation")
+ "-framework CoreFoundation"
+ "-framework CoreVideo")
set(glfw_PKG_DEPS "")
- set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation")
+ set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo")
endif()
if (GLFW_BUILD_WAYLAND)
diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h
index 39914554..ad32e83d 100644
--- a/src/cocoa_platform.h
+++ b/src/cocoa_platform.h
@@ -37,8 +37,10 @@
#if defined(__OBJC__)
#import <Cocoa/Cocoa.h>
+#import <CoreVideo/CoreVideo.h>
#else
typedef void* id;
+typedef void* CVDisplayLinkRef;
#endif
// NOTE: Many Cocoa enum values have been renamed and we need to build across
@@ -124,6 +126,10 @@ typedef struct _GLFWcontextNSGL
{
id pixelFormat;
id object;
+ int swapInterval;
+ int swapIntervalsPassed;
+ id swapIntervalCond;
+ CVDisplayLinkRef displayLink;
} _GLFWcontextNSGL;
// NSGL-specific global data
@@ -299,4 +305,5 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextNSGL(_GLFWwindow* window);
+void _glfwUpdateDisplayLinkNSGL(_GLFWwindow* window);
diff --git a/src/cocoa_window.m b/src/cocoa_window.m
index 0dcf0a38..a4a7ae41 100644
--- a/src/cocoa_window.m
+++ b/src/cocoa_window.m
@@ -320,6 +320,12 @@ - (void)windowDidChangeOcclusionState:(NSNotification* )notification
#endif
}
+- (void)windowDidChangeScreen:(NSNotification *)notification
+{
+ if (window->context.source == GLFW_NATIVE_CONTEXT_API)
+ _glfwUpdateDisplayLinkNSGL(window);
+}
+
@end
diff --git a/src/nsgl_context.m b/src/nsgl_context.m
index daa8367a..b2c109d2 100644
--- a/src/nsgl_context.m
+++ b/src/nsgl_context.m
@@ -45,30 +45,42 @@ static void makeContextCurrentNSGL(_GLFWwindow* window)
} // autoreleasepool
}
+
+static CVReturn nsglDisplayLinkCallback(CVDisplayLinkRef displayLink,
+ const CVTimeStamp* now,
+ const CVTimeStamp* outputTime,
+ CVOptionFlags flagsIn,
+ CVOptionFlags* flagsOut,
+ void* userContext)
+{
+ _GLFWcontextNSGL* nsgl = (_GLFWcontextNSGL*)userContext;
+ NSCondition* intervalCond = nsgl->swapIntervalCond;
+
+ [intervalCond lock];
+ ++nsgl->swapIntervalsPassed;
+ [intervalCond signal];
+ [intervalCond unlock];
+
+ return kCVReturnSuccess;
+}
+
static void swapBuffersNSGL(_GLFWwindow* window)
{
@autoreleasepool {
- // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to
- // windows with a non-visible occlusion state
- if (window->ns.occluded)
+ if (window->context.nsgl.swapInterval > 0)
{
- int interval = 0;
- [window->context.nsgl.object getValues:&interval
- forParameter:NSOpenGLContextParameterSwapInterval];
+ [window->context.nsgl.swapIntervalCond lock];
- if (interval > 0)
+ do
{
- const double framerate = 60.0;
- const uint64_t frequency = _glfwPlatformGetTimerFrequency();
- const uint64_t value = _glfwPlatformGetTimerValue();
-
- const double elapsed = value / (double) frequency;
- const double period = 1.0 / framerate;
- const double delay = period - fmod(elapsed, period);
-
- usleep(floorl(delay * 1e6));
+ // do-while guarantees at least one swap interval has occurred.
+ [window->context.nsgl.swapIntervalCond wait];
}
+ while (window->context.nsgl.swapIntervalsPassed % window->context.nsgl.swapInterval != 0);
+
+ window->context.nsgl.swapIntervalsPassed = 0;
+ [window->context.nsgl.swapIntervalCond unlock];
}
[window->context.nsgl.object flushBuffer];
@@ -83,8 +95,7 @@ static void swapIntervalNSGL(int interval)
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
assert(window != NULL);
- [window->context.nsgl.object setValues:&interval
- forParameter:NSOpenGLContextParameterSwapInterval];
+ window->context.nsgl.swapInterval = interval;
} // autoreleasepool
}
@@ -113,6 +124,13 @@ static void destroyContextNSGL(_GLFWwindow* window)
{
@autoreleasepool {
+ CVDisplayLinkStop(window->context.nsgl.displayLink);
+ CVDisplayLinkRelease(window->context.nsgl.displayLink);
+ window->context.nsgl.displayLink = NULL;
+
+ [window->context.nsgl.swapIntervalCond release];
+ window->context.nsgl.swapIntervalCond = nil;
+
[window->context.nsgl.pixelFormat release];
window->context.nsgl.pixelFormat = nil;
@@ -344,6 +362,21 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
[window->context.nsgl.object setView:window->ns.view];
+ window->context.nsgl.swapInterval = 0; // Default value of NSGL swap interval
+ window->context.nsgl.swapIntervalsPassed = 0;
+ window->context.nsgl.swapIntervalCond = [[NSCondition alloc] init];
+
+ // Explicitly set NSGL swap interval to 0, since CVDisplayLink will be used
+ // instead.
+ int swapInterval = 0;
+ [window->context.nsgl.object setValues:&swapInterval
+ forParameter:NSOpenGLContextParameterSwapInterval];
+
+ CVDisplayLinkCreateWithActiveCGDisplays(&window->context.nsgl.displayLink);
+ CVDisplayLinkSetOutputCallback(window->context.nsgl.displayLink, &nsglDisplayLinkCallback, &window->context.nsgl);
+ _glfwUpdateDisplayLinkNSGL(window);
+ CVDisplayLinkStart(window->context.nsgl.displayLink);
+
window->context.makeCurrent = makeContextCurrentNSGL;
window->context.swapBuffers = swapBuffersNSGL;
window->context.swapInterval = swapIntervalNSGL;
@@ -354,6 +387,13 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
return GLFW_TRUE;
}
+void _glfwUpdateDisplayLinkNSGL(_GLFWwindow* window)
+{
+ CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(window->context.nsgl.displayLink,
+ [window->context.nsgl.object CGLContextObj],
+ [window->context.nsgl.pixelFormat CGLPixelFormatObj]);
+}
+
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////