How to resolve CGDirectDisplayID changing issues on newer multi-GPU Apple laptops in Core Foundation
Posted
by Dave Gallagher
on Stack Overflow
See other posts from Stack Overflow
or by Dave Gallagher
Published on 2010-05-18T23:26:10Z
Indexed on
2010/05/18
23:30 UTC
Read the original article
Hit count: 376
In Mac OS X, every display gets a unique CGDirectDisplayID
number assigned to it. You can use CGGetActiveDisplayList(
) or [NSScreen screens]
to access them, among others. Per Apple's docs:
A display ID can persist across processes and system reboot, and typically remains constant as long as certain display parameters do not change.
On newer mid-2010 MacBook Pro's, Apple started using auto-switching Intel/nVidia graphics. Laptops have two GPU's, a low-powered Intel, and a high-powered nVidia. Previous dual-GPU laptops (2009 models) didn't have auto-GPU switching, and required the user to make a settings change, logoff, and then logon again to make a GPU switch occur. Even older systems only had one GPU.
There's an issue with the mid-2010 models where CGDirectDisplayID's don't remain the same when a display switches from one GPU to the next. For example:
- Laptop powers on.
- Built-In LCD Screen is driven by Intel chipset. Display ID: 30002
- External Display is plugged in.
- Built-In LCD Screen switches to nVidia chipset. It's display ID changes: 30004
- External Display is driven by nVidia chipset.
- ...at this point, the Intel chipset is dormant...
- User unplugs External Display.
- Built-In LCD Screen switches back to Intel chipset. It's display ID changes back to original: 30002
My question is, how can I match an old display ID to a new display ID when they alter due to a GPU change?
Thought about:
I've noticed that the display ID only changes by 2, but I don't have enough test Mac's available to determine if this is common to all new MacBook Pro's, or just mine. Kind of a kludge if "just check for display ID's which are +/-2 from one another" works, anyway.
Tried:
CGDisplayRegisterReconfigurationCallback()
, which notifies before-and-after when displays are going to change, has no matching logic. Putting something like this inside a method registered with it doesn't work:
// Run before display settings change:
CGDirectDisplayID directDisplayID = ...;
io_service_t servicePort = CGDisplayIOServicePort(directDisplayID);
CFDictionaryRef oldInfoDict = IODisplayCreateInfoDictionary(servicePort, kIODisplayMatchingInfo);
// ...display settings change...
// Run after display settings change:
CGDirectDisplayID directDisplayID = ...;
io_service_t servicePort = CGDisplayIOServicePort(directDisplayID);
CFDictionaryRef newInfoDict = IODisplayCreateInfoDictionary(servicePort, kIODisplayMatchingInfo);
BOOL match = IODisplayMatchDictionaries(oldInfoDict, newInfoDict, 0);
if (match)
NSLog(@"Displays are a match");
else
NSLog(@"Displays are not a match");
What's happening above is I'm caching oldInfoDict before display settings change, letting them change, and then comparing it to newInfoDict by using IODisplayMatchDictionaries()
, which will say either "yes, both displays are the same!" or "no, both displays are not the same." Unfortunately, it does not return YES if GPU's have changed for a monitor. Example of the dictionary's it's comparing:
// oldInfoDict (Display ID: 30002)
oldInfoDict: {
DisplayProductID = 40144;
DisplayVendorID = 1552;
IODisplayLocation = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/IGPU@2/AppleIntelFramebuffer/display0/AppleBacklightDisplay";
}
// newInfoDict (Display ID: 30004)
newInfoDict: {
DisplayProductID = 40144;
DisplayVendorID = 1552;
IODisplayLocation = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/P0P2@1/IOPCI2PCIBridge/GFX0@0/NVDA,Display-A@0/NVDA/display0/AppleBacklightDisplay";
}
As you can see, the IODisplayLocation
key changes when GPU's are switched, hence IODisplayMatchDictionaries()
doesn't work. I can, theoretically, compared just the DisplayProductID
and DisplayVendorID
keys, but I'm writing end-user software, and am worried of a situation where users have two or more identical monitors plugged in.
Any help is greatly appreciated! :)
© Stack Overflow or respective owner