如何解决Core Foundation/IO Kit中较新的多GPU Apple笔记本电脑上CGDirectDisplayID更改的问题? [英] How to resolve CGDirectDisplayID changing issues on newer multi-GPU Apple laptops in Core Foundation/IO Kit?

查看:161
本文介绍了如何解决Core Foundation/IO Kit中较新的多GPU Apple笔记本电脑上CGDirectDisplayID更改的问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Mac OS X中,每个显示器都会分配一个唯一的CGDirectDisplayID号.您可以使用CGGetActiveDisplayList()或[NSScreen screens]来访问它们.每个 Apple的文档:

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:

显示ID可以持续存在 进程和系统重启,以及 通常只要保持恒定 某些显示参数不 改变.

A display ID can persist across processes and system reboot, and typically remains constant as long as certain display parameters do not change.

在2010年中期更新的MacBook Pro上,Apple开始使用自动切换Intel/nVidia图形的功能.笔记本电脑有两个GPU,一个低功耗的Intel和一个高功耗的nVidia.以前的双GPU笔记本电脑(2009型号)没有自动GPU切换功能,需要用户进行设置更改,注销并再次登录才能进行GPU切换.甚至较旧的系统也只有一个GPU.

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.

2010年中期的型号存在一个问题,当显示器从一个GPU切换到下一个GPU时,CGDirectDisplayID不会保持不变.例如:

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:

  1. 笔记本电脑开机.
  2. 内置 LCD 屏幕由英特尔芯片组驱动. 显示ID: 30002
  3. 外部 显示器已插入.
  4. 内置 LCD屏幕切换到nVidia 芯片组.它的显示ID发生了变化: 30004
  5. 已驱动
  6. 外部显示 由nVidia芯片组提供.
  7. ...在这一点上, 英特尔芯片组处于休眠状态...
  8. 用户拔下外部显示器.
  9. 内置 LCD屏幕切换回 英特尔芯片组.它是显示ID 更改回原始: 30002
  1. Laptop powers on.
  2. Built-In LCD Screen is driven by Intel chipset. Display ID: 30002
  3. External Display is plugged in.
  4. Built-In LCD Screen switches to nVidia chipset. It's display ID changes: 30004
  5. External Display is driven by nVidia chipset.
  6. ...at this point, the Intel chipset is dormant...
  7. User unplugs External Display.
  8. Built-In LCD Screen switches back to Intel chipset. It's display ID changes back to original: 30002

我的问题是,当旧的显示ID由于GPU的变化而改变时,如何将旧的显示ID与新的显示ID匹配?

有关的想法:

我注意到显示ID仅改变了2,但我没有足够的测试Mac来确定这是否对所有新MacBook Pro通用,还是仅属于我.无论如何,只要仅检查彼此之间的+/- 2的显示ID"有效,就有点麻烦了.

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.

尝试过:

CGDisplayRegisterReconfigurationCallback()在显示将要更改时前后通知,但没有匹配逻辑.将这样的东西放入已注册的方法中是行不通的:

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");

上面发生的是:

  1. 在显示设置更改之前,我正在缓存 oldInfoDict .
  2. 等待显示设置更改
  3. 然后使用IODisplayMatchDictionaries()
  4. oldInfoDict newInfoDict
  5. IODisplayMatchDictionaries()返回BOOL,是,它们是相同的,或者是否,它们是不同的.
  1. I'm caching oldInfoDict before display settings change.
  2. Waiting for display settings to change
  3. Then comparing oldInfoDict to newInfoDict by using IODisplayMatchDictionaries()
  4. IODisplayMatchDictionaries() returns a BOOL, either YES they're the same, or NO they're different.

不幸的是,如果同一显示器更改了GPU,IODisplayMatchDictionaries()不会返回YES.这是字典进行比较的示例(请查看IODisplayLocation键):

Unfortunately, IODisplayMatchDictionaries() doesn't return YES if the same display changed GPU's. Here's an example of the dictionary's it's comparing (look at the IODisplayLocation key):

// 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";
}

如您所见,IODisplayLocation键在切换GPU时会更改,因此IODisplayMatchDictionaries()不起作用.

As you can see, the IODisplayLocation key changes when GPU's are switched, hence IODisplayMatchDictionaries() doesn't work.

从理论上讲,我只能比较DisplayProductIDDisplayVendorID键,但是我正在编写最终用户软件,并且担心用户插入两个或多个相同显示器的情况(这意味着他们两者都具有相同的DisplayProductID/DisplayVendorID).换句话说,这是一个不完善的解决方案,可以应对潜在的故障.

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 (meaning they'll both have the same DisplayProductID/DisplayVendorID). In other words, it's a less-than-perfect solution open to potential glitches.

任何帮助将不胜感激! :)

Any help is greatly appreciated! :)

推荐答案

使用CFUUIDRef,可以使用以下方法获得:

Use CFUUIDRef which can be obtained using:

CGDisplayCreateUUIDFromDisplayID(CGDirectDisplayID displayID) 您可以使用以下方法获取显示ID:

CGDisplayCreateUUIDFromDisplayID(CGDirectDisplayID displayID) and you can get the display ID back using:

CGDisplayGetDisplayIDFromUUID(CFUUIDRef uuid)

这就是我用来唯一标识显示器的内容,即使它们的CGDirectDisplayID发生了变化(例如已插入其他端口).不幸的是,Apple并没有正确记录这些功能,但是我在多台Mac电脑上进行的多屏显示测试表明,即使CGDirectDisplayID出于任何原因而更改,即使重启后,获得的CFUUIDRef都是唯一且一致的.

This is what I'm using to uniquely identify displays even when their CGDirectDisplayID changes, for example was plugged into a different port. These functions aren't properly documented by Apple unfortunately, but my testing on multiple Macs with multiple displays shown that the CFUUIDRef obtained is unique and consistent -even after a reboot-, regardless of whether CGDirectDisplayID changed for whatever reason.

要检查显示是否是新的/唯一的,请获取其CGDirectDisplayID并将其转换为CFUUIDRef,然后比较UUID,这是多对一的关系,许多CGDirectDisplayID将映射到单个CFUUIDRef.

To check if a display is new/unique, take its CGDirectDisplayID and convert it to CFUUIDRef, and then compare the UUID, it is a many-to-one relationship, many CGDirectDisplayIDs will map to a single CFUUIDRef.

这些API调用在10.7-10.12的ApplicationServices中可用,从10.13开始在ColorSync中可用.

These API calls are available in ApplicationServices in 10.7 - 10.12, and ColorSync since 10.13.

这篇关于如何解决Core Foundation/IO Kit中较新的多GPU Apple笔记本电脑上CGDirectDisplayID更改的问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆