gpt4 book ai didi

objective-c - 如何解决 Core Foundation/IO Kit 中较新的多 GPU Apple 笔记本电脑上的 CGDirectDisplayID 更改问题?

转载 作者:太空狗 更新时间:2023-10-30 03:26:39 25 4
gpt4 key购买 nike

在 Mac OS X 中,每个显示器都有一个分配给它的唯一 CGDirectDisplayID 编号。您可以使用 CGGetActiveDisplayList() 或 [NSScreen screens] 访问它们等。每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.

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

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

  1. 笔记本电脑开机。
  2. 内置 LCD屏幕 由英特尔芯片组驱动。显示 ID:30002
  3. 外部显示器已插入。
  4. 内置LCD 屏幕 切换到 nVidia芯片组。它的显示 ID 更改:30004
  5. External Display 驱动通过 nVidia 芯片组。
  6. ...在这一点上,英特尔芯片组处于休眠状态...
  7. 用户拔下外部显示器
  8. 内置LCD 屏幕 切换回英特尔芯片组。这是显示ID变回原来的:30002

我的问题是,当旧显示器 ID 因 GPU 更改而改变时,我如何将它们与新显示器 ID 匹配?


思考:

我注意到显示器 ID 只改变了 2,但我没有足够的测试 Mac 可用以确定这是否对所有新 MacBook Pro 都通用,或者只是我的。无论如何,如果“只检查彼此相差 +/-2 的显示 ID”是否有效,那就有点麻烦了。


尝试过:

CGDisplayRegisterReconfigurationCallback(),它在显示将要改变之前和之后通知,没有匹配逻辑。把这样的东西放在一个用它注册的方法里是行不通的:

// 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. 比较 oldInfoDictnewInfoDict
  5. IODisplayMatchDictionaries() 返回一个 BOOL,要么 YES 它们相同,要么 NO 它们不同。

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

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

如您所见,切换 GPU 时 IODisplayLocation 键会发生变化,因此 IODisplayMatchDictionaries() 不起作用。

理论上,我可以只比较 DisplayProductIDDisplayVendorID 键,但我正在编写最终用户软件,并且担心用户有两个键的情况或插入更多相同的显示器(意味着它们将具有相同的 DisplayProductID/DisplayVendorID)。换句话说,这是一个不够完美的解决方案,容易出现潜在故障。


非常感谢任何帮助! :)

最佳答案

使用 CFUUIDRef,它可以通过以下方式获得:

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

CGDisplayGetDisplayIDFromUUID(CFUUIDRef uuid)

这就是我用来唯一标识显示器的方法,即使它们的 CGDirectDisplayID 发生变化,例如插入到不同的端口。不幸的是,Apple 没有正确记录这些功能,但我在多台具有多个显示器的 Mac 上进行的测试表明,即使在重新启动后,获得的 CFUUIDRef 也是唯一且一致的,无论 CGDirectDisplayID 是否因任何原因发生更改。

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

这些 API 调用在 10.7 - 10.12 的 ApplicationServices 和 10.13 之后的 ColorSync 中可用。

关于objective-c - 如何解决 Core Foundation/IO Kit 中较新的多 GPU Apple 笔记本电脑上的 CGDirectDisplayID 更改问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2861871/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com