【问题标题】:CGDirectDisplayID, multiple GPUs, deprecated CGDisplayIOServicePort and uniquely identifying displaysCGDirectDisplayID、多个 GPU、已弃用的 CGDisplayIOServicePort 和唯一标识显示器
【发布时间】:2014-08-12 10:38:52
【问题描述】:

我需要在显示器确实具有不同特征的范围内对显示器进行唯一标识。因此,插入同一个物理端口的相同型号的显示器不会被视为不同,但基本上其他一切都会被视为不同。

当系统 GPU 发生变化时,CGDirectDisplayID 也会发生变化,但不会以记录的方式发生变化。实验表明,相同的屏幕 ID 会根据使用的 GPU 相差 2。

CGDisplayID changing issues

解决此问题的一种方法是获取显示的 IO 注册表字符串:

io_service_t  servicePort = CGDisplayIOServicePort (cgDisplayID);
io_service_t  root = IODisplayForFramebuffer (servicePort, kNilOptions);
NSDictionary* ioRegistryDict = nil;
NSString*     displayKey = nil;

IORegistryEntryCreateCFProperties (root, (CFMutableDictionaryRef *)&ioRegistryDict, kCFAllocatorDefault, kNilOptions);

if (ioRegistryDict)
    displayKey = [ioRegistryDict objectForKey:@"IODisplayPrefsKey"];

这很好用,除了在 10.9 中,CGDisplayIOServicePort 已被弃用。

鉴于所有这一切,以及 Apple 的建议不要缓存 NSScreens(无论如何它都不能真正用于此目的),可靠识别屏幕的最佳方法是什么,以便我可以分辨(例如)在家屏幕和工作屏幕?

我不想依赖屏幕分辨率,因为用户更改分辨率不应被视为不同的显示器。不同 GPU 上的相同屏幕也不应被视为不同。

次要目标是找到一种方法,在给定 CGDirectDisplayID 的情况下,如果发生 GPU 切换,我如何确定同一屏幕的 CGDirectDisplayID 是什么?只要我可以匹配来自两个 GPU 控制器的两个结果,这至少可以让我通过 CGDirectDisplayID 跟踪显示。

【问题讨论】:

  • 我不确定您希望显示的哪些属性会影响“相同”与“不同”的概念,但您应该查看 Quartz 显示服务功能,例如 CGDisplayModelNumber() 、CGDisplaySerialNumber()、CGDisplayUnitNumber() 和 CGDisplayVendorNumber()。
  • Quartz 参考声明“在分配显示 ID 时,Quartz 会考虑以下参数:供应商、型号、序列号和 I/O 套件注册表中的位置”当我在集成的 MBP 上运行时我得到的 GPU:displayID:2077805631。在快速 GPU (AMD Radeon) 上,我得到一个 displayID:69678016。在这两种情况下,供应商、型号、序列号和单位都是相同的:1552、40143、0、0。那么苹果还做了什么导致这些ID 不同?
  • 我不知道。我怀疑该列表是否旨在详尽无遗。但你为什么在乎?我以为您正在寻找一种方法来识别没有随 GPU 发生变化的显示器。
  • 确实,这可能适用于第一个问题。但是对于第二个,我正在寻找一种方法来确定 69678016 和 2077805631 指的是同一个屏幕……我希望能够从另一个中派生出其中一个。这是因为 Apple 使用 DisplayID 来确定桌面和空间,但 Apple 只会使用其中一个(我称之为主 ID),即使 GPU 已经规定“辅助 ID”是从任何查询返回的内容NSS 屏幕。
  • 我有另一个想法(尽管我仍然不确定我是否理解您在寻找什么)。尝试将 CGDisplayIDToOpenGLDisplayMask() 与两个显示 ID 一起使用。它们可能映射到 OpenGL 显示掩码中的同一位。您还可以尝试通过 CGOpenGLDisplayMaskToDisplayID() 来回返回,看看它是否“标准化”为单个显示 ID。

标签: xcode macos gpu retina-display


【解决方案1】:

使用可以通过以下方式获得的 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 中可用。

【讨论】:

  • 在显示被移除的显示回调期间调用CGDisplayCreateUUIDFromDisplayID 不起作用,因为即使在设置kCGDisplayBeginConfigurationFlag 的初始部分,这也会返回“无效显示”。在此期间,可以获取所有NSScreens,其中一个将具有相关的 displayID。 NSScreen 有一个名为 _UUIDString 的私有 ivar,这是正确的。当CGDisplayCreateUUIDFromDisplayID 不能时,NSScreen 怎么会得到这个?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 2017-05-24
  • 1970-01-01
相关资源
最近更新 更多