Как решить проблемы с изменением CGDirectDisplayID на новых ноутбуках Apple с несколькими графическими процессорами в Core Foundation / IO Kit?

В Mac OS X каждому дисплею присваивается уникальный номер CGDirectDisplayID. Вы можете использовать CGGetActiveDisplayList() или [NSScreen screens] для доступа к ним, среди прочего. Согласно Документам Apple :

Идентификатор дисплея может сохраняться при всех процессах и перезагрузке системы и, как правило, остается постоянным до тех пор, пока некоторые параметры дисплея не изменятся.

На новых MacBook Pro середины 2010 года Apple начала использовать автоматическое переключение графики Intel / nVidia. Ноутбуки имеют два графических процессора, маломощный Intel и мощный nVidia. Предыдущие ноутбуки с двумя графическими процессорами (модели 2009 года) не имели автоматического переключения графических процессоров и требовали от пользователя изменения настроек, выхода из системы и повторного входа в систему для переключения графического процессора. Даже в старых системах был только один графический процессор.

Существует проблема с моделями середины 2010 года, когда CGDirectDisplayID не остаются прежними, когда дисплей переключается с одного графического процессора на другое. Например:

  1. Ноутбук включается.
  2. Встроенный ЖК-экран управляется чипсетом Intel. Идентификатор дисплея: 30002
  3. Внешний дисплей подключен.
  4. Встроенный ЖК-экран переключается на чипсет nVidia. Изменение идентификатора дисплея: 30004
  5. Внешний дисплей управляется чипсетом nVidia.
  6. ... на данный момент чипсет Intel бездействует ...
  7. Пользователь отключает Внешний дисплей .
  8. Встроенный ЖК-экран переключается обратно на набор микросхем Intel. Идентификатор дисплея меняется на исходный: 30002

У меня вопрос: как сопоставить старый идентификатор дисплея новому идентификатору дисплея, если они меняются из-за Смена графического процессора?


Мысль о:

Я заметил, что идентификатор дисплея меняется только на 2, но мне не хватает протестируйте Mac, чтобы определить, является ли это общим для всех новых MacBook Pro или только для меня. В любом случае, это своего рода клочок, если "просто проверьте идентификаторы дисплея, которые находятся +/- 2 друг от друга".


Пробовал:

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. Затем сравнение oldInfoDict с newInfoDict с помощью IODisplayMatchDictionaries()
  4. IODisplayMatchDictionaries() возвращает BOOL, либо ДА, они одинаковы, либо НЕТ, они разные.

К сожалению, IODisplayMatchDictionaries() не возвращает YES, если тот же дисплей изменил GPU. Вот пример сравнения словаря (посмотрите на клавишу 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";
}

Как видите, клавиша IODisplayLocation изменяется при переключении графических процессоров, поэтому IODisplayMatchDictionaries() не работа.

Теоретически я могу сравнить только клавиши DisplayProductID и DisplayVendorID, но я пишу программное обеспечение для конечного пользователя, и меня беспокоит ситуация, когда у пользователя есть два или более одинаковых монитора, то есть будут ли оба одинаковых DisplayProductID / DisplayVendorID). Другими словами, это не идеальное решение, открытое для потенциальных сбоев.


Любая помощь очень ценится! :) [+1143]

10
задан Dave Gallagher 18 May 2010 в 23:32
поделиться

1 ответ

Хотя я не профессионал, я считаю, что ответ заключается в том, чтобы позволить Apple уведомлять вас, когда пользователь меняет дисплеи. Информация в обратном вызове содержит флаги для добавления и удаления CGDirectDisplayIDов.

Пользователь не должен добавлять или удалять видеокарты во время работы, поэтому я бы поигрался с составлением списка при запуске, и всякий раз, когда вы получаете флаг "remove", установите следующую операцию "add" для замены этого ID в списке.

Я бы попробовал просто печатать информацию, которую вы получаете каждый раз, когда CGDisplayRegisterReconfigurationCallback вызывает вашу функцию. Посмотрите, получаете ли вы один DeviceUID с флагом 'remove', а затем при последующем вызове другой с флагом 'add'. Проверка этих идентификаторов по CGGetActiveDisplayList также поможет понять, что происходит.

Это мой лучший вариант, надеюсь, он поможет!

1
ответ дан 4 December 2019 в 03:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: