From 9fc5fd1375e8ad8f3195451602980fc713e8b996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Wed, 25 Dec 2019 17:09:38 +0100 Subject: [PATCH] Cocoa: Replace display link with IOKit query This removes the final dependency on CoreVideo, using a display link to get the refresh rate of monitors where Core Graphics report a refresh rate of zero. Instead we now query the I/O registry directly, similarly to what the display link does at creation. Thanks to @OneSadCookie for pointers to this solution. (cherry picked from commit 4ec7daf3e92440efab8dac7c1f4c60707d990ed0) --- CMakeLists.txt | 5 ++- README.md | 1 + docs/build.dox | 6 ++-- src/cocoa_monitor.m | 73 +++++++++++++++++++++++++++++++++++--------- src/cocoa_platform.h | 2 -- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96e9e041..8086d422 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,11 +282,10 @@ if (_GLFW_COCOA) list(APPEND glfw_LIBRARIES "-framework Cocoa" "-framework IOKit" - "-framework CoreFoundation" - "-framework CoreVideo") + "-framework CoreFoundation") set(glfw_PKG_DEPS "") - set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo") + set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation") endif() #-------------------------------------------------------------------- diff --git a/README.md b/README.md index 01dbcdc3..083d9c48 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ information on what to include when reporting a bug. event (#1490) - [Win32] Bugfix: The window hint `GLFW_MAXIMIZED` did not move or resize the window (#1499) + - [Cocoa] Removed dependency on the CoreVideo framework - [Cocoa] Bugfix: `glfwSetWindowSize` used a bottom-left anchor point (#1553) - [Cocoa] Bugfix: Window remained on screen after destruction until event poll (#1412) diff --git a/docs/build.dox b/docs/build.dox index 65646aa2..f957ca9a 100644 --- a/docs/build.dox +++ b/docs/build.dox @@ -354,8 +354,8 @@ If you are using the dynamic library version of GLFW, add it to the project dependencies. If you are using the static library version of GLFW, add it and the Cocoa, -OpenGL, IOKit and CoreVideo frameworks to the project as dependencies. They can -all be found in `/System/Library/Frameworks`. +OpenGL and IOKit frameworks to the project as dependencies. They can all be +found in `/System/Library/Frameworks`. @subsection build_link_osx With command-line on macOS @@ -369,7 +369,7 @@ the `-l` and `-framework` switches. If you are using the dynamic GLFW library, which is named `libglfw.3.dylib`, do: @code{.sh} -cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo +cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit @endcode If you are using the static library, named `libglfw3.a`, substitute `-lglfw3` diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 13d463f1..8ef94a3b 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -234,26 +234,65 @@ static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor) return GLFW_FALSE; } -// Returns a fallback refresh rate for when Core Graphics says it is zero +// Returns the display refresh rate queried from the I/O registry // -static double getFallbackRefreshRate(_GLFWmonitor* monitor) +static double getFallbackRefreshRate(CGDirectDisplayID displayID) { - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(monitor->ns.displayID); - double refreshRate = CGDisplayModeGetRefreshRate(mode); - CGDisplayModeRelease(mode); + double refreshRate = 60.0; - if (refreshRate == 0.0) + io_iterator_t it; + io_service_t service; + + if (IOServiceGetMatchingServices(kIOMasterPortDefault, + IOServiceMatching("IOFramebuffer"), + &it) != 0) { - CVDisplayLinkRef link = NULL; - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); - - const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - if (!(time.flags & kCVTimeIsIndefinite)) - refreshRate = (int) (time.timeScale / (double) time.timeValue); - - CVDisplayLinkRelease(link); + return refreshRate; } + while ((service = IOIteratorNext(it)) != 0) + { + const CFNumberRef indexRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFramebufferOpenGLIndex"), + kCFAllocatorDefault, + kNilOptions); + if (!indexRef) + continue; + + uint32_t index = 0; + CFNumberGetValue(indexRef, kCFNumberIntType, &index); + CFRelease(indexRef); + + if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID) + continue; + + const CFNumberRef clockRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFBCurrentPixelClock"), + kCFAllocatorDefault, + kNilOptions); + const CFNumberRef countRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFBCurrentPixelCount"), + kCFAllocatorDefault, + kNilOptions); + if (!clockRef || !countRef) + break; + + uint32_t clock = 0, count = 0; + CFNumberGetValue(clockRef, kCFNumberIntType, &clock); + CFNumberGetValue(countRef, kCFNumberIntType, &count); + CFRelease(clockRef); + CFRelease(countRef); + + if (clock > 0 && count > 0) + refreshRate = clock / (double) count; + + break; + } + + IOObjectRelease(it); return refreshRate; } @@ -310,10 +349,14 @@ void _glfwPollMonitorsNS(void) _GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; monitor->ns.unitNumber = unitNumber; - monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(monitor); free(name); + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]); + if (CGDisplayModeGetRefreshRate(mode) == 0.0) + monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]); + CGDisplayModeRelease(mode); + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 2b7371a1..fbe71bf2 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -28,8 +28,6 @@ #include #include -#include -#include // NOTE: All of NSGL was deprecated in the 10.14 SDK // This disables the pointless warnings for every symbol we use