Possible fix for #3890
Try to ensure we have a functioning displaylink always. GLFW skips over sleeping monitors during a poll and also had a bug where the display link was not re-created for a monitor that already had a glfw monitor entry. Also add a bunch more debug reporting
This commit is contained in:
parent
656f49f2ff
commit
ade4e67b51
@ -41,7 +41,8 @@
|
|||||||
|
|
||||||
// Get the name of the specified display, or NULL
|
// Get the name of the specified display, or NULL
|
||||||
//
|
//
|
||||||
static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
|
static char*
|
||||||
|
getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
|
||||||
{
|
{
|
||||||
// IOKit doesn't work on Apple Silicon anymore
|
// IOKit doesn't work on Apple Silicon anymore
|
||||||
// Luckily, 10.15 introduced -[NSScreen localizedName].
|
// Luckily, 10.15 introduced -[NSScreen localizedName].
|
||||||
@ -51,10 +52,11 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
|
|||||||
if ([screen respondsToSelector:@selector(localizedName)])
|
if ([screen respondsToSelector:@selector(localizedName)])
|
||||||
{
|
{
|
||||||
NSString* name = [screen valueForKey:@"localizedName"];
|
NSString* name = [screen valueForKey:@"localizedName"];
|
||||||
if (name)
|
if (name) {
|
||||||
return _glfw_strdup([name UTF8String]);
|
return _glfw_strdup([name UTF8String]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
io_iterator_t it;
|
io_iterator_t it;
|
||||||
io_service_t service;
|
io_service_t service;
|
||||||
CFDictionaryRef info;
|
CFDictionaryRef info;
|
||||||
@ -64,7 +66,7 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
|
|||||||
&it) != 0)
|
&it) != 0)
|
||||||
{
|
{
|
||||||
// This may happen if a desktop Mac is running headless
|
// This may happen if a desktop Mac is running headless
|
||||||
return _glfw_strdup("Display");
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((service = IOIteratorNext(it)) != 0)
|
while ((service = IOIteratorNext(it)) != 0)
|
||||||
@ -102,7 +104,7 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
|
|||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Cocoa: Failed to find service port for display");
|
"Cocoa: Failed to find service port for display");
|
||||||
return _glfw_strdup("Display");
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFDictionaryRef names =
|
CFDictionaryRef names =
|
||||||
@ -115,7 +117,7 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
|
|||||||
{
|
{
|
||||||
// This may happen if a desktop Mac is running headless
|
// This may happen if a desktop Mac is running headless
|
||||||
CFRelease(info);
|
CFRelease(info);
|
||||||
return _glfw_strdup("Display");
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CFIndex size =
|
const CFIndex size =
|
||||||
@ -326,11 +328,9 @@ void _glfwClearDisplayLinks() {
|
|||||||
if (_glfw.ns.displayLinks.entries[i].displayLink) {
|
if (_glfw.ns.displayLinks.entries[i].displayLink) {
|
||||||
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||||
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
|
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||||
_glfw.ns.displayLinks.entries[i].displayLink = nil;
|
|
||||||
_glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0;
|
|
||||||
_glfw.ns.displayLinks.entries[i].first_unserviced_render_frame_request_at = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memset(_glfw.ns.displayLinks.entries, 0, sizeof(_GLFWDisplayLinkNS) * _glfw.ns.displayLinks.count);
|
||||||
_glfw.ns.displayLinks.count = 0;
|
_glfw.ns.displayLinks.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,16 +352,21 @@ _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
|
|||||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
|
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
_GLFWDisplayLinkNS*
|
||||||
createDisplayLink(CGDirectDisplayID displayID) {
|
_glfw_create_display_link(CGDirectDisplayID displayID) {
|
||||||
if (_glfw.ns.displayLinks.count >= sizeof(_glfw.ns.displayLinks.entries)/sizeof(_glfw.ns.displayLinks.entries[0]) - 1) return;
|
if (_glfw.ns.displayLinks.count >= arraysz(_glfw.ns.displayLinks.entries) - 1) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
|
// already created in this run
|
||||||
|
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return _glfw.ns.displayLinks.entries + i;
|
||||||
}
|
}
|
||||||
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
|
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
|
||||||
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
|
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
|
||||||
entry->displayID = displayID;
|
entry->displayID = displayID;
|
||||||
_glfw_create_cv_display_link(entry);
|
_glfw_create_cv_display_link(entry);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll for changes in the set of connected monitors
|
// Poll for changes in the set of connected monitors
|
||||||
@ -369,11 +374,13 @@ createDisplayLink(CGDirectDisplayID displayID) {
|
|||||||
void _glfwPollMonitorsNS(void)
|
void _glfwPollMonitorsNS(void)
|
||||||
{
|
{
|
||||||
uint32_t displayCount;
|
uint32_t displayCount;
|
||||||
|
|
||||||
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||||
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||||
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||||
_glfwClearDisplayLinks();
|
_glfwClearDisplayLinks();
|
||||||
|
if (_glfw.hints.init.debugRendering) {
|
||||||
|
fprintf(stderr, "Polling for monitors: %u found\n", displayCount);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < _glfw.monitorCount; i++)
|
for (int i = 0; i < _glfw.monitorCount; i++)
|
||||||
_glfw.monitors[i]->ns.screen = nil;
|
_glfw.monitors[i]->ns.screen = nil;
|
||||||
@ -390,8 +397,10 @@ void _glfwPollMonitorsNS(void)
|
|||||||
|
|
||||||
for (uint32_t i = 0; i < displayCount; i++)
|
for (uint32_t i = 0; i < displayCount; i++)
|
||||||
{
|
{
|
||||||
if (CGDisplayIsAsleep(displays[i]))
|
if (CGDisplayIsAsleep(displays[i])) {
|
||||||
|
if (_glfw.hints.init.debugRendering) fprintf(stderr, "Ignoring sleeping display: %u", displays[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
|
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
|
||||||
NSScreen* screen = nil;
|
NSScreen* screen = nil;
|
||||||
@ -415,7 +424,9 @@ void _glfwPollMonitorsNS(void)
|
|||||||
{
|
{
|
||||||
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
|
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
|
||||||
{
|
{
|
||||||
|
disconnected[j]->ns.displayID = displays[i];
|
||||||
disconnected[j]->ns.screen = screen;
|
disconnected[j]->ns.screen = screen;
|
||||||
|
_glfw_create_display_link(displays[i]);
|
||||||
disconnected[j] = NULL;
|
disconnected[j] = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -426,14 +437,17 @@ void _glfwPollMonitorsNS(void)
|
|||||||
|
|
||||||
const CGSize size = CGDisplayScreenSize(displays[i]);
|
const CGSize size = CGDisplayScreenSize(displays[i]);
|
||||||
char* name = getDisplayName(displays[i], screen);
|
char* name = getDisplayName(displays[i], screen);
|
||||||
if (!name)
|
if (!name) {
|
||||||
continue;
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Failed to get name for display, using generic name");
|
||||||
|
name = _glfw_strdup("Display with no name");
|
||||||
|
}
|
||||||
|
|
||||||
_GLFWmonitor* monitor = _glfwAllocMonitor(name, (int)size.width, (int)size.height);
|
_GLFWmonitor* monitor = _glfwAllocMonitor(name, (int)size.width, (int)size.height);
|
||||||
monitor->ns.displayID = displays[i];
|
monitor->ns.displayID = displays[i];
|
||||||
monitor->ns.unitNumber = unitNumber;
|
monitor->ns.unitNumber = unitNumber;
|
||||||
monitor->ns.screen = screen;
|
monitor->ns.screen = screen;
|
||||||
createDisplayLink(monitor->ns.displayID);
|
_glfw_create_display_link(monitor->ns.displayID);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
|
|||||||
1
glfw/cocoa_platform.h
vendored
1
glfw/cocoa_platform.h
vendored
@ -250,3 +250,4 @@ void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
|||||||
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
|
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
|
||||||
void _glfwCocoaPostEmptyEvent(void);
|
void _glfwCocoaPostEmptyEvent(void);
|
||||||
void _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry);
|
void _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry);
|
||||||
|
_GLFWDisplayLinkNS* _glfw_create_display_link(CGDirectDisplayID);
|
||||||
|
|||||||
@ -337,9 +337,12 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
|||||||
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
|
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
|
||||||
}
|
}
|
||||||
monotonic_t now = glfwGetTime();
|
monotonic_t now = glfwGetTime();
|
||||||
|
bool found_display_link = false;
|
||||||
|
_GLFWDisplayLinkNS *dl = NULL;
|
||||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||||
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
dl = &_glfw.ns.displayLinks.entries[i];
|
||||||
if (dl->displayID == displayID) {
|
if (dl->displayID == displayID) {
|
||||||
|
found_display_link = true;
|
||||||
dl->lastRenderFrameRequestedAt = now;
|
dl->lastRenderFrameRequestedAt = now;
|
||||||
if (!dl->first_unserviced_render_frame_request_at) dl->first_unserviced_render_frame_request_at = now;
|
if (!dl->first_unserviced_render_frame_request_at) dl->first_unserviced_render_frame_request_at = now;
|
||||||
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||||
@ -359,6 +362,13 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
|||||||
dl->first_unserviced_render_frame_request_at = 0;
|
dl->first_unserviced_render_frame_request_at = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!found_display_link) {
|
||||||
|
dl = _glfw_create_display_link(displayID);
|
||||||
|
if (dl) {
|
||||||
|
dl->lastRenderFrameRequestedAt = now;
|
||||||
|
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user