Skip to content

Commit c0f0423

Browse files
committed
Move CVDisplayLink code into its own module
Apple has deprecated CVDisplayLink in favor of CADisplayLink which has different semantics. So turn off deprecation warnings for CVDisplayLink related code only until I can be bothered to port it to CADisplayLink.
1 parent c127517 commit c0f0423

File tree

5 files changed

+172
-149
lines changed

5 files changed

+172
-149
lines changed

glfw/cocoa_displaylink.m

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* cocoa_displaylink.m
3+
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
4+
*
5+
* Distributed under terms of the GPL3 license.
6+
*/
7+
8+
// CVDisplayLink is deprecated
9+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
10+
11+
#include "internal.h"
12+
#include <CoreVideo/CVDisplayLink.h>
13+
14+
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL s_to_monotonic_t(30ll)
15+
16+
typedef struct _GLFWDisplayLinkNS
17+
{
18+
CVDisplayLinkRef displayLink;
19+
CGDirectDisplayID displayID;
20+
monotonic_t lastRenderFrameRequestedAt, first_unserviced_render_frame_request_at;
21+
} _GLFWDisplayLinkNS;
22+
23+
static struct {
24+
_GLFWDisplayLinkNS entries[256];
25+
size_t count;
26+
} displayLinks = {0};
27+
28+
static CGDirectDisplayID
29+
displayIDForWindow(_GLFWwindow *w) {
30+
NSWindow *nw = w->ns.object;
31+
NSDictionary *dict = [nw.screen deviceDescription];
32+
NSNumber *displayIDns = dict[@"NSScreenNumber"];
33+
if (displayIDns) return [displayIDns unsignedIntValue];
34+
return (CGDirectDisplayID)-1;
35+
}
36+
37+
void
38+
_glfwClearDisplayLinks(void) {
39+
for (size_t i = 0; i < displayLinks.count; i++) {
40+
if (displayLinks.entries[i].displayLink) {
41+
CVDisplayLinkStop(displayLinks.entries[i].displayLink);
42+
CVDisplayLinkRelease(displayLinks.entries[i].displayLink);
43+
}
44+
}
45+
memset(displayLinks.entries, 0, sizeof(_GLFWDisplayLinkNS) * displayLinks.count);
46+
displayLinks.count = 0;
47+
}
48+
49+
static CVReturn
50+
displayLinkCallback(
51+
CVDisplayLinkRef displayLink UNUSED,
52+
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
53+
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo) {
54+
CGDirectDisplayID displayID = (uintptr_t)userInfo;
55+
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
56+
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
57+
[arg release];
58+
return kCVReturnSuccess;
59+
}
60+
61+
static void
62+
_glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
63+
CVDisplayLinkCreateWithCGDisplay(entry->displayID, &entry->displayLink);
64+
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
65+
}
66+
67+
unsigned
68+
_glfwCreateDisplayLink(CGDirectDisplayID displayID) {
69+
if (displayLinks.count >= arraysz(displayLinks.entries) - 1) {
70+
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
71+
return displayLinks.count;
72+
}
73+
for (unsigned i = 0; i < displayLinks.count; i++) {
74+
// already created in this run
75+
if (displayLinks.entries[i].displayID == displayID) return i;
76+
}
77+
_GLFWDisplayLinkNS *entry = &displayLinks.entries[displayLinks.count++];
78+
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
79+
entry->displayID = displayID;
80+
_glfw_create_cv_display_link(entry);
81+
return displayLinks.count - 1;
82+
}
83+
84+
static unsigned long long display_link_shutdown_timer = 0;
85+
86+
static void
87+
_glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) {
88+
display_link_shutdown_timer = 0;
89+
for (size_t i = 0; i < displayLinks.count; i++) {
90+
_GLFWDisplayLinkNS *dl = &displayLinks.entries[i];
91+
if (dl->displayLink) CVDisplayLinkStop(dl->displayLink);
92+
dl->lastRenderFrameRequestedAt = 0;
93+
dl->first_unserviced_render_frame_request_at = 0;
94+
}
95+
}
96+
97+
void
98+
_glfwRequestRenderFrame(_GLFWwindow *w) {
99+
CGDirectDisplayID displayID = displayIDForWindow(w);
100+
if (display_link_shutdown_timer) {
101+
_glfwPlatformUpdateTimer(display_link_shutdown_timer, DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, true);
102+
} else {
103+
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
104+
}
105+
monotonic_t now = glfwGetTime();
106+
bool found_display_link = false;
107+
_GLFWDisplayLinkNS *dl = NULL;
108+
for (size_t i = 0; i < displayLinks.count; i++) {
109+
dl = &displayLinks.entries[i];
110+
if (dl->displayID == displayID) {
111+
found_display_link = true;
112+
dl->lastRenderFrameRequestedAt = now;
113+
if (!dl->first_unserviced_render_frame_request_at) dl->first_unserviced_render_frame_request_at = now;
114+
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
115+
else if (now - dl->first_unserviced_render_frame_request_at > s_to_monotonic_t(1ll)) {
116+
// display link is stuck need to recreate it because Apple can't even
117+
// get a simple timer right
118+
CVDisplayLinkRelease(dl->displayLink); dl->displayLink = nil;
119+
dl->first_unserviced_render_frame_request_at = now;
120+
_glfw_create_cv_display_link(dl);
121+
_glfwInputError(GLFW_PLATFORM_ERROR,
122+
"CVDisplayLink stuck possibly because of sleep/screensaver + Apple's incompetence, recreating.");
123+
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
124+
}
125+
} else if (dl->displayLink && dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt >= DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL) {
126+
CVDisplayLinkStop(dl->displayLink);
127+
dl->lastRenderFrameRequestedAt = 0;
128+
dl->first_unserviced_render_frame_request_at = 0;
129+
}
130+
}
131+
if (!found_display_link) {
132+
unsigned idx = _glfwCreateDisplayLink(displayID);
133+
if (idx < displayLinks.count) {
134+
dl = &displayLinks.entries[idx];
135+
dl->lastRenderFrameRequestedAt = now;
136+
dl->first_unserviced_render_frame_request_at = now;
137+
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
138+
}
139+
}
140+
}
141+
142+
void
143+
_glfwDispatchRenderFrame(CGDirectDisplayID displayID) {
144+
_GLFWwindow *w = _glfw.windowListHead;
145+
while (w) {
146+
if (w->ns.renderFrameRequested && displayID == displayIDForWindow(w)) {
147+
w->ns.renderFrameRequested = false;
148+
w->ns.renderFrameCallback((GLFWwindow*)w);
149+
}
150+
w = w->next;
151+
}
152+
for (size_t i = 0; i < displayLinks.count; i++) {
153+
_GLFWDisplayLinkNS *dl = &displayLinks.entries[i];
154+
if (dl->displayID == displayID) {
155+
dl->first_unserviced_render_frame_request_at = 0;
156+
}
157+
}
158+
}
159+
160+

glfw/cocoa_monitor.m

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
// It is fine to use C99 in this file because it will not be built with VS
2828
//========================================================================
2929

30-
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
3130
#include "internal.h"
3231

3332
#include <stdlib.h>
@@ -36,7 +35,6 @@
3635

3736
#include <IOKit/graphics/IOGraphicsLib.h>
3837
#include <CoreVideo/CVBase.h>
39-
#include <CoreVideo/CVDisplayLink.h>
4038
#include <ApplicationServices/ApplicationServices.h>
4139

4240

@@ -324,54 +322,7 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID)
324322
////// GLFW internal API //////
325323
//////////////////////////////////////////////////////////////////////////
326324

327-
void _glfwClearDisplayLinks(void) {
328-
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
329-
if (_glfw.ns.displayLinks.entries[i].displayLink) {
330-
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
331-
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
332-
}
333-
}
334-
memset(_glfw.ns.displayLinks.entries, 0, sizeof(_GLFWDisplayLinkNS) * _glfw.ns.displayLinks.count);
335-
_glfw.ns.displayLinks.count = 0;
336-
}
337-
338-
static CVReturn displayLinkCallback(
339-
CVDisplayLinkRef displayLink UNUSED,
340-
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
341-
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo)
342-
{
343-
CGDirectDisplayID displayID = (uintptr_t)userInfo;
344-
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
345-
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
346-
[arg release];
347-
return kCVReturnSuccess;
348-
}
349-
350-
void
351-
_glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
352-
CVDisplayLinkCreateWithCGDisplay(entry->displayID, &entry->displayLink);
353-
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
354-
}
355-
356-
_GLFWDisplayLinkNS*
357-
_glfw_create_display_link(CGDirectDisplayID displayID) {
358-
if (_glfw.ns.displayLinks.count >= arraysz(_glfw.ns.displayLinks.entries) - 1) {
359-
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
360-
return NULL;
361-
}
362-
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
363-
// already created in this run
364-
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return _glfw.ns.displayLinks.entries + i;
365-
}
366-
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
367-
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
368-
entry->displayID = displayID;
369-
_glfw_create_cv_display_link(entry);
370-
return entry;
371-
}
372-
373325
// Poll for changes in the set of connected monitors
374-
//
375326
void _glfwPollMonitorsNS(void)
376327
{
377328
uint32_t displayCount;
@@ -427,7 +378,7 @@ void _glfwPollMonitorsNS(void)
427378
{
428379
disconnected[j]->ns.displayID = displays[i];
429380
disconnected[j]->ns.screen = screen;
430-
_glfw_create_display_link(displays[i]);
381+
_glfwCreateDisplayLink(displays[i]);
431382
disconnected[j] = NULL;
432383
break;
433384
}
@@ -448,7 +399,7 @@ void _glfwPollMonitorsNS(void)
448399
monitor->ns.displayID = displays[i];
449400
monitor->ns.unitNumber = unitNumber;
450401
monitor->ns.screen = screen;
451-
_glfw_create_display_link(monitor->ns.displayID);
402+
_glfwCreateDisplayLink(monitor->ns.displayID);
452403

453404
free(name);
454405

glfw/cocoa_platform.h

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@
3030
#include <Carbon/Carbon.h>
3131
#if defined(__OBJC__)
3232
#import <Cocoa/Cocoa.h>
33-
#import <CoreVideo/CoreVideo.h>
3433
#else
3534
typedef void* id;
36-
typedef void* CVDisplayLinkRef;
3735
#endif
3836

3937
// NOTE: Many Cocoa enum values have been renamed and we need to build across
@@ -160,13 +158,6 @@ typedef struct _GLFWwindowNS
160158
GLFWcocoarenderframefun resizeCallback;
161159
} _GLFWwindowNS;
162160

163-
typedef struct _GLFWDisplayLinkNS
164-
{
165-
CVDisplayLinkRef displayLink;
166-
CGDirectDisplayID displayID;
167-
monotonic_t lastRenderFrameRequestedAt, first_unserviced_render_frame_request_at;
168-
} _GLFWDisplayLinkNS;
169-
170161
// Cocoa-specific global data
171162
//
172163
typedef struct _GLFWlibraryNS
@@ -199,10 +190,6 @@ typedef struct _GLFWlibraryNS
199190
CFStringRef kPropertyUnicodeKeyLayoutData;
200191
} tis;
201192

202-
struct {
203-
_GLFWDisplayLinkNS entries[256];
204-
size_t count;
205-
} displayLinks;
206193
// the callback to handle url open events
207194
GLFWhandleurlopen url_open_callback;
208195

@@ -244,12 +231,16 @@ float _glfwTransformYNS(float y);
244231

245232
void* _glfwLoadLocalVulkanLoaderNS(void);
246233

234+
235+
// display links
247236
void _glfwClearDisplayLinks(void);
248237
void _glfwRestartDisplayLinks(void);
249-
void _glfwDispatchTickCallback(void);
238+
unsigned _glfwCreateDisplayLink(CGDirectDisplayID);
250239
void _glfwDispatchRenderFrame(CGDirectDisplayID);
251-
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
240+
void _glfwRequestRenderFrame(_GLFWwindow *w);
241+
242+
// event loop
243+
void _glfwDispatchTickCallback(void);
252244
void _glfwCocoaPostEmptyEvent(void);
253-
void _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry);
254-
_GLFWDisplayLinkNS* _glfw_create_display_link(CGDirectDisplayID);
245+
255246
uint32_t vk_to_unicode_key_with_current_layout(uint16_t keycode);

0 commit comments

Comments
 (0)